我正在使用OpenGL和GLSL开发一个小型3D引擎。我目前使用纹理缓冲对象(TBOs)来存储所有矩阵(Proj, View, Model和Shadow Matrices)。但是我尝试了一些方式,试图找到图形引擎中处理矩阵的最佳效率方法,但没有成功。目标是将尽可能多的矩阵存储到最少数量的TBO中,并尽量减少状态更改和GPU和客户端代码(glBufferSubData)之间的交换次数。
我提出以下两种不同的方法(以及它们的优缺点):
以下是一个场景示例:
1个相机(1 ProjMatrix、1 ViewMatrix) 5个盒子(5个ModelMatrix)
以下是我使用的简单顶点着色器示例:
优点:TBO包含使用的矩阵的确切数量。更新是高度针对性的(如果我移动相机,只会更新视图矩阵;如果我调整窗口大小,只会更新投影矩阵;最后,如果一个对象在移动,只有它的模型矩阵会被更新)。
缺点:我需要在每个顶点着色器中计算ModelViewProjMatrix。此外,如果场景由大量拥有不同模型矩阵的对象组成,我可能需要创建一个新的TBO。因此,我将失去proj/view矩阵信息,因为我将无法连接到正确的TBO,这就带来了我的第三种方法。
3)将投影和视图矩阵存储在一个TBO中,将所有其他模型矩阵存储在另一个或多个TBO中,如下所示:
TBO_0 = {[ProjMatrix][ViewMatrix]} TBO_1 = {[ModelMatrix_Box1][ModelMatrix_Box2]...}
你觉得我的三种方法怎么样?哪一种对你来说最好?
非常感谢您的帮助!
我提出以下两种不同的方法(以及它们的优缺点):
以下是一个场景示例:
1个相机(1 ProjMatrix、1 ViewMatrix) 5个盒子(5个ModelMatrix)
以下是我使用的简单顶点着色器示例:
#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_Position)),ModelViewMatrix(用于光照计算)和ModelMatrix。因此,为了避免在顶点着色器中进行无用的计算,我决定将每个网格节点的ModelViewProjMatrix、ModelViewMatrix和ModelMatrix嵌入到TBO中,如下所示:
TBO = {[ModelViewProj_Box1][ModelView_Box1][Model_Box1]|[ModelViewProj_Box2]...}
优点:我不需要为每个顶点着色器计算Proj * View * Model(例如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]...}
你觉得我的三种方法怎么样?哪一种对你来说最好?
非常感谢您的帮助!