Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用纹理缓冲区对象在图形应用程序中管理矩阵的有效方法(OpenGL)_Opengl_Matrix_Glsl_Shader_Vertex Shader - Fatal编程技术网

使用纹理缓冲区对象在图形应用程序中管理矩阵的有效方法(OpenGL)

使用纹理缓冲区对象在图形应用程序中管理矩阵的有效方法(OpenGL),opengl,matrix,glsl,shader,vertex-shader,Opengl,Matrix,Glsl,Shader,Vertex Shader,我正在用OpenGL和GLSL开发一个小的3D引擎。我目前使用纹理缓冲区对象(TBO)来存储我的所有矩阵(Proj、View、Model和Shadow矩阵)。但是我做了一些关于在图形引擎中处理矩阵的最佳方法(我指的是最有效的方法)的研究,但没有成功。目标是将最多的矩阵存储到最少数量的TBO中,并在GPU和客户机代码(glBufferSubData)之间发生最少的状态更改和最少的交换 我提出了两种不同的方法(及其优缺点): 下面是一个场景示例: 1个摄像头(1个ProjMatrix,1个ViewM

我正在用OpenGL和GLSL开发一个小的3D引擎。我目前使用纹理缓冲区对象(TBO)来存储我的所有矩阵(Proj、View、Model和Shadow矩阵)。但是我做了一些关于在图形引擎中处理矩阵的最佳方法(我指的是最有效的方法)的研究,但没有成功。目标是将最多的矩阵存储到最少数量的TBO中,并在GPU和客户机代码(glBufferSubData)之间发生最少的状态更改和最少的交换

我提出了两种不同的方法(及其优缺点):

下面是一个场景示例:

1个摄像头(1个ProjMatrix,1个ViewMatrix) 5个盒子(5个模型矩阵)

下面是我使用的一个简单顶点着色器的示例:

#version 400

/*
** Vertex attributes.
*/
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec2 VertexTexture;

/*
** Uniform matrix buffer.
*/
uniform samplerBuffer matrixBuffer;

/*
** Matrix buffer offset.
*/
uniform int MatrixBufferOffset;

/*
** Output variables.
*/
out vec2 TexCoords;

/*
** Returns matrix4x4 from texture cache.
*/
mat4 Get_Matrix(int offset)
{
    return (mat4(texelFetch(
        matrixBuffer, offset), texelFetch(
            matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2),
                texelFetch(matrixBuffer, offset + 3)));
}

/*
** Vertex shader entry point.
*/
void main(void)
{
    TexCoords = VertexTexture;
    {
        mat4 ModelViewProjMatrix = Get_Matrix(
            MatrixBufferOffset);
        gl_Position = ModelViewProjMatrix  * VertexPosition;
    }
}
1) 我当前使用的方法:在顶点着色器中,我使用ModelViewProjMatrix(光栅化(gl_位置)所需)、ModelViewMatrix(用于照明计算)和ModelMatrix。因此,为了避免顶点着色器中的无用计算,我决定为TBO中内联的每个网格节点存储ModelViewProjMatrix、ModelViewMatrix和ModelMatrix,如下所示:

TBO={[ModelViewProj_Box1][ModelView_Box1][Model_Box1]|[ModelViewProj_Box2]…}

优点:我不需要为每个顶点着色器(矩阵是预先计算的)计算product Proj*View*模型(例如ModelViewProj)

缺点:如果移动相机,则需要更新所有ModelViewProj和ModelView矩阵。所以,有很多信息需要更新

2) 我考虑了另一种方法,我认为更有效:存储一次投影矩阵,一次视图矩阵,最后再存储一次每个长方体场景节点模型矩阵,方法如下:

TBO={[ProjMatrix][ViewMatrix][ModelMatrix_Box1][ModelMatrix_Box2]…}

因此,我的顶点着色器将如下所示:

#version 400

/*
** Vertex attributes.
*/
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec2 VertexTexture;

/*
** Uniform matrix buffer.
*/
uniform samplerBuffer matrixBuffer;

/*
** Matrix buffer offset.
*/
uniform int MatrixBufferOffset;

/*
** Output variables.
*/
out vec2 TexCoords;

/*
** Returns matrix4x4 from texture cache.
*/
mat4 Get_Matrix(int offset)
{
    return (mat4(texelFetch(
        matrixBuffer, offset), texelFetch(
            matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2),
                texelFetch(matrixBuffer, offset + 3)));
}

/*
** Vertex shader entry point.
*/
void main(void)
{
    TexCoords = VertexTexture;
    {
        mat4 ProjMatrix = Get_Matrix(MatrixBufferOffset);
        mat4 ViewMatrix = Get_Matrix(MatrixBufferOffset + 4);
        mat4 ModelMatrix = Get_Matrix(MatrixBufferOffset + 8);

        gl_Position = ProjMatrix * ViewMatrix * ModelMatrix * VertexPosition;
    }
}
优点:TBO包含所用矩阵的确切数量。更新具有很强的针对性(如果移动摄影机,则仅更新视图矩阵;如果调整窗口大小,则仅更新投影矩阵;最后,如果对象仅移动,则将更新其模型矩阵)

缺点:我需要计算ModelViewProjMatrix中顶点着色器中的每个顶点。另外,如果场景由大量对象组成,并且每个对象都拥有不同的模型矩阵,我可能需要创建一个新的TBO。因此,我将丢失proj/view矩阵信息,因为我无法连接到正确的TBO,这就引出了我的第三种方法

3) 将投影和视图矩阵存储在TBO中,并将所有其他模型矩阵存储在另一个或其他TBO中,如下所示:

TBO_0={[ProjMatrix][ViewMatrix]} TBO_1={[ModelMatrix_Box1][ModelMatrix_Box2]…}

你觉得我的三种方法怎么样?哪一个最适合你


非常感谢您的帮助

解决方案3是大多数引擎所做的,只是它们使用统一缓冲区(常量缓冲区)而不是纹理缓冲区。此外,它们通常不会在同一缓冲区中将所有模型矩阵分组在一起,它们通常按对象类型分组(因为使用实例一次绘制相同的对象),有时按更新频率分组(从不移动的对象位于同一缓冲区中,因此不需要更新)

此外,子数据可能非常慢;更新缓冲区通常比绑定不同的缓冲区慢,因为所有同步都发生在驱动程序内部。关于这一点,有一本非常好的书,在互联网上免费提供,叫做“OpenGL洞察:异步缓冲区传输”(谷歌搜索)

编辑:你在评论中链接的内容非常有趣。他们建议使用glmultidrawerelements一次进行几个draw调用(这是主要的技巧,其他一切都是因为这个决定)。这可以大大减少驱动程序中的CPU工作,但这也意味着提供绘制对象所需的所有数据要复杂得多:必须为矩阵/材质值构建/更新更大的缓冲区,并且还需要使用无绑定纹理之类的东西,以便能够为每个对象创建不同的纹理。所以,很有趣,但更复杂


只有当你想画很多不同的物体时,多重元素才是重要的。他们的例子有68000-98000个不同的网格,这真是太多了。例如,在游戏中,通常有许多相同对象的实例,但只有几百个不同对象(最多)。最后,这取决于3D引擎需要渲染什么。

为什么要使用TBO而不是统一的缓冲区?因为尺寸限制?你好,杰里米,谢谢你的回复。我决定使用TBO而不是UBO(仅用于材质和灯光参数),因为我读了NVIDIA关于这个主题的一篇文章。也许你已经读过了。这是链接(您可以从第31张幻灯片访问TBO矩阵存储)。你能告诉我你对这篇文章的看法吗?提前谢谢!在幻灯片34中,他们说TBO用于存储大型/随机访问数据,UBO仅用于频繁更改,而不用于分散访问。这到底是什么意思?我们可以把矩阵看作大数据吗?那么在阅读本文之后,TBO和UBO之间为您存储矩阵的最佳方式是什么?您可以将您的选择锁定在UBO上:)?TBO更适合于大数据,因为它没有大小限制(与限制为64KB的UBO不同)。当着色器的两个实例不读取UBO中的同一位置时,会发生不同的访问。例如,对于片段着色器,nvidia GPU通常运行同一着色器的32个实例,一次着色32个像素。所有这些实例同时运行相同的指令。如果它们中的一个碰巧以与其他缓冲区不同的偏移量读取缓冲区,则这是一种不同的访问。TBO可能在这方面做得更好