I'm to learn OpenGL 4 and now I working with textures. I would like to apply a texture to a sphere, and my vertex shader looks like this:
#version 410
in vec4 vPosition;
in vec2 texCoord;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
smooth out vec2 uvCoord;
void main (void)
{
uvCoord = texCoord;
vec3 vNormal = vPosition.xyz / vPosition.w;
vVaryingNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vPosition;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vVaryingLightDir = normalize(vLightPosition - vPosition3);
gl_Position = mvpMatrix * vPosition;
}
After defining the coordinates and triangulation indexes of a sphere, I build a VAO with the following code:
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned int width, height;
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
To load the attributes, I did the following (before using texture):
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
Now, however, I have an array (_sphereTexCoords) which contains the texture coordinates and I don't really know how to pass it to the vertex shader as the vertex coordinates are passed. Do I have to create another VBO? I though of doing something like this:
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I don't really know how to specify that this is related to the _sphereTexCoords array.
EDIT
I tried this, but it didn't work.
void SphereShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(2, _vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glBufferData(GL_ARRAY_BUFFER, _sphereCoordinates.size() * sizeof(float), &_sphereCoordinates[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glBufferData(GL_ARRAY_BUFFER, _textureCoordinates.size() * sizeof(float), &_textureCoordinates[0], GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _sphereIndexes.size() * sizeof(unsigned int), &_sphereIndexes[0], GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("ball.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
void SphereShaderProgram::LoadAttributeVariables()
{
// Vertex Attributes
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
I get an error when binding the program.
You're very close. The only thing I see missing is that you do not bind the correct buffer before calling glVertexAttribPointer(). When you call glVertexAttribPointer(), you specify that the data for the attribute will be pulled from the buffer that is currently bound to GL_ARRAY_BUFFER.
Your LoadAttributeVariables() method should therefore be:
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[0]);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint TextureCoord_Location = glGetAttribLocation(GetProgramID(), "texCoord");
glEnableVertexAttribArray(TextureCoord_Location);
glBindBuffer(GL_ARRAY_BUFFER, _vbo[1]);
glVertexAttribPointer(TextureCoord_Location, 2, GL_FLOAT, GL_FALSE, 0, 0);
Related
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 working on some examples, and I was trying to pass a texture to a shader.
To build a VAO, I have this piece of code:
void PlaneShaderProgram::BuildVAO()
{
// Generate and bind the vertex array object
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Generate and bind the vertex buffer object
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), _coordinates, GL_STATIC_DRAW);
// Generate and bind the index buffer object
glGenBuffers(1, &_ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), _indexes, GL_STATIC_DRAW);
// Generate and bind texture
_texture = LoadTexture("floor.bmp");
LoadAttributeVariables();
glBindVertexArray(0);
}
This is how I load the shader attributes:
void PlaneShaderProgram::LoadAttributeVariables()
{
GLuint VertexPosition_location = glGetAttribLocation(GetProgramID(), "vPosition");
glEnableVertexAttribArray(VertexPosition_location);
glVertexAttribPointer(VertexPosition_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
void PlaneShaderProgram::LoadUniformVariables()
{
// OpenGL Matrices
GLuint ModelViewProjection_location = glGetUniformLocation(GetProgramID(), "mvpMatrix");
glUniformMatrix4fv(ModelViewProjection_location, 1, GL_FALSE, glm::value_ptr(_ModelViewProjection));
// Floor texture
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, _texture);
// GLint Texture_location = glGetUniformLocation(GetProgramID(), "texture");
// glUniform1i(Texture_location, 0);
}
And my LoatTexture:
GLuint ProgramManager::LoadTexture(const char* imagepath)
{
unsigned char * data = LoadBMP(imagepath, &width, &height);
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
return textureID;
}
Finally, my draw function, which is called in the OpenGL main loop, is the following:
void PlaneShaderProgram::DrawPlane(const glm::mat4 &Projection, const glm::mat4 &ModelView)
{
_ModelViewProjection = Projection * ModelView;
_ModelView = ModelView;
Bind();
glBindVertexArray(_vao);
LoadUniformVariables();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
UnBind();
}
What I didn't get is that even if I didn't set the uniform texture (commented in the code) used by my shader, the plane is still draw using the texture. This makes no sense for me. Once the shader requires a sample2D, I think this shouldn't work and return some error.
Vertex Shader:
uniform mat4 mvpMatrix;
in vec4 vPosition;
smooth out vec2 uvCoord;
void main()
{
uvCoord = vPosition.xz;
gl_Position = mvpMatrix * vPosition;
}
Frag Shader:
uniform sampler2D texture;
in vec2 uvCoord;
out vec4 fragColor;
void main()
{
fragColor.rgb = texture(texture, uvCoord).rgb;
};
Am I missing something? Somehow this works I don't understand why, but I really like to.
The sampler data types in GLSL reference the texture unit, not a texture object. By default, uniforms will be initialized to 0, so if you don't set the sampler uniforms, they will sample from texture unit 0 (which is also the default unit). In your ProgramManager::LoadTexture() method, you bind the newly created texture, and very likely you are still using GL_TEXTURE0 as the currently active texture unit. You never seem to unbind it, so it is still bound at the time of the draw call, and the shader can access it.
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.
|Actually, I am trying to display two or more models on the screen at the same time. I am generating three different vertex buffers for vertices, colors, normals separately, here is the main code:
//==================From here is my implementation ==========================//
// Create and compile our GLSL program from the shaders. Todo: load shader
GLuint programID = LoadShaders("simple_shading.vertexshader", "simple_shading.fragmentshader");
// Get a handle for uniform variables such as matrices, lights, ....
GLuint ModelMatrixID = glGetUniformLocation(programID, "ModelMatrix");
GLuint ViewMatrixID = glGetUniformLocation(programID, "ViewMatrix");
GLuint NormalMatrixID = glGetUniformLocation(programID, "NormalMatrix");
GLuint lightPosition_worldspaceID = glGetUniformLocation(programID, "lightPosition_worldspace");
GLuint lightColorID = glGetUniformLocation(programID, "lightColor");
// Get a handle for vertex attribute arrays such as vertex positions, colors, normals, ....
GLuint vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
GLuint vertexColorID = glGetAttribLocation(programID, "vertexColor");
GLuint vertexNormal_modelspaceID = glGetAttribLocation(programID, "vertexNormal_modelspace");
// Load your scene
TRIModel model;
TRIModel model2;
model.loadFromFile("models/ball.tri");
model2.loadFromFile("models/ball.tri");
//vector<TRIModel> models;
/*** Here shows an exmple which generates three different vertex buffers for vertices, colors, normals.***/
//However, you can always incorporate them together in a single buffer.(Hint: use glBufferSubData)
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.vertices[0], GL_STATIC_DRAW);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.foreColors[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, model.vertices.size() * sizeof(vec3), &model.normals[0], GL_STATIC_DRAW);
///*** **/
GLfloat rotZ;
while (!glfwWindowShouldClose(window))
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// //Tell OpenGL to use the shader program
glUseProgram(programID);
// //send matrix to shader: You can use the keyboard and mouse to close the window and control the transformation
// // (See computeMatricesFromKey(window) )
mat4 ModelMatrix;
mat4 ViewMatrix = lookAt( vec3(0.5, 0.5, 1), vec3(2, 3, 2), vec3(0, 1.0, 0.0) );
//move object to the world origin
ModelMatrix = translate(mat4(1.0), -vec3(model.center[0], model.center[1], model.center[2]));
ModelMatrix = scale( ModelMatrix, vec3(0.002, 0.002, 0.002) );
ModelMatrix = rotate( ModelMatrix, rotZ, vec3(0.0, 0.0, 1.0) );
mat4 NormalMatrix = transpose( inverse(ViewMatrix * ModelMatrix) );
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(NormalMatrixID, 1, GL_FALSE, &NormalMatrix[0][0]);
// //send lights to shader
vec3 lightPosition = vec3(4, 4, 4);
vec3 lightColor = vec3(1.0, 1.0, 1.0);
glUniform3f(lightPosition_worldspaceID, lightPosition.x, lightPosition.y, lightPosition.z);
glUniform3f(lightColorID, lightColor.r, lightColor.g, lightColor.b);
//define an vertex attribute array on the vertex buffer
glEnableVertexAttribArray(vertexPosition_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
// //define an vertex attribute array on the color buffer
glEnableVertexAttribArray(vertexColorID);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
vertexColorID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
// //define an vertex attribute array on the normal buffer
glEnableVertexAttribArray(vertexNormal_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
vertexNormal_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*) 0 // array buffer offset
);
//draw the scene by vertex attribute arrays
glDrawArrays(GL_TRIANGLES, 0, model.vertices.size());
glDisableVertexAttribArray(vertexPosition_modelspaceID);
glDisableVertexAttribArray(vertexColorID);
glDisableVertexAttribArray(vertexNormal_modelspaceID);
glfwSwapBuffers(window);
glfwPollEvents();
//
// //update rotate angle
rotZ += 0.1;
}
//// Cleanup VBO and shade //glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteBuffers(1, &normalbuffer);
glDeleteProgram(programID);
//=================== implementation Ends here ================================//
I read in some resources that I can incorporate them together in a single buffer using glBufferSubData, but I dont know how to use it. eventually, I have successfully displayed one model as shown in the picture. Now, if I need to display another model, lets say I want to display another ball on the right side, what should I do? I tried to generate a nother set of buffers , but it is still not working. what I can see is just model one. Any ideas?
I am trying to map a texture to objects using GLSL version 330
Here is some code that my help you understanding my problem
Fragment Shader:
#version 330
layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 vertex_normal;
layout(location = 2) in vec2 texCoord;
out vec2 tCoord;
uniform mat4 modelview;
uniform mat4 projection;
void main() {
gl_Position = projection * modelview * vec4(vertex, 1.0);
tCoord = texCoord;
}
Vertex Shader
#version 330
in vec2 tCoord;
uniform sampler2D texture;
out vec4 color;
void main() {
if(tCoord == vec2(0,0))
color = vec4(1.0,0.0,0.0,1.0);
else
color = vec4(0.0,1.0,0.0,1.0);
}
Loading the Mesh and texture to OpenGL
texture coordinates will be boudn using vertexAttribPointer to position 2 (0 is position and 1 is normal)
Creating the MeshObj
void MeshObj::setData(const MeshData &meshData) {
mIndexCount = meshData.indices.size();
// TODO: extend this method to upload texture coordinates as another VBO //
// - texture coordinates are at location 2 within the shader code
// create local storage arrays for vertices, normals and indices //
unsigned int vertexDataSize = meshData.vertex_position.size();
unsigned int vertexNormalSize = meshData.vertex_normal.size();
unsigned int vertexTexcoordSize = meshData.vertex_texcoord.size();
GLfloat *vertex_position = new GLfloat[vertexDataSize]();
std::copy(meshData.vertex_position.begin(), meshData.vertex_position.end(), vertex_position);
GLfloat *vertex_normal = NULL;
if (vertexNormalSize > 0) {
vertex_normal = new GLfloat[vertexNormalSize]();
std::copy(meshData.vertex_normal.begin(), meshData.vertex_normal.end(), vertex_normal);
}
GLfloat *vertex_texcoord = NULL;
if (vertexTexcoordSize > 0) {
vertex_texcoord = new GLfloat[vertexTexcoordSize]();
std::copy(meshData.vertex_texcoord.begin(), meshData.vertex_texcoord.end(), vertex_texcoord);
}
GLuint *indices = new GLuint[mIndexCount]();
std::copy(meshData.indices.begin(), meshData.indices.end(), indices);
// create VAO //
if (mVAO == 0) {
glGenVertexArrays(1, &mVAO);
}
glBindVertexArray(mVAO);
// create and bind VBOs and upload data (one VBO per available vertex attribute -> position, normal) //
if (mVBO_position == 0) {
glGenBuffers(1, &mVBO_position);
}
glBindBuffer(GL_ARRAY_BUFFER, mVBO_position);
glBufferData(GL_ARRAY_BUFFER, vertexDataSize * sizeof(GLfloat), &vertex_position[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
if (vertexNormalSize > 0) {
if (mVBO_normal == 0) {
glGenBuffers(1, &mVBO_normal);
}
glBindBuffer(GL_ARRAY_BUFFER, mVBO_normal);
glBufferData(GL_ARRAY_BUFFER, vertexNormalSize * sizeof(GLfloat), &vertex_normal[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
}
if (vertexTexcoordSize > 0) {
if (mVBO_texcoord == 0) {
glGenBuffers(1, &mVBO_texcoord);
}
std::cout << "Texture stuff set" << std::endl;
glBindBuffer(GL_ARRAY_BUFFER, mVBO_texcoord);
glBufferData(GL_ARRAY_BUFFER, vertexTexcoordSize * sizeof(GLfloat), &vertex_texcoord[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
}
// init and bind a IBO //
if (mIBO == 0) {
glGenBuffers(1, &mIBO);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexCount * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);
// unbind buffers //
glBindVertexArray(0);
// make sure to clean up temporarily allocated data, if neccessary //
delete[] vertex_position;
if (vertexNormalSize > 0) {
delete[] vertex_normal;
}
if (vertexTexcoordSize > 0) {
delete[] vertex_texcoord;
}
delete[] indices;
}
Render the Scene
glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
glActiveTexture(GL_TEXTURE0);
glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),0.0f,-13.0f,-10.0f);
glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));
glBindTexture(GL_TEXTURE_2D, objLoader->getMeshObj("trashbin")->getTexttureID());
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("trashbin")->getTexttureID());
objLoader->getMeshObj("trashbin")->render();
glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),-9.0f,-13.0f,-10.0f);
glm_ModelViewMatrix.top() = glm::scale(glm_ModelViewMatrix.top(), 1.5f,1.5f,1.5f);
glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));
glBindTexture(GL_TEXTURE_2D, objLoader->getMeshObj("ball")->getTexttureID());
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("ball")->getTexttureID());
objLoader->getMeshObj("ball")->render();
// restore scene graph to previous state //
glm_ModelViewMatrix.pop();
Render the mesh
void MeshObj::render(void) {
// render your VAO //
if (mVAO != 0) {
glBindVertexArray(mVAO);
glDrawElements(GL_TRIANGLES, mIndexCount, GL_UNSIGNED_INT, (void*)0);
glBindVertexArray(0);
}
}
After all this code, now a short description of my problem:
In my shaders I am currently checking if the texCoord is passed correctly to the shader, but it always stays (0,0).
Where is the problem when uploading the texture coordinates? The same technique is working fine for the vertexPosition and the vertex normal...
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), objLoader->getMeshObj("trashbin")->getTexttureID());
Try passing in the texture unit index (texUnit) instead of the texture object ID (texObj, from a glGenTextures() call).
Generally:
unsigned int texUnit = 0;
glActiveTexture( GL_TEXTURE0 + texUnit );
glBindTexture( GL_TEXTURE_2D, texObj );
glUniform1i( ..., texUnit );
In your case:
glActiveTexture( GL_TEXTURE0 );
...
glBindTexture( GL_TEXTURE_2D, objLoader->getMeshObj("trashbin")->getTexttureID() );
glUniform1i( glGetUniformLocation( shaderProgram, "texture" ), 0 );
You don't give the image to OpenGL at any point with glTexImage2D
Add this below your bind texture in order to give OpenGL your texture
//example parameters, substitute with your own.
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
//just parameters for texture(optional)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Reference to glTexImage2D:
http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml