I tried to make a cube in openGL and render a default texture on each side. I've been messing around with it for days but I cant get it to work. I really don't know what the problem is as I am convinced that my vertices and texture coordinates are right. What am I doing wrong?
These are my vertices, uv's and indices:
vertices = {
// front face
0.0f, 0.0f, 0.0f,
length, 0.0f, 0.0f,
length, height, 0.0f,
0.0f, height, 0.0f,
// back face
0.0f, 0.0f, width,
length, 0.0f, width,
length, height, width,
0.0f, height, width,
// left face
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, width,
0.0f, height, width,
0.0f, height, 0.0f,
// right face
length, 0.0f, 0.0f,
length, 0.0f, width,
length, height, width,
length, height, 0.0f,
// top face
0.0f, height, 0.0f,
length, height, 0.0f,
length, height, width,
0.0f, height, width,
// bottom face
0.0f, 0.0f, 0.0f,
length, 0.0f, 0.0f,
length, 0.0f, width,
0.0f, 0.0f, width
};
uvs = {
// front face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// back face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// left face
0.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
0.0f, 1.0f,
// right face
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
// top face
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// bottom face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f
};
indices = {
// front face
0, 1, 2,
2, 3, 0,
// right face
1, 5, 6,
6, 2, 1,
// back face
7, 6, 5,
5, 4, 7,
// left face
4, 0, 3,
3, 7, 4,
// bottom face
4, 5, 1,
1, 0, 4,
// top face
3, 2, 6,
6, 7, 3
};
This is my render method:
void Mesh::render() {
// Render the pyramid using OpenGL
view = glm::lookAt(Camera::getInstance().cameraPos, Camera::getInstance().cameraPos + Camera::getInstance().cameraFront, Camera::getInstance().cameraUp);
mvp = projection * view * model;
// Attach to program_id
glUseProgram(programId);
// Send mvp
glUniformMatrix4fv(uniformMvp, 1, GL_FALSE, glm::value_ptr(mvp));
// Send vao
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, textureId);
glDrawElements(GL_TRIANGLES, indices.size() * sizeof(GLushort),
GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
}
Vertexshader:
#version 430 core
in vec2 UV;
uniform sampler2D texsampler;
layout(location = 0) out vec4 gl_FragColor;
void main()
{
// Compute the diffuse and specular components for each fragment
vec3 test = texture2D(texsampler, UV).rgb;
// Write final color to the framebuffer
gl_FragColor = vec4(test, 1.0);
}
and the fragmentshader:
#version 430 core
// Uniform matrices
uniform mat4 mv;
uniform mat4 projection;
// Per-vertex inputs
in vec3 position;
// UV
in vec2 uv;
out vec2 UV;
void main()
{
// Calculate view-space coordinate
vec4 P = mv * vec4(position, 1.0);
// Calculate the clip-space position of each vertex
gl_Position = projection * P;
UV = uv;
}
Image of the cube:
I think this is enough information. Only the front and the back are textured normally and the rest is just like on the image.
Your texture coordinates are wrong, as commented:
// left face
0.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
0.0f, 1.0f,
// right face
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
This tells the computer to take a single line of pixels and stretch them across the entire face. The U coordinate is the same for the whole face. It does not advance from left to right across the texture.
Same for the top and bottom faces:
// top face
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// bottom face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f
the V does not advance, so the computer keeps reading the first or last row of the texture over and over. If you want to use the entire texture, then V should be 0 on one side of the texture, and 1 on the other side. Also note the direction where U changes must be different than the direction V changes - i.e. they can't change together - or else the compute only reads the diagonal pixels where U and V are equal.
Looking at OPs vertices, I noticed that there are 24 of them although a cube has 8 corners only. That's not surprising as coordinates for the same corner may correspond to distinct vertex coordinates depending on which face it belongs to.
Hence, it makes sense to define coordinates and corresponding texture coordinates per face, i.e. 6 faces with 4 corners each face -> 24 coordinates.
I enriched OPs code with enumeration:
vertices = {
// front face
0.0f, 0.0f, 0.0f, // 0
length, 0.0f, 0.0f, // 1
length, height, 0.0f, // 2
0.0f, height, 0.0f, // 3
// back face
0.0f, 0.0f, width, // 4
length, 0.0f, width, // 5
length, height, width, // 6
0.0f, height, width, // 7
// left face
0.0f, 0.0f, 0.0f, // 8
0.0f, 0.0f, width, // 9
0.0f, height, width, // 10
0.0f, height, 0.0f, // 11
// right face
length, 0.0f, 0.0f, // 12
length, 0.0f, width, // 13
length, height, width, // 14
length, height, 0.0f, // 15
// top face
0.0f, height, 0.0f, // 16
length, height, 0.0f, // 17
length, height, width, // 18
0.0f, height, width, // 29
// bottom face
0.0f, 0.0f, 0.0f, // 20
length, 0.0f, 0.0f, // 21
length, 0.0f, width, // 22
0.0f, 0.0f, width // 23
};
uvs = {
// front face
0.0f, 0.0f, // 0
1.0f, 0.0f, // 1
1.0f, 1.0f, // 2
0.0f, 1.0f, // 3
// back face
0.0f, 0.0f, // 4
1.0f, 0.0f, // 5
1.0f, 1.0f, // 6
0.0f, 1.0f, // 7
// left face
0.0f, 0.0f, // 8
0.0f, 0.0f, // 9
0.0f, 1.0f, // 10
0.0f, 1.0f, // 11
// right face
1.0f, 0.0f, // 12
1.0f, 0.0f, // 13
1.0f, 1.0f, // 14
1.0f, 1.0f, // 15
// top face
0.0f, 1.0f, // 16
1.0f, 1.0f, // 17
1.0f, 1.0f, // 18
0.0f, 1.0f, // 29
// bottom face
0.0f, 0.0f, // 20
1.0f, 0.0f, // 21
1.0f, 0.0f, // 22
0.0f, 0.0f // 23
};
But then I took a closer look what the indices look-up:
indices = {
// ...
// right face
1, 5, 6, // -> UV: { 1.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }
6, 2, 1, // -> UV: { 1.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }
// ...
}
There are only two distinct values of texture coordinates but there should be four of them. Hence, it's not a surprise if the texture projection of that right face looks strange.
OP noted the wrong indices. This doesn't manifest in the geometry as the wrong indices address coordinates (vertices) with identical values. However, concerning the texture coordinates (uvs) these indices are just wrong.
According to the added index values, I corrected the indices for the right face:
indices = {
// ...
// right face
12, 13, 14,
14, 15, 12,
// ...
}
The indices of the top face are defined correctly but the other faces have to be checked as well. (I leave this as "homework" to OP. Or, like a colleague of mine used to say: Not to punish just to practice.) ;-)
On the second glance, I realized that OP's texture coordinates are wrong as well.
To understand how texture coordinates work:
There is a uv coordinate system applied to the image with
(0, 0) … the lower left corner
(1, 0) … the lower right corner
(0, 1) … the upper left corner
of the image.
taken from opengl-tutorial – Tutorial 5: A Textured Cube
Hence, using my
uvs = {
// ...
// right face
1.0f, 0.0f, // 12
1.0f, 0.0f, // 13
1.0f, 1.0f, // 14
1.0f, 1.0f, // 15
// ...
};
provides two times the lower right corner and two times the upper right corner. The result of such texture projection are stripes instead of bricks.
A better result should be achieved by repeating the texture coordinates of the front face 6 times:
uvs = {
// ...
// right face
0.0f, 0.0f, // 12
1.0f, 0.0f, // 13
1.0f, 1.0f, // 14
0.0f, 1.0f, // 15
// ...
};
I am a little confused when it comes to what function i should be using for my OpenGL Deferred Rendering.
I have a list of VBO( vertex buffer objects )
each one represents a type of vertex such a one might be (Position + Color)
I also have one for indeces
my problem comes when i want to render different objects
im use to the directX way where you
1)activate your vertex buffer
2)activate your index buffer
3) then you specify on your draw call your primitive type
the start vertex from the vertex buffer, the min vertex index, the vertex count, the start indice and the primivite count
with openGL im lost because i can use:
glDrawElements - but this uses render mode, object count, the indice byte type and the indices
this just basically tells me it will render at the start of the VBO which wont help me any if i have multiple objects in there.
Anyone have any clue what rendering function openGL has that I can specify where in the VBO to start rendering from and specify my start vertex position? I hope someone has any idea =\
glDrawElements starts not from the start of the VBO, but from wherever you specify the pointer to start.
If you have a VBO and you want to start rendering from the second half of it, then you set the byte offset to start from as the last attribute of glVertexAttribPointer.
You have several options.
You can reposition the start of each particular object's vertex data by issuing more glVertexAttribPointer calls before you draw that object. Or you can use glDrawElementsBaseVertex, where you get to specify a vertex index that all of the indices fetched by gets added to.
The latter should be available on any non-Intel hardware still supported.
Edit: I just realized that this might not be applicable if you're not using shaders, but since I'm not familiar with legacy OpenGL I'm not sure what benefit what my post has to you. What version are you using/targeting?
I recently asked a question regarding glDrawElements here. Hopefully what I posted gives some explanation/example.
The way I understand it: your indices are determined by you, so if you want to start at the 2nd vertex, you could try (a basic skeleton, does not have glVertexAttribPointer calls and such but i can add those if you want):
const float VBOdata = {
//Some X and Y coordinates for triangle1 (in the first quadrant)
//(z = 0, w = 1 and are not strictly necessary here)
0.0f, 1.0f, 0.0f, 1.0f //index 0
0.0f, 0.0f, 0.0f, 1.0f //1
1.0f, 0.0f, 0.0f, 1.0f //2
//Some X and Y coordinates for triangle2 (in the second quadrant)
0.0f, -1.0f, 0.0f, 1.0f //3
0.0f, 0.0f, 0.0f, 1.0f //4
-1.0f, 0.0f, 0.0f, 1.0f //5
//Now some color data (all white)
1.0f, 1.0f, 1.0f, 1.0f, //0
1.0f, 1.0f, 1.0f, 1.0f, //1
1.0f, 1.0f, 1.0f, 1.0f, //2
1.0f, 1.0f, 1.0f, 1.0f, //3
1.0f, 1.0f, 1.0f, 1.0f, //4
1.0f, 1.0f, 1.0f, 1.0f, //5
};
const GLubyte indices[] = {
3, 4, 5,
};
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indices);
Where GL_TRIANGLES is the type of primitive, 3 is the number of elements inside of "indices", GL_UNSIGNED_BYTE is how to interpret them, and "indices" is just the name of the array.
This should draw only the second triangle. You can also try glDrawElementsBaseVertex, but I haven't personally tried it myself. What I gather is that you would generate/explicitly code your indices starting from 0, but give an offset so that it actually reads at 0+offset, 1+offset, and so on.
Does this help?