I am developing a small 3D engine using OpenGL and GLSL. I am currently using Texture Buffer Objects (TBOs) to store all my matrices (Proj, View, Model and Shadow Matrices). But I did some research on how best to handle matrices (I mean the most efficient way) in the graphics engine without any success. The goal is to store a maximum of matrices in a minimum number of TBOs and have a minimum of state changes and a minimum of exchanges between the GPU and client code (glBufferSubData).
I suggest 2 different methods (with their advantages and disadvantages):
Here is an example scene:
1 Camera (1 ProjMatrix, 1 ViewMatrix) 5 boxes (5 ModelMatrix)
Here is an example of a simple vertex shader that I use:
#version 400 layout (location = 0) in vec4 VertexPosition; layout (location = 1) in vec2 VertexTexture; uniform samplerBuffer matrixBuffer; uniform int MatrixBufferOffset; out vec2 TexCoords; mat4 Get_Matrix(int offset) { return (mat4(texelFetch( matrixBuffer, offset), texelFetch( matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2), texelFetch(matrixBuffer, offset + 3))); } void main(void) { TexCoords = VertexTexture; { mat4 ModelViewProjMatrix = Get_Matrix( MatrixBufferOffset); gl_Position = ModelViewProjMatrix * VertexPosition; } }
1) The method I use: in my vertex shader, I use ModelViewProjMatrix (necessary for rasterization (gl_Position)), ModelViewMatrix (for calculating lighting) and ModelMatrix. Therefore, in order to avoid useless calculations in the vertex shader, I decided to save ModelViewProjMatrix, ModelViewMatrix and ModelMatrix for each node mesh nested in TBO as follows:
TBO = {[ModelViewProj_Box1] [ModelView_Box1] [Model_Box1] | [ModelViewProj_Box2] ...}
Advantages: I do not need to calculate the product Proj * View * Model (ModelViewProj for example) for each vertex shader (pre-computed matrices).
Disadvantages: if I move the camera, I need to update all ModelViewProj and ModelView models. So, a lot of information to update.
2) I thought of something else, I think it’s more efficient: save the projection matrix as soon as the presentation matrix and finally each model of the window of the node window will again look like this:
TBO = {[ProjMatrix] [ViewMatrix] [ModelMatrix_Box1] [ModelMatrix_Box2] ...}
So my vertex shader will look like this:
#version 400 layout (location = 0) in vec4 VertexPosition; layout (location = 1) in vec2 VertexTexture; uniform samplerBuffer matrixBuffer; uniform int MatrixBufferOffset; out vec2 TexCoords; mat4 Get_Matrix(int offset) { return (mat4(texelFetch( matrixBuffer, offset), texelFetch( matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2), texelFetch(matrixBuffer, offset + 3))); } 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; } }
Advantages: TBO contains the exact number of matrices used. The update is strongly aimed (if I move the camera, I only update the view matrix, if I change the window size, I only update the projection matrix, and finally, if the object moves, only its model matrix will be updated).
Disadvantages: I need to calculate each vertex in the vertex shader of ModelViewProjMatrix. In addition, if the scene consists of a huge number of objects, each of which has a different model matrix, I probably need to create a new TBO. Therefore, I will lose information about the proj / view matrix, because I will not connect to the correct TBO, which will lead us to the third method.
3) Store the projection and view matrix in TBO and all other model matrices inside another or other TBO (s) as follows:
TBO_0 = {[ProjMatrix] [ViewMatrix]} TBO_1 = {[ModelMatrix_Box1] [ModelMatrix_Box2] ...}
What do you think of my 3 methods? Which one is best for you?
Thanks for your help!