Working with UV coordinates when they are not in the range of 0 -1

Hello,

I am using a loading library which supplies UV coordinates as shown below.

Note that these coordinates are not in the range of 0.0 - 1.0

Therefore the textures aren’t mapping properly and the end results suck.

I tried using GLSL’s clamp as shown below in the fragment shader but that doesn’t work.

How do I work with these UV coordinates?

Thank you for your time:

GLSL shader snippet:


MaterialTextureColor = texture2D(MainTextureSampler, clamp(TextureCoordinates, 0, 1));

UV Coordinates:

Note that this is just a textual representation, the coordinates are floats within C++/OpenGL when loaded.


UV Point: S: -53.0558 T: -15.3896
UV Point: S: 5.99937 T: -15.3896
UV Point: S: -3.84315 T: 2.00539
UV Point: S: -3.84315 T: 2.00539
UV Point: S: 5.99937 T: -15.3896
UV Point: S: 5.99937 T: 2.00539
UV Point: S: -53.0558 T: -15.3896
UV Point: S: -3.84315 T: 2.00539
UV Point: S: -53.0558 T: 4.29541
UV Point: S: -3.84315 T: 4.29541
UV Point: S: -53.0558 T: 4.29541
UV Point: S: -3.84315 T: 2.00539
UV Point: S: -3.84315 T: -2.00539
UV Point: S: -53.0558 T: -4.29541
UV Point: S: -3.84315 T: -4.29541
UV Point: S: -3.84315 T: -2.00539
UV Point: S: 5.99937 T: 15.3896
UV Point: S: -53.0558 T: 15.3896
UV Point: S: 5.99937 T: 15.3896
UV Point: S: -3.84315 T: -2.00539
UV Point: S: 5.99937 T: -2.00539
UV Point: S: -3.84315 T: -2.00539
UV Point: S: -53.0558 T: 15.3896
UV Point: S: -53.0558 T: -4.29541
UV Point: S: -2.00539 T: -0.492126
UV Point: S: 15.3896 T: -0.492126
UV Point: S: 15.3896 T: 3.75462e^-009
UV Point: S: 15.3896 T: 3.75462e^-009
UV Point: S: -2.00539 T: 3.75462e^-009
UV Point: S: -2.00539 T: -0.492126
UV Point: S: -3.84315 T: -0.492126
UV Point: S: 5.99937 T: -0.492126
UV Point: S: 5.99937 T: 3.75462e^-009
UV Point: S: 5.99937 T: 3.75462e^-009
UV Point: S: -3.84315 T: 3.75462e^-009
UV Point: S: -3.84315 T: -0.492126
UV Point: S: -4.29541 T: -0.492126
UV Point: S: -2.00539 T: -0.492126
UV Point: S: -2.00539 T: 3.75462e^-009
UV Point: S: -2.00539 T: 3.75462e^-009
UV Point: S: -4.29541 T: 3.75462e^-009
UV Point: S: -4.29541 T: -0.492126
UV Point: S: -53.0557 T: -0.492126
UV Point: S: -3.84315 T: -0.492126
UV Point: S: -53.0557 T: 3.75462e^-009
UV Point: S: -3.84315 T: 3.75462e^-009
UV Point: S: -53.0557 T: 3.75462e^-009
UV Point: S: -3.84315 T: -0.492126
UV Point: S: -15.3896 T: -0.492126
UV Point: S: 4.29541 T: -0.492126
UV Point: S: 4.29541 T: 3.75462e^-009
UV Point: S: 4.29541 T: 3.75462e^-009
UV Point: S: -15.3896 T: 3.75462e^-009
UV Point: S: -15.3896 T: -0.492126
UV Point: S: 5.99937 T: 0.492126
UV Point: S: -53.0558 T: 0.492126
UV Point: S: -53.0558 T: -3.75462e^-009
UV Point: S: -53.0558 T: -3.75462e^-009
UV Point: S: 5.99937 T: -3.75462e^-009
UV Point: S: 5.99937 T: 0.492126

Without understanding why your UV coordinates are outside of the 0…1 range, you could try one of the different texture sampling parameters, eg GL_REPEAT
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

[QUOTE=BionicBytes;1260415]Without understanding why your UV coordinates are outside of the 0…1 range, you could try one of the different texture sampling parameters, eg GL_REPEAT
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_T, GL_REPEAT);[/QUOTE]

I tried the different parameters for glTexParameter as specified here but I get the same results.

Thank you for the suggestion…

If you get the same results something is going very wrong and to me it sounds as if your glTexParameter where not actually operating on the correct texture. If you were getting different results, but none of those are what you want, you’d need to explain what mapping you expect and ideally find out what units the existing UV coords are in (maybe texels?).

The problem definitely seems to be the UV coordinates; what I did was this.

I set the texture coordinates to be the actual color of red and green in the GLSL fragment shader as so:


        if (TextureCoordinateDebug == 1) {
		if (Clamping == 1) {
			finalColor = vec4(clamp(TextureCoordinates, 0, 1), 0.0, 1.0);
		} else {
			finalColor = vec4(TextureCoordinates, 0.0, 1.0);
		}
	}

Both “TextureCoordinateDebug” and “Clamping” are uniforms I change via a key event.

Regardless of whether clamping is done or not I get the following image:

If UVs were working OK I should get a smooth gradient from red to green on all of the surfaces.

Anyone have any ideas? I contacted the Autodesk FBX forums as well.

Thank you.

Fragment shader outputs that are written to the default framebuffers are always clamped to [0,1]. Your ‘Clamping’ uniform won’t have an effect.

I see, that makes sense.

So how do I get around this problem?

I asked around on the AutoDESK FBX forums and the response was that the function above I used to retrieve the texture coordinates is the correct function.

Here is how my textures come out currently:

Hmm, can you trim your model down to just a single surface that has the problem? That way it may be possible to determine what is wrong from looking at the numbers. Otherwise you just have a large pile of triangles and it is very difficult to manually correlate numbers with what happens on screen.

You got it.

Here is a very simple model’s coordinates for vertices, normals, and UV’s:


Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.998895 T: 0.992545
Vertex:  X: 1 Y: 1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.0232662 T: 0.0169165
Vertex:  X: 1 Y: -1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.998895 T: 0.0169165
Vertex:  X: 1 Y: 1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.0232662 T: 0.0169165
Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.998895 T: 0.992545
Vertex:  X: -1 Y: 1 Z: -1 Normal:  X: 0 Y: 0 Z: -1 UV Point:  S: 0.023266 T: 0.992545
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 0.333333 T: 0.666667
Vertex:  X: 0.999999 Y: -1 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 0 T: 0.333333
Vertex:  X: 1 Y: 0.999999 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 0.333333 T: 0.333333
Vertex:  X: 0.999999 Y: -1 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 0 T: 0.333333
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 0.333333 T: 0.666667
Vertex:  X: -1 Y: -1 Z: 1 Normal:  X: 2.98023e-008 Y: 0 Z: 1 UV Point:  S: 4.96705e-008 T: 0.666667
Vertex:  X: 1 Y: 0.999999 Z: 1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.333333 T: 0.333333
Vertex:  X: 1 Y: -1 Z: -1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.666667 T: 1.98682e-008
Vertex:  X: 1 Y: 1 Z: -1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.666667 T: 0.333333
Vertex:  X: 1 Y: -1 Z: -1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.666667 T: 1.98682e-008
Vertex:  X: 1 Y: 0.999999 Z: 1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.333333 T: 0.333333
Vertex:  X: 0.999999 Y: -1 Z: 1 Normal:  X: 1 Y: -2.98023e-007 Z: 4.47034e-008 UV Point:  S: 0.333333 T: 0
Vertex:  X: 0.999999 Y: -1 Z: 1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 0 T: 1.29143e-007
Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 0.333333 T: 0.333333
Vertex:  X: 1 Y: -1 Z: -1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 2.98023e-008 T: 0.333333
Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 0.333333 T: 0.333333
Vertex:  X: 0.999999 Y: -1 Z: 1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 0 T: 1.29143e-007
Vertex:  X: -1 Y: -1 Z: 1 Normal:  X: -2.83122e-007 Y: -1 Z: -1.78814e-007 UV Point:  S: 0.333333 T: 0
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 0.666667 T: 8.9407e-008
Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 1 T: 0.333333
Vertex:  X: -1 Y: -1 Z: 1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 0.666667 T: 0.333333
Vertex:  X: -1 Y: -1 Z: -1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 1 T: 0.333333
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 0.666667 T: 8.9407e-008
Vertex:  X: -1 Y: 1 Z: -1 Normal:  X: -1 Y: 2.38419e-007 Z: -1.3411e-007 UV Point:  S: 1 T: 0
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.333333 T: 0.666667
Vertex:  X: 1 Y: 1 Z: -1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.666667 T: 0.333333
Vertex:  X: -1 Y: 1 Z: -1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.666667 T: 0.666667
Vertex:  X: 1 Y: 1 Z: -1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.666667 T: 0.333333
Vertex:  X: -1 Y: 1 Z: 1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.333333 T: 0.666667
Vertex:  X: 1 Y: 0.999999 Z: 1 Normal:  X: 2.38419e-007 Y: 1 Z: 1.63913e-007 UV Point:  S: 0.333333 T: 0.333333

The MVP Matrix for this model:


x: 1,000.0 y: 0.0, z: 0.0, w: 0.0

x: 1,000.0 y: -0.00162920682 , z: -1000.0, w: 0.0

x: 0.0 y: 200.0, z: -3.25841356e-005, w: 0.0

x: 0.0 y: 0.0, z: 0.0, w: 1.0

The wireframe of the model:

The texture:

The resultant final image with texture:

Did you consider the exporter you use is faulty here?
This problem obviously doesn’t relate to OpenGL, but to bad UVs (to me it seems as reordering vertices without reordering the UVs along and a scaling issue 0-1 vs 0-pixel dimension). However we don’t really know what exporter you use, other than it seems to export in FBX format (“Anyone have any ideas? I contacted the Autodesk FBX forums as well.” is the only information I can gather from this thread).

[QUOTE=decimad;1260446]Did you consider the exporter you use is faulty here?
This problem obviously doesn’t relate to OpenGL, but to bad UVs (to me it seems as reordering vertices without reordering the UVs along and a scaling issue 0-1 vs 0-pixel dimension). However we don’t really know what exporter you use, other than it seems to export in FBX format (“Anyone have any ideas? I contacted the Autodesk FBX forums as well.” is the only information I can gather from this thread).[/QUOTE]

Fair enough; what’s a rock solid exporter I can test with?

For the above model I used Blender’s FBX exporter to create the file.

I then use Autodesk’s FBX SDK to load the model…

Hmm, something is strange. Your vertex positions are all (essentially) +/-1 but the image does not show a cube? For debugging a texture with the pixels along the edges colored in a single (but different for each edge) color and a clear pattern that allows inferring orientation is more helpful, since you can learn a lot more than from a wood surface where it is very hard to see any kind of repetition.
Also, here all texture coordinates are in [0,1] if I’m reading it correctly, so the problem is not related to tex coords outside the canonical range, but that vertices do not have the correct tex coords associated with them. As decimad says, this points towards the exporter or your loader as the source of the problem.

[QUOTE=carsten neumann;1260448]Hmm, something is strange. Your vertex positions are all (essentially) +/-1 but the image does not show a cube? For debugging a texture with the pixels along the edges colored in a single (but different for each edge) color and a clear pattern that allows inferring orientation is more helpful, since you can learn a lot more than from a wood surface where it is very hard to see any kind of repetition.
[/QUOTE]

Good point; here you go:

And the fragment shader code that produces the above:


finalColor = vec4(TextureCoordinates, 0.0, 1.0);

There were a few texture coordinates that were outside of the 0-1 range.

If I have to switch the importer then that is fine.

I used Blender for the export of the above model; I assume that creates decent FBX files with the correct UV’s…

Also, as for this:

[QUOTE=carsten neumann;1260448]Hmm, something is strange. Your vertex positions are all (essentially) +/-1 but the image does not show a cube?
[/QUOTE]

I used Blender’s scaling function on the default cube it produces…

Could you provide the VBO/VAO setup code for the tex coords (plus the information of the output data layout of the FBX SDK)?
Maybe there’s something wrong with strides, offsets or the like. I can’t seem to find a pattern though. Changing from a non-unit cube could help too, to see if vertex components end up as UVs. I find it intruiging, that scaling the cube produced 0.3333 u/vs.

PS: I don’t know a “solid” blender exporter. I used Collada export back then, it had its flaws but left me with good vertices and uvs.

[QUOTE=decimad;1260454]Could you provide the VBO/VAO setup code for the tex coords (plus the information of the output data layout of the FBX SDK)?
Maybe there’s something wrong with strides, offsets or the like. I can’t seem to find a pattern though. Changing from a non-unit cube could help too, to see if vertex components end up as UVs. I find it intruiging, that scaling the cube produced 0.3333 u/vs.

PS: I don’t know a “solid” blender exporter. I used Collada export back then, it had its flaws but left me with good vertices and uvs.[/QUOTE]

Here is the code for what is being sent to the GPU:


glGenVertexArrays(1, &Pointer_VAO);
glBindVertexArray(Pointer_VAO);

glGenBuffers(1, &Vertex_VBO);

glBindBuffer(GL_ARRAY_BUFFER, Vertex_VBO);

glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_STATIC_DRAW);

glBufferSubData(GL_ARRAY_BUFFER, NULL, VerticesBufferSize, Vertices);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

if (HasNormals) {
    glBufferSubData(GL_ARRAY_BUFFER, NormalOffset, NormalBufferSize, Normals);
    /*
    Set up our Attribute pointer so that our Shader knows where to get our normals.
    */
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
}

if (HasUVs) {
    glBufferSubData(GL_ARRAY_BUFFER, UVOffset, UVBufferSize, UVs);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(2);
}

glGenBuffers(1, &MVP_VBO);
glBindBuffer(GL_ARRAY_BUFFER, MVP_VBO);
glBufferData(GL_ARRAY_BUFFER, ModelMatrixInstances.size() * sizeof(glm::mat4), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 0));
glEnableVertexAttribArray(3);
glVertexAttribDivisor(3, 1);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 4));
glEnableVertexAttribArray(4);
glVertexAttribDivisor(4, 1);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 8));
glEnableVertexAttribArray(5);
glVertexAttribDivisor(5, 1);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 12));
glEnableVertexAttribArray(6);
glVertexAttribDivisor(6, 1);

glGenBuffers(1, &NormalMatrix_VBO);
glBindBuffer(GL_ARRAY_BUFFER, NormalMatrix_VBO);
glBufferData(GL_ARRAY_BUFFER, ModelMatrixInstances.size() * sizeof(glm::mat3), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 0));
glEnableVertexAttribArray(7);
glVertexAttribDivisor(7, 1);
glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 3));
glEnableVertexAttribArray(8);
glVertexAttribDivisor(8, 1);
glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 6));
glEnableVertexAttribArray(9);
glVertexAttribDivisor(9, 1);

glGenBuffers(1, &Index_VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Index_VBO);

glBufferData(GL_ELEMENT_ARRAY_BUFFER, TotalPolygonCount * 3 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);

glBindVertexArray(0);

Are you also requesting looking at the FBX SDK code?

I’ll dig it up; I know it is a lot of code…

AFAIUI your vertex data lives in a single buffer, first all positions, then all normals, then all tex coords. But when setting up your attribute pointers you do not pass an offset, so your positions get used as normals and tex coords (since positions are stored at the beginning of the buffer).


if (HasNormals) {
    glBufferSubData(GL_ARRAY_BUFFER, NormalOffset, NormalBufferSize, Normals);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
                                                       ^^ NormalOffset here
    glEnableVertexAttribArray(1);
}
 
if (HasUVs) {
    glBufferSubData(GL_ARRAY_BUFFER, UVOffset, UVBufferSize, UVs);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
                                                       ^^ UVOffset here

    glEnableVertexAttribArray(2);
}

Yeppers, the offsets are missing for the normal/uv attribute declaration.
If I might ask, since I’m new to all this VAO/VBO stuff… Is it common practice to store Matrices in VBOs rathern than plain uniforms? If so, what’s the reasoning there? Are the attribute matrices fed in modulo matrix size? How does that work exactly? I haven’t seen such code yet.

[QUOTE=carsten neumann;1260457]AFAIUI your vertex data lives in a single buffer, first all positions, then all normals, then all tex coords. But when setting up your attribute pointers you do not pass an offset, so your positions get used as normals and tex coords (since positions are stored at the beginning of the buffer).
[/QUOTE]

You are correct that I do not pass an offset into glVertexAttribPointer() but that is because there is no offset PER attribute, only offsets for each buffer as a whole:

In other words, in my packed buffer is specify all vertices, THEN all normals, THEN all of the texture coordinates. I don’t have offsets in-between a specified normal or texture coordinate, in other words.

From the way I set up the buffer, isn’r that the correct way to use glVertexAttribPointer()?

It sounds to me as if you might be confusing offset and stride. The former specifies where in the buffer the attribute value for the first vertex is stored (how else could OpenGL now that your normals are not at the beginning of the buffer?). The latter specifies the distance between attribute values for consecutive vertices (and stride 0 means tightly packed).

Yep, I feel like a dufus now.

Changed the code to what is shown below based on what you suggested and it worked:


glGenVertexArrays(1, &Pointer_VAO);
glBindVertexArray(Pointer_VAO);
 
glGenBuffers(1, &Vertex_VBO);
 
glBindBuffer(GL_ARRAY_BUFFER, Vertex_VBO);
 
glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_STATIC_DRAW);
 
glBufferSubData(GL_ARRAY_BUFFER, NULL, VerticesBufferSize, Vertices);
 
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
 
if (HasNormals) {
    glBufferSubData(GL_ARRAY_BUFFER, NormalOffset, NormalBufferSize, Normals);
    /*
    Set up our Attribute pointer so that our Shader knows where to get our normals.
    */
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)NormalOffset);
    glEnableVertexAttribArray(1);
}
 
if (HasUVs) {
    glBufferSubData(GL_ARRAY_BUFFER, UVOffset, UVBufferSize, UVs);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid *)UVOffset);
    glEnableVertexAttribArray(2);
}
 
glGenBuffers(1, &MVP_VBO);
glBindBuffer(GL_ARRAY_BUFFER, MVP_VBO);
glBufferData(GL_ARRAY_BUFFER, ModelMatrixInstances.size() * sizeof(glm::mat4), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 0));
glEnableVertexAttribArray(3);
glVertexAttribDivisor(3, 1);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 4));
glEnableVertexAttribArray(4);
glVertexAttribDivisor(4, 1);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 8));
glEnableVertexAttribArray(5);
glVertexAttribDivisor(5, 1);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 12));
glEnableVertexAttribArray(6);
glVertexAttribDivisor(6, 1);
 
glGenBuffers(1, &NormalMatrix_VBO);
glBindBuffer(GL_ARRAY_BUFFER, NormalMatrix_VBO);
glBufferData(GL_ARRAY_BUFFER, ModelMatrixInstances.size() * sizeof(glm::mat3), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 0));
glEnableVertexAttribArray(7);
glVertexAttribDivisor(7, 1);
glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 3));
glEnableVertexAttribArray(8);
glVertexAttribDivisor(8, 1);
glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 6));
glEnableVertexAttribArray(9);
glVertexAttribDivisor(9, 1);
 
glGenBuffers(1, &Index_VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Index_VBO);
 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, TotalPolygonCount * 3 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);
 
glBindVertexArray(0);