OpenGL odd z-axis behaviour when drawing square - c++

I'm a newcomer to OpenGL and I was playing around with drawing triangles with different z-coordinates. From what I understand, the z axis point out of the screen, and the -z axis points into the screen.
When I draw a square with 3 corners at a 0.0 z-coordinate, and the last corner at, say, -3.0 z-coordinate, I get this:
I don't understand how it's making this shape... I thought it would be something like this, since the 4th vertex is just 'far away'.
Can someone explain?
Edit: This is my vertex data
// vertex array
float vertices[] = {
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // top left, first 3 are location, last 3 are color
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // top right
-0.5f, -0.5f, -2.0f, 0.0f, 0.0f, 1.0f, // bottom left
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f // bottom right
};
// element buffer array
GLuint elements[] = {
0, 1, 2,
2, 1, 3
};
And I am calling the draw like:
glDrawElements(GL_TRIANGLES, 6,GL_UNSIGNED_INT,0);

I assume that you've just begun learning OpenGL. The problem is that any value not belonging to the range [-1, 1] is simply "out of bounds". All values are normalized in OpenGL. This improves portability. Just think that the whole world(if you're familiar with game development) is a cube of side 2 units. Any further and you're somewhere else entirely. Hope it helps!

Related

Texture mapping on cube only shows two sides correctly

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
// ...
};

OpenGL z value. Why negative value in front?

Opengl has right-hand coordinate system. It means z values increase towards me.
right-hand coordinate system
I draw two triangles:
float vertices[] =
{
//position //color
//triangle 1
0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//0
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//1
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//2
//triangle 2
0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//3
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//4
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f//5
};
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
After it, if I translate vertices by z=-3 in vertex shader, this translation behaves as it should be. Object becomes further.
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
Of course the red triangle is in front of the blue one, because you don't use any projection matrix. You forgot to transform the input vertex by the projection matrix before you assign the vertex coordinate to gl_Position.
This causes that the vertices are equal to the normalized device space coordinates. In normalized device space the z-axis points into the viewport and the "projection" is orthographic and not perspective.
You have to do something like this:
in vec3 aPos;
mat4 modelProjectionMatrix;
void main()
{
gl_Position = modelProjectionMatrix * vec4(aPos, 1.0);
}

Why changing the Z position of the 'camera' won't show the primitive?

I have an untransformed struct with the vertices coordination that'll form up a triangle:
struct utVertex ut_Vertex[] =
{
{ 2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), }, //a
{ 0.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), }, //b
{ -2.5f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },//c
};
The image above should (not sure, because z axis could be inverted, + perhaps should be where - is) be correct according to my code:
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3(0.0f, 0.0f, 10.0f),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
d3dDevice->SetTransform(D3DTS_VIEW, &matView);
The blue dot on the image above should be the camera position based on this code. (Please tell me if I'm wrong).
This draws a triangle correctly on screen.
Now, if I change the camera position to -10.0f instead of 10.0f (I think) this is where the camera should be:
But it should still be looking at 0.0f, 0.0f, 0.0f.
If it does, then why changing Z position of the 'camera' won't show the primitive(triangle)?
Nothing shows:
The polygons you're using are single sided, so they are not visible when viewed from behind. To get your triangle to show when you reverse the camera, you'll either need to add another polygon with the same points but listed in the opposite direction - (a,c,b) instead of (a,b,c) - or swap two of these points in your ut_Vertex array.

DirectX 9 hiding first triangle in TRIANGLEFAN

My question is: How can I draw a correct pyramid (triangular quadrilateral pyramid) using D3DPT_TRIANGLEFAN?
I used as points:
CUSTOMVERTEX vertices[] =
{
{ 0.0f, 3.0f, 0.0f, 0x00ff0000, }, //The top Vertex
{ 1.0f, 0.0f, -1.0f, 0xff00ff00, }, //(A) vertex
{ 1.0f, 0.0f, 1.0f, 0xff0000ff, }, //(B) vertex
{ -1.0f, 0.0f, 1.0f, 0xffffff00, }, //(C) vertex
{ -1.0f, 0.0f, -1.0f, 0xffff00ff, }, //(D) vertex
{ 1.0f, 0.0f, -1.0f, 0xff00ff00, }, //(A) vertex
};
where a CUSTOMVERTEX is:
struct CUSTOMVERTEX
{
float x, y, z;
DWORD color;
};
and I call it by:
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 5);
The pyramid draws correctly, but there is an additional triangle drawn to the screen, the one made with the top and the first vertex ( a right triangle with the PI / 2 angle in the base of the pyramind and the other point being <<1.0f, 0.0f, -1.0f>> (the first point (A)).
So what I want is to hide that triangle, I tried making the device draw from 1 to 5 but that only gives me the base ( (A)-(B)-(C)-(D) plane ), and I also tried making the culling D3DCULL_CW, and when I rotated the pyramid half the time I can see the additional triangle and half it was hidden by another plane.
The last parameter to IDirect3DDevice9::DrawPrimitive() is the primitive count which should be 4 in your case?
If you want to include the base you'll have to render the pyramid as a triangle list instead as a complete pyramid can't be represented by a fan.

OpenGL Rendering Issue With glDrawElement

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?