so i have a very simple glsl shader that renders an object with texture and directional light.
now I'm having a really tough time trying to get the texture to display, everything else works except for that.
when i disable the shader( glUseProgram(0) ) the texture renders in black and white but when i enable it the whole mesh is in a single color and not textured, and it changes color when I try different textures.
this is how i load my texture
data = CImg<unsigned char>(src);
glGenTextures(1, &m_textureObj);
glBindTexture(GL_TEXTURE_2D, m_textureObj);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, data.width(), data.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
this is how i bind my texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textureObj);
and this is my vertex shader
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
uniform mat4 gWVP;
uniform mat4 gWorld;
out vec2 TexCoord0;
out vec3 Normal0;
void main()
{
gl_Position = (gWVP * gWorld) * vec4(Position, 1.0);
TexCoord0 = TexCoord;
Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
}
and this is my fragment shader
#version 330
in vec2 TexCoord0;
in vec3 Normal0;
out vec4 FragColor;
struct DirectionalLight
{
vec3 Color;
float AmbientIntensity;
float DiffuseIntensity;
vec3 Direction;
};
uniform DirectionalLight gDirectionalLight;
uniform sampler2D gSampler;
void main()
{
vec4 AmbientColor = vec4(gDirectionalLight.Color, 1.0f) *
gDirectionalLight.AmbientIntensity;
float DiffuseFactor = dot(normalize(Normal0), -gDirectionalLight.Direction);
vec4 DiffuseColor;
if (DiffuseFactor > 0) {
DiffuseColor = vec4(gDirectionalLight.Color, 1.0f) *
gDirectionalLight.DiffuseIntensity *
DiffuseFactor;
}
else {
DiffuseColor = vec4(0, 0, 0, 0);
}
FragColor = texture2D(gSampler, TexCoord0.xy) *
(AmbientColor + DiffuseColor);
}
and last but not least i tell my shader to use the correct texture
glUniform1i(GetUniformLocation("gSampler"), 0);
I have done a F**** ton of reading online on how to properly do this simple and task and ran it in a bunch of different configurations only to become frustrated.
If anyone can point out what I'm doing wrong I would be thrilled, I'm sure I'm missing one stupid detail but i cant seem to find it. please don't refer me to https://www.opengl.org/wiki/Common_Mistakes#Creating_a_complete_texture thanks for reading.
this is how i create my mesh and upload it to the GPU.
this is the vertex constructor Vertex(x, y, z, u, v)
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
unsigned int Indices[] = {
0, 3, 1,
1, 3, 2,
2, 3, 0,
1, 2, 0
};
Vertex Vertices[4] = {
Vertex(-1.0f, -1.0f, 0.5773f, 0.0f, 0.0f),
Vertex(0.0f, -1.0f, -1.15475f, 0.5f, 0.0f),
Vertex(1.0f, -1.0f, 0.5773f, 1.0f, 0.0f),
Vertex(0.0f, 1.0f, 0.0f, 0.5f, 1.0f)
};
Mesh *data = new Mesh(Vertices, 4, Indices, 12);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ibo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(12));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(24));
glBufferData(GL_ARRAY_BUFFER, data->count*Vertex::Size(), data->verts, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data->indsCount*sizeof(unsigned int), data->inds, GL_STATIC_DRAW);
unsigned int Vertex::Size() {
return 32;
}
/*In the update function*/
glDrawElements(GL_TRIANGLES, data->indsCount, GL_UNSIGNED_INT, 0);
this is my vertex class http://pastebin.com/iYwjEdTQ
Edit
I HAVE SOLVED IT! i was binding the vertex the old way, then after ratchet freak showed me how to bind it correctly i noticed that i was binding the texture coordinates to location 2 but in the shader i was looking for in in location 1.
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(24));
(the frag shader)
layout (location = 1) in vec2 TexCoord;
so i changed the fragment shader to
layout (location = 2) in vec2 TexCoord;
and now it works beautifully. Thanks ratchet freak and birdypme for helping I'm gonna accept ratchet freak's answer because it lead me to the solution but you both steered me in the right direction.
This is your problem:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(0));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(12));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(24));
This uses the old and deprecated fixed-function style specification instead you wan to use glVertexAttribPointer:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(12));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(24));
The other problem I see is that your Vertex class doesn't take the normal in the constructor. And Vertex::Size() should be equal to sizeof(Vertex)
Generally speaking, you should be using sizeof() instead of hard-coded offsets, to avoid bad surprises.
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(0));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(3*sizeof(float)));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(6*sizeof(float)));
and in vertex.h
static unsigned int Size() {
return 8*sizeof(float);
}
However, this is unlikely to properly answer your question. I am not deleting my answer to keep the vertex.h pastebin below, which can be important, but I'll probably delete it once a valid answer has been posted.
Related
I was trying to implement normal mapping on a simple cube but since i had troubles with my normals i wanted to try to display them using a geometry shader. Following learnopengl tutorial, it basically calls mesh.render() twice, the first time to draw the model and the second time to display normals. When i try to do the same i get this
The cube seems well drawn but it has a weird white rectangle in front of it and i don't know why. I don't know if it's a problem of drawings or if it's the geometry shader, so i'll post both.
My code:
glutDisplayFunc(MyRenderScene);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glGenVertexArrays(1,&global.gVAO);
glGenBuffers(1, &global.VBO);
glBindVertexArray(global.VAO);
glBindBuffer(GL_ARRAY_BUFFER, global.VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &global.IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, global.IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glGenVertexArrays(1,&global.gVAO);
glGenBuffers(1, &global.gVBO);
glBindVertexArray(global.gVAO);
glBindBuffer(GL_ARRAY_BUFFER, global.gVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &global.gIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, global.gIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
Here i'm basically passing the same structure to both buffers.
Buffers are istantiated in a global struct.
This is MyRenderScene() :
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
global.shaders.enable(); // glUseProgram
global.shaders.set_sampler(0); // setting textures
global.shaders.set_sampler(1);
global.sceneT.set_camera(
global.camera.position(),
global.camera.lookat(),
global.camera.up()
);
glm::mat4 model = glm::mat4(1.0f);
glm::vec3 vaxis = glm::vec3(0.0,1.0,0.0);
glm::vec3 haxis = glm::vec3(1.0,0.0,0.0);
model = glm::rotate(model,glm::radians(global.gradX),haxis);
model = glm::rotate(model,glm::radians(global.gradY),vaxis);
glm::mat4 projection = glm::perspective(glm::radians(40.0f), (float)global.WINDOW_WIDTH/(float)global.WINDOW_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = glm::lookAt(global.camera.position(),global.camera.lookat()+ global.camera.position(),global.camera.up());
global.shaders.set_model(model);
global.shaders.set_view(view);
global.shaders.set_projection(projection);
global.shaders.set_viewPos(global.camera.position());
global.shaders.set_lightPos(lightPos);
global.shaders.update_uniforms();
glBindVertexArray(global.VAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, position)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, textcoord)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, normal)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, tangent)));
glBindBuffer(GL_ARRAY_BUFFER, global.VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, global.IBO);
global.brickwall.Bind(GL_TEXTURE0+0); // binding textures
global.brickwall_normals.Bind(GL_TEXTURE0+1);
glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
global.geometryShader.enable(); // setting up geometry shader
global.geometryShader.set_projection(projection);
global.geometryShader.set_model(model);
global.geometryShader.set_view(view);
global.geometryShader.update_uniforms();
glBindVertexArray(global.gVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, position)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, textcoord)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, normal)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(struct Vertex, tangent)));
glBindBuffer(GL_ARRAY_BUFFER, global.gVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, global.gIBO);
glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glutSwapBuffers();
glutPostRedisplay();***
I even tried calling the same vertexArrays and vertexArrayBuffer but i get the same result.
Here are vertex shader:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 textcoord;
layout (location = 2) in vec3 normal;
layout (location = 3) in vec3 tangent;
out VS_OUT {
vec3 newNormal;
} vs_out;
uniform mat4 view;
uniform mat4 model;
void main() {
mat3 normalMatrix = mat3(transpose(inverse(view * model)));
newNormal = vec3(vec4(normalMatrix * normal, 0.0));
gl_Position = view * model * vec4(position, 1.0);
}
And geometryShader:
#version 330 core
layout (triangles) in;
layout (line_strip, max_vertices = 6) out;
in VS_OUT {
vec3 newNormal;
} gs_in[];
const float MAGNITUDE = 0.2;
uniform mat4 projection;
void GenerateLine(int index) {
gl_Position = projection * gl_in[index].gl_Position;
EmitVertex();
gl_Position = projection * (gl_in[index].gl_Position + vec4(gs_in[index].newNormal,0.0) * MAGNITUDE);
EmitVertex();
EndPrimitive();
}
void main() {
GenerateLine(0); // first vertex normal
GenerateLine(1); // second vertex normal
GenerateLine(2); // third vertex normal
}
Feel free to correct me on everything possible and imaginable.
The reason for the issue is, that the shader program with the geometry shader fails to compile or link. Hence the geometry is drawn by the default shader program instead of the program with the geometry shader.
There is (at least) one error in the vertex shader:
newNormal = vec3(vec4(normalMatrix * normal, 0.0));
vs_out.newNormal = vec3(vec4(normalMatrix * normal, 0.0));
I cannot get texture coordinates to have any effect on what is rendered on screen. My texture constantly seemed to rendering from 0,0 to 1,1.
The method I am using is to send the following buffer layout: x,y,u,v (xy: vertex position and u,v texture coordinates).
However, changing the values u & v have no effect on the rendered texture.
I've removed a lot of surrounding code to try and make it easier to read, but I can post it in full if the problem isn't immediately obvious to someone.
Vertex Shader:
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 mytextpos;
out vec2 v_TexCoord;
uniform mat4 u_Model;
void main()
{
gl_Position = u_Model * vec4(position, 0.0f, 1.0f);
v_TexCoord = mytextpos;
}
Fragment Shader:
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
void main()
{
color = texture(u_Texture, v_TexCoord);
}
My Rectangle Class Constructor:
// GENERATE BUFFERS
glGenVertexArrays(1, &VertexArrayObject);
glGenBuffers(1, &VertexBufferId);
glGenBuffers(1, &IndexBufferObjectId);
Indices = {
0, 1, 2,
2, 3, 0
};
unsigned int numberOfVertices = Vertices.size();
unsigned int numberOfIndices = Indices.size();
glBindVertexArray(VertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObjectId);
Vertices = {
0.2f, 0.0f, 0.0f, 0.5f,
1.0f, 0.0f, 1.5f, 0.5f,
1.0f, 1.0f, 1.5f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f
};
// ADD BUFFER DATA
glBufferData( GL_ARRAY_BUFFER, Vertices.size() * sizeof(float), Vertices.data(), GL_STATIC_DRAW );
// ARRANGE ATTRIBUTES
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, numberOfIndices * sizeof(unsigned int), Indices.data(), GL_STATIC_DRAW );`
Render Function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLint u_Texture = glGetUniformLocation( shader.getId(), "u_Texture" );
glUniform1i( u_Texture, 0 );
GLint u_Model = glGetUniformLocation( shader.getId(), "u_Model" );
glUniformMatrix4fv( u_Model, 1, GL_FALSE, glm::value_ptr( rect.TransformMatrix() ) );
glDrawElements(GL_TRIANGLES, rect.Indices.size(), GL_UNSIGNED_INT, nullptr);
// SWAP BUFFERS
glfwSwapBuffers( _window->WindowInstance );
glfwPollEvents();
My program runs, but my texture is mapped between 0,0 and 1,0 no matter what my vertex or u,v positions are. I would expect the texture to be interpolated between the u,v coordinates for each vertex?
You attribute setup is wrong:
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
This tells OpenGL that it should attach the first two floats of each vertex to the mytextpos attribute. But you actually want it to read the 3rd and 4th float. Thus you have to set the offset such that it skips the first two floats:
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
When I run this program, it seems to only be mapping my textures to 3 sides of a right angle triangle (the first 3 points in my vertices array), and completely missing out the fourth, as when I change that bit, nothing changes in the image. https://imgur.com/a/MvhsYYv here is the current output as the top image, and the expected output as the 2nd image. When I texture it with just a colour in my shader, it maps fine, with a texture, it still seems that it is drawing a square, but then mapping to the top left when it should be mapping to the top right.
Vertex vertices[] = {
//Position //Colour
vec3(-0.5f, 0.5f, 0.f), vec3(1.f, 0.f, 0.f), vec2(0.f, 1.f), //Top left
vec3(-0.5f, -0.5f, 0.f), vec3(0.f, 1.f, 0.f), vec2(0.f, 0.f), //Bottom Left
vec3(0.5f, -0.5f, 0.f), vec3(0.f, 0.f, 1.f), vec2(1.f, 0.f), //Bottom Right
vec3(0.5f, 0.5f, 0.f), vec3(1.f, 1.f, 1.f), vec2(1.f, 1.f) //Top Right
};
unsigned int numOfVertices = sizeof(vertices) / sizeof(Vertex);
GLuint indices[] = {
0,1,2,
3,0,2
};
unsigned numOfIndices = sizeof(indices) / sizeof(GLint);
void updateInput(GLFWwindow* window) {
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
int main() {
//INIT GLFW
glfwInit();
Wrapper mainWrapper = Wrapper();
Shader *mainShader = new Shader(vs_source.c_str(), fs_source.c_str());
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0,4, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
//TEXTURE INIT
int image_width = 0;
int image_height = 0;
unsigned char* image = SOIL_load_image("images/super-meat-boy.png", &image_width, &image_height, NULL, SOIL_LOAD_RGBA);
GLuint texture0;
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (image) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
std::cout << "IMAGE LOADED";
}
else {
std::cout << "Error loading image";
}
//Clean up, needed when stuff done with texture
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
//MAIN LOOP
while (!glfwWindowShouldClose(mainWrapper.getWindow())) {
//UPDATE INPUT
updateInput(mainWrapper.getWindow());
glfwPollEvents();
//UPDATE
//DRAW------
//clear
glClearColor(0.f,0.f,0.f,1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//draw
glUseProgram(mainShader->myProgram);
//activate texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_INT, 0);
//END DRAW
glfwSwapBuffers(mainWrapper.getWindow());
glFlush();
}
//END OF PROGRAM
glfwDestroyWindow(mainWrapper.getWindow());
delete mainShader;
glfwTerminate();
return 0;
}
#version 440
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec3 vertex_texcoord;
out vec3 vs_position;
out vec3 vs_color;
out vec2 vs_texcoord;
void main() {
vs_position = vertex_position;
vs_color = vertex_color;
vs_texcoord = vec2(vertex_texcoord.x, vertex_texcoord.y * -1.f);
gl_Position = vec4(vertex_position, 1.f);
}
#version 440
in vec3 vs_position;
in vec3 vs_color;
in vec2 vs_texcoord;
out vec4 fs_color;
uniform sampler2D texture0;
void main() {
fs_color = vec4(vs_color, 1.f);
fs_color = texture(texture0, vs_texcoord);
}
The 2nd parameter of glVertexAttribPointer has to be the tuple size (number) of components) of the attribute in the vertex buffer.
Your vertex coordinates have 3 components x, y, z. The color attributes have 3 components too (red, green, blue). The texture coordinate have 2 components u and v:
glVertexAttribPointer(0,
3, // 3 instead of 4
GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,
3, // 3 instead of 4
GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,
3, // 2 instead of 3
GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
The parameter of 3 for the tuple size of the texture coordinates causes that you access the vertex buffer out of bounds for the vertex coordinate with index 3.
It was incorrect sizing in my glVertexAttribPointer. I have since changed my vertices to vec2, vec3, vec2, and changed the sizing accordingly.
I tried to load the same model(modeled in 3Ds max) in opengl, but with different textures. The problem is, that when I try to bind the Texture with glBindTexture after I have acitvated the texture, then it disappears. Before I changed the textures in 3Ds max, it always has show me the model in black color (just in opengl). But I havenĀ“t even assign black color to my model. My image "model-image.png" also contains all textures, that I have assign to my object. So am I missing something?
Thanks for your help in advance.
void initDrawing()
{
glEnable(GL_DEPTH_TEST);
program = glCreateProgram();
std::string shaderV = Utilities::loadFile("shader.vert");
std::string shaderF = Utilities::loadFile("shader.frag");
program = Utilities::compileShader(shaderV, shaderF);
Utilities::loadObj("model.obj", obj);
Utilities::loadPNG("model-image.png", diffuse);
glEnable(GL_TEXTURE_2D);
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vPosition);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4)*obj.vertices.size(), &obj.vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint vCoordinates;
glGenBuffers(1, &vCoordinates);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*obj.textureCoordinates.size(), &obj.textureCoordinates[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glGenTextures(2, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, diffuse.width, diffuse.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&diffuse.colors[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUseProgram(program);
ModelView = glGetUniformLocation(program, "ModelView");
Projection = glGetUniformLocation(program, "Projection");
Diffuse = glGetUniformLocation(program, "Diffuse");
}
void display()
{
// background color
const GLfloat color[] = { 0.5, 0.5, 0.5, 1 };
glClear(GL_DEPTH_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
modelView = view * model;
glUniformMatrix4fv(ModelView, 1, GL_FALSE, glm::value_ptr(modelView));
glUniformMatrix4fv(Projection, 1, GL_FALSE, glm::value_ptr(projection));
glUniform1i(Diffuse, 0);
glDrawArrays(GL_TRIANGLES, 0, obj.vertices.size());
glutSwapBuffers();
}
My Shader:
fragment shader:
uniform sampler2D Diffuse;
in vec2 fUV;
out vec3 color;
//main for the color
void main(void)
{
color = texture(Diffuse, fUV).rgb;
}
vertex Shader:
layout (location = 0) in vec4 vPosition;
layout (location = 2) in vec2 vCoordinates;
uniform mat4 ModelView;
uniform mat4 Projection;
out vec2 fUV;
void main(void)
{
gl_Position = Projection * ModelView * vPosition;
fUV = vCoordinates;
}
My guess is that when you say
layout(location = 2) in vec2 vCoordinates;
you really mean to say
layout(location = 1) in vec2 vCoordinates;
considering you never enable vertex attribute 2.
I'm trying to texture the ground with grass. Would someone mind looking through my steps to get a 2D texture to show up in 3D space? I haven't had any luck with online tutorials.
Here is my steps:
1) Call the sprite class initialization to set the vertex coordinates and uv data
void Sprite::init(vec3 bottomleft, vec3 topLeft, vec3 topRight, vec3 bottomRight, std::string texturePath)
{
_texture = ImageLoader::loadPNG(texturePath);
_points = { bottomleft.x, bottomleft.y, bottomleft.z, topLeft.x, topLeft.y, topLeft.z, topRight.x, topRight.y, topRight.z, topRight.x, topRight.y, topRight.z, bottomRight.x, bottomRight.y, bottomRight.z, bottomleft.x, bottomleft.y, bottomleft.z };
_uv = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
}
I use the uniform sampler and activate the texture
//draw ground texture
glUniform1i(samplerLocation, 0);
glActiveTexture(GL_TEXTURE0);
_grassTexture.draw();
The draw function is implemented as follows, which puts the data in the buffer and draws the triangle:
void Sprite::draw()
{
if (_vboID == 0)
{
glGenBuffers(1, &_vboID);
}
glBindTexture(GL_TEXTURE_2D, _texture.id);
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glBufferData(GL_ARRAY_BUFFER, _points.size() * sizeof(float) + _uv.size() * sizeof(float), nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, _points.size() * sizeof(float), &_points.front());
glBufferSubData(GL_ARRAY_BUFFER, _points.size() * sizeof(float), _uv.size() * sizeof(float), &_uv.front());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//position attribute pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, &_points.front());
//uv attribute pointer
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, &_uv.front());
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
The vertex shader:
#version 400
in vec4 vertexPosition;
in vec2 vertexUV;
out vec4 fragmentColor;
out vec2 fragmentUV;
uniform mat4 MVP;
uniform vec4 COLOR;
void main()
{
gl_Position = MVP * vertexPosition;
fragmentColor = COLOR;
fragmentUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
and fragment shader:
#version 400
in vec4 fragmentColor;
in vec2 fragmentUV;
out vec4 fragColor;
uniform sampler2D SAMPLER;
void main()
{
vec4 textureColor = texture(SAMPLER, fragmentUV);
fragColor = textureColor * fragmentColor;
}
At this point, nothing displays in the screen. I do know that the textureColor in the fragment shader is green, so it appears the uniform is being set correctly. My best guess is that I'm either missing a texture initialization step or am not filling the buffer correctly.
I think there's a problem with the pointer parameter in your calls to glVertexAttribPointer. You're passing the address of your _points and _uv arrays, but you should be passing the offset relative to the base of your vbo.
Try:
//position attribute pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
//uv attribute pointer
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(_points.size() * sizeof(float)));