I am trying to get textures to work properly in OpenGL.
Here is the current problem:
As you can see, the image comes in on the various faces per triangle rather than around the entire mesh.
I want the textures to work normal: ie: wrap around the entire mesh instead of per triangle.
To further illustrate the problem; I created a wireframe of the model and loaded the various points into a "text dump" so you can see how the mapping should work:
Vertices/Normals/UVs for above model
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
Texture for above Image
Code Listing
Loading the image:
Here is how I load the image in (partial code listing):
glGenTextures(1, &TextureObject_ID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, TextureObject_ID);
GLsizei iFormat = BytesPerPixel == 24 ? GL_BGR : BytesPerPixel == 8 ? GL_LUMINANCE : 0;
GLsizei iInternalFormat = BytesPerPixel == 24 ? GL_RGB : GL_DEPTH_COMPONENT;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
WidthOfTexture, HeightOfTexture, 0, iFormat,
GL_UNSIGNED_BYTE, bytesDataPointer);
glGenerateMipmap(GL_TEXTURE_2D);
FreeImage_Unload(loadedImage);
glGenSamplers(1, &TextureSamplerObject_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
setFiltering(TEXTURE_FILTER_MAG_BILINEAR, TEXTURE_FILTER_MIN_BILINEAR_MIPMAP);
HasMipsBeenGenerated = true;
glBindTexture(GL_TEXTURE_2D, NULL);
glActiveTexture(GL_TEXTURE0);
Binding the attributes and loading into the GPU
And here is how I bind various attributes and send data 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);
Shaders
Vertex shader:
#version 430
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec3 vNormal;
layout(location = 2) in vec2 vUV;
layout(location = 3) in mat4 ModelViewProjectionMatrix;
layout(location = 7) in mat3 NormalMatrix;
out vec3 SurfaceNormal;
out vec2 TextureCoordinates;
void main () {
SurfaceNormal = normalize(NormalMatrix * vNormal);
TextureCoordinates = vUV;
gl_Position = ModelViewProjectionMatrix * vec4(vPosition, 1.0);
}
Fragment Shader:
#version 430
uniform MaterialBlock
{
vec4 MaterialColor;
vec4 AmbientMeshColor;
vec4 EmmissiveMeshColor;
vec4 DiffuseMeshColor;
vec4 SpecularMeshColor;
float MeshShininess;
float ObjectHasMaterialFile;
} Material;
uniform float EnableWireframe;
uniform vec4 WireframeColor;
uniform float IfEnableMaterial;
uniform float EnableLighting;
uniform float EnableSun;
uniform vec3 SunDirection;
uniform vec3 LightHalfVector;
uniform vec4 SunColor;
uniform vec4 SunSpotCutoff;
uniform float SunlightStrength;
in vec3 SurfaceNormal;
in vec2 TextureCoordinates;
uniform sampler2D MainTextureSampler;
out vec4 finalColor;
void SunlightWithMaterials() {
vec4 MaterialTextureColor = texture2D(MainTextureSampler, TextureCoordinates);
float DiffuseValue = max(0.0, dot(SurfaceNormal, SunDirection));
float SpecularValue = max(0.0, dot(SurfaceNormal, LightHalfVector));
if (DiffuseValue == 0.0) {
SpecularValue = 0.0;
} else {
SpecularValue = pow(SpecularValue, Material.MeshShininess);
}
vec3 ScatteredLight = Material.AmbientMeshColor.rgb + (SunColor.rgb * DiffuseValue);
vec3 ReflectedLight = SunColor.rgb * SpecularValue * SunlightStrength;
vec3 CalculatedColor = min(MaterialTextureColor.rgb * ScatteredLight + ReflectedLight, vec3(1.0));
finalColor = vec4(CalculatedColor, Material.MaterialColor.a);
}
void SunlightWithoutMaterials() {
float DiffuseValue = max(0.0, dot(SurfaceNormal, SunDirection));
float SpecularValue = max(0.0, dot(SurfaceNormal, LightHalfVector));
if (DiffuseValue == 0.0) {
SpecularValue = 0.0;
} else {
SpecularValue = pow(SpecularValue, Material.MeshShininess);
}
vec3 ScatteredLight = Material.AmbientMeshColor.rgb + (SunColor.rgb * DiffuseValue);
vec3 ReflectedLight = SunColor.rgb * SpecularValue * SunlightStrength;
vec3 CalculatedColor = min(Material.MaterialColor.rgb * ScatteredLight + ReflectedLight, vec3(1.0));
finalColor = vec4(CalculatedColor, Material.MaterialColor.a);
}
void main()
{
if (EnableWireframe == 1) {
finalColor = WireframeColor;
} else {
if (IfEnableMaterial == 1.0 && ObjectHasMaterialFile == 1.0) {
if (EnableLighting == 1.0) {
if (EnableSun == 1.0) {
SunlightWithMaterials();
}
else {
vec4 MaterialTextureColor = texture2D(MainTextureSampler, TextureCoordinates);
finalColor = min(MaterialTextureColor * Material.AmbientMeshColor, vec4(1.0));
}
}
else {
vec4 MaterialTextureColor = texture2D(MainTextureSampler, TextureCoordinates);
finalColor = MaterialTextureColor;
}
}
else {
if (EnableLighting == 1.0) {
if (EnableSun == 1.0) {
SunlightWithoutMaterials();
}
else {
finalColor = min(Material.MaterialColor * Material.AmbientMeshColor, vec4(1.0));
}
} else {
finalColor = Material.MaterialColor;
}
}
}
}
Drawing the image in OpenGL:
glBindVertexArray(Pointer_VAO);
for (int i = 0; i < ModelMatrixInstances.size(); i++) {
glm::mat4 ModelViewMatrix = CurrentOpenGLController->GetViewMatrix() * ModelMatrixInstances[i];
glm::mat3 NormalMatrix = glm::transpose(glm::inverse(glm::mat3(ModelViewMatrix)));
glm::mat4 ModelViewProjectionMatrix = CurrentOpenGLController->GetProjectionViewMatrix() * ModelMatrixInstances[i];
glBindBuffer(GL_ARRAY_BUFFER, MVP_VBO);
glBufferSubData(GL_ARRAY_BUFFER, (i * (sizeof(glm::mat4))), sizeof(glm::mat4), glm::value_ptr(ModelViewProjectionMatrix));
glBindBuffer(GL_ARRAY_BUFFER, NormalMatrix_VBO);
glBufferSubData(GL_ARRAY_BUFFER, (i * (sizeof(glm::mat3))), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));
}
if (Materials[0].HasMaterialFile == true) {
GLfloat ObjectHasMaterial = 1.0f;
glUniform1fv(CurrentOpenGLController->GetObjectHasMaterialFileID(), 1, &ObjectHasMaterial);
glUniform1i(CurrentOpenGLController->GetMainTextureID(), 1);
Materials[0].bindTexture(1);
}
else {
glBindTexture(GL_TEXTURE_2D, NULL);
}
glBufferData(GL_UNIFORM_BUFFER, sizeof(Materials[0].ColorProperties), Materials[0].ColorProperties, GL_DYNAMIC_DRAW);
glDrawElementsInstanced(GL_TRIANGLES, TotalVertexCount,
GL_UNSIGNED_INT, NULL, NumberOfChildItems + 1);
if (Materials[0].HasMaterialFile == true) {
glActiveTexture(NULL);
glBindTexture(GL_TEXTURE_2D, NULL);
}