How to use the stride parameter in VBO? - c++

I have problems understanding how to use one buffer with 3 different data in it, I have the following structure for my vert,text,color data:
struct xyzf {
float x, y, z;
};
struct xyf {
float x, y;
};
struct vertype {
xyzf points[4];
};
struct textype {
xyf points[4];
};
struct coltype {
GLuint points[4];
};
struct buftype {
vertype vertex;
textype texcoord;
coltype color;
};
Then I (try to) use it in the following way (which makes most sense to me):
glBindBufferARB(GL_ARRAY_BUFFER, mybufid);
glVertexPointer(3, GL_FLOAT, sizeof(buftype), 0);
glTexCoordPointer(2, GL_FLOAT, sizeof(buftype), (GLvoid *)sizeof(vertype));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(buftype), (GLvoid *)(sizeof(vertype)+sizeof(textype)));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_QUADS, 0, indices);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER, 0); // unbind
But it fails, and its rendering something else than what I got with setting stride and pointers to zero all. When I do that, I get my vertex data correctly rendered, but text/color still incorrect.
I can't use &data[0].vertex for the last param in glVertexPointer() etc. because I don't have the data anymore since I am using a VBO, that method works only with vertex arrays.
Also I'm not sure how the count value for glDrawArrays() works, I read docs which say it is the indices, so a quad would have 4, right? But when I multiply the count of quads by 4, it only renders HALF of my vertices, whats going on there? (it will render them all if I multiply by 8...)

It seems you are interleaving your data per quad, but you should rather interleave it per vertex (at least that's what usually done).
Your code should be right if you change the vertex layout to this:
xyz
uv
rgba
xyz
uv
rgba
xyz
uv
rgba
xyz
uv
rgba
Rather than
xyzxyzxyzxyz
uvuvuvuv
rgbargbargbargba

Related

Opengl: triangles with element buffer object (EBO) aka GL_ELEMENT_ARRAY_BUFFER

I am trying to render a kinect depth map in real time and in 3D using openGL in an efficient way to possibly scale up and use multiple kinects.
A frame from the kinect gives 640*480 3D coordinates. X and Y are static and Z vary each frame depending on the depth of what the kinect films.
I am trying to modify my GL_ARRAY_BUFFER but partially since the X and Y don't change, I just need to change the Z part of the buffer. This is easy yet, I can use glBufferSubData or glMapBuffer to partially change the buffer and I thus decided to put all X values together, all Y togethers and all Z together at the end, I can thus change in one block the whole Z values.
The problem is the following: Since I have a cloud points of vertices, I want to draw triangles from them and the easy way I found was using a GL_ELEMENT_ARRAY_BUFFER which prevents repeating vertices multiple times. But GL_ELEMENT_ARRAY_BUFFER reads from the buffer X,Y,Z in an automatic way. Like you give the indice 0 to the GL_ELEMENT_ARRAY_BUFFER, I'd like him to take his X from the first X element in the buffer, his Y from the first Y element in the buffer and his Z from the first Z element in the buffer. Since the vertices coordinates are not arranged in a continuous fashion, it doesn't work.
Is there an alternative to specify to the GL_ELEMENT_ARRAY_BUFFER how to interprete the indices?
I tried to find a way to glBufferSubData in a disparate way (not big continuous chunk of memory but rater changing an element in the buffer every 3 steps, but this seems not optimal)
I'm not entirely sure what the problem is here? Indices stored within a GL_ELEMENT_ARRAY_BUFFER can be used to index multiple buffers at the same time. Just set up your separated vertex buffers in your VAO:
glBindBuffer(GL_ARRAY_BUFFER, vbo_X);
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, sizeof(float), 0); //< x
glBindBuffer(GL_ARRAY_BUFFER, vbo_Y);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(float), 0); //< y
glBindBuffer(GL_ARRAY_BUFFER, vbo_Z);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(float), 0); //< z
Set your indices and draw:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, 0);
And then just recombine the vertex data in your vertex shader
layout(location = 0) in float x_value;
layout(location = 1) in float y_value;
layout(location = 2) in float z_value;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(x_value, y_value, z_value, 1.0);
}

OpenGL : How can I pass multiple texture to a shader with one variable?

I loaded the material and texture information from the Obj file based on this code (https://github.com/Bly7/OBJ-Loader). Now I want to load Sponza and render it. However, there are 10 or more textures, and even if all are passed to the shader, it is necessary to correspond to the appropriate vertices. Looking at the result of loading from the Obj file, textures are assigned to each part.
Example.
Mesh 0 : Pillar
position0(x, y, z), position1(x, y, z), uv0(x, y) ...
diffuse texture : tex0.png
Mesh 1 : Wall
position0(x, y, z), position1(x, y, z), uv0(x, y) ...
diffuse texture : tex1.png
.
.
.
Textures are kept as an array, and each has a corresponding mesh index. In my opinion, when passing vertex information to the shader, it works well if you divide it by the number of meshes and pass the texture at the same time. However, I'm not sure if this idea is correct, and I've tried several methods but it doesn't work.
This is the current simple code.
main.cpp :
do {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture[i]); // texture[] : Array of textures loaded from obj file.
glUniform1i(glGetUniformLocation(shaderID, "myTex"), 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_position);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, texCoord);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element);
glDrawElements(GL_TRIANGLES, element_indices.size(), GL_UNSIGNED_INT, (void*)0);
} while(glfwWindowShouldClose(window) == 0);
Fragment shader :
layout(location = 0) out vec4 out_color;
// from vertex shader
in vec2 texCoord;
uniform sampler2D myTex;
void main() {
out_color = texture(myTex, texCoord);
}
I want to correspond to the mesh index loaded with the "i" in the above code. Please let me know if my idea is wrong or if there is another way.
As your model has only one texture per mesh, I can suggest this simple code to use:
do {
glActiveTexture(GL_TEXTURE0);
glUniform1i(glGetUniformLocation(shaderID, "myTex"), 0);
for (unsigned int i = 0; i < mesh_count; i++) {
glcall(glBindTexture(type, texture[i]));
// Bind vertex and index (or element) buffer and setup vertex attribute pointers
// Draw mesh
}
} while (window_open);
The code much self-explaning. It first activates texture slot 0, then for every mesh it binds texture, vertex buffer, index or element buffer and does any preparation need to draw the mesh. Then it issues draw call.
Note that this is very basic example. Most models would look weird with this code. I would recommend to this tutorial from LearnOpenGL which explain this more broadly but in an easy way.

Colors in OpenGL VBOs?

I'm trying to add colors to my object that using a single struct and single VBO in OpenGL. To do this, I have a Vertex struct that I created that looks like this:
typedef struct {
float x;
float y;
float z;
float r;
float g;
float b;
float a;
} Vertex;
I already know that I'm setting all of the coordinates and colors correctly to get what I want, because I ran a test iterating over each object I have stored in my list and drawing out the points and setting the colors using glVertex3f and glColor4f (this was significantly slower than what I'm looking for). But when I try to draw it using VBOs I just get a huge mess of colored triangles going everywhere.
The part of my rendering loop that draws the VBO looks like this:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, offsetof(Vertex, r), NULL);
glDrawArrays(GL_TRIANGLES, 0, vertex_amount);
glBindBuffer(GL_ARRAY_BUFFER, 0);
What am I doing wrong?
glVertexPointer(3, GL_FLOAT, 0, NULL);
^
The position values in an array of Vertexs are not tightly packed so you can't use 0 for stride. Use sizeof( Vertex ).
glColorPointer(4, GL_FLOAT, offsetof(Vertex, r), NULL);
^^^^^^^^^^^^^^^^^^^
I'm...not sure what you're going for here. Perhaps you thought the 3rd parameter of glVertexPointer()/glColorPointer() was pointer instead of stride? Move your offsetof() to the final parameter, pointer.
All together:
glVertexPointer(3, GL_FLOAT, sizeof( Vertex ), offsetof(Vertex, x) );
glColorPointer(4, GL_FLOAT, sizeof( Vertex ), offsetof(Vertex, r) );
You may have to cast the pointer parameter values to void* depending on how you've implemented offsetof().

(OpenGL) How to transform an object while keeping an identical object stationary?

So I had a quick question about a homework assignment I was assigned for my OpenGL class. In class, we made two triangles transform (get bigger and smaller) as they follow a sine wave, and our homework is to make it so that only one transforms while the other stays static, all while only using one vertex shader, one fragment shader, and uniform variables. When I tried it, my mindset was to somehow return the value of 1 to a Scale variable to keep one of the triangles from moving. I was able to make it so that one of the triangles was stationary, but no shader was attached to it, so it was solid white. I have a feeling I have to use some OOP to create another instance of the triangle, but I really can't wrap my head around how I'm supposed to distinguish between the two triangles while only using one vertex shader. Can anyone shed some light onto this? This is the hardest class of the curriculum, so even a hint would be lovely! Thank you! I can post my code if you all want, but I made some changes to it that made my program cry, so I'll try to retrace my steps and post it tomorrow! Thank you all!
[EDIT] Okay here's my code. Trying to make it so that only the red triangle is static. I have a feeling the answer is in the provided class in the form of an "if statement", though I could be wrong about the complexity of this problem. Thank you all again for helping me.
#include "Triangle.h"
Triangle::Triangle(vec3 points[], vec4 color[], GLuint pID)
{
ProgramID = pID;
memcpy(Points, points, sizeof(Points));
memcpy(Colors, color, sizeof(Colors));
glUseProgram(ProgramID);
glGenVertexArrays(1, &VBO);
glBindVertexArray(VBO);
glGenBuffers(1, &VB);
glBindBuffer(GL_ARRAY_BUFFER, VB);
glBufferData(GL_ARRAY_BUFFER, sizeof(Points), Points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glGenBuffers(1, &CB);
glBindBuffer(GL_ARRAY_BUFFER, CB);
glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
Scale = 90.0f;
gScaleLocation = glGetUniformLocation(ProgramID, "Scale");
}
void Triangle::Draw()
{
glUseProgram(ProgramID);
glBindVertexArray(VBO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
if ()
{
Scale += 0.0f;
}
else
{
Scale += 0.01f;
}
glUniform1f(gScaleLocation, sinf(Scale));
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
Rather than putting the animation logic into the Triangle class, move it to the caller. So first extract the scaling factor as a parameter:
void Triangle::Draw(double scale)
{
glUseProgram(ProgramID);
glBindVertexArray(VBO);
glUniform1f(gScaleLocation, scale);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
Next call Draw with different parameters on different triangle instances:
// your triangles. I assume you have two instances based on the little code you provided.
Triangle tri0, tri1;
// add this to some context, initialized to 0
int frame;
// Your rendering function, you didn't post it.
void render()
{
tri0.Draw(1); // triangle 0 is not animating
tri1.Draw(sin(frame*0.01)); // triangle 1 follows a sine wave
frame++;
}

glDrawArrays doesn't draw

I use vectors to store vertex and normal data
vector<float> vertex;
vector<float> normal;
For example:
normal.push_back(-1);
normal.push_back(0);
normal.push_back(0);
vertex.push_back(BARRIER_RADIUS);
vertex.push_back(POLE_HEIGHT);
vertex.push_back(-POLE_RADIUS);
for (int i = POLE_POINTS, i >= 0; i--)
{
//add more vertex
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertex[0]);
glNormalPointer(GL_FLOAT, 0, &normal[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, vertex.size());
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
//Add some more + Draw some thing else the same way
What I've got from this is nothing. it doesn't draw anything onto the screen.
The previous version, which works, is as follow:
glNormal3f(-1, 0, 0);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(BARRIER_RADIUS, POLE_HEIGHT, -POLE_RADIUS);
for ()
{
//add more vertex
glVertex3f(........);
}
glEnd();
//draw more the same way
Point me to where I've gone wrong.
You have defined vertex as a vector of float, but a geometric vertex consists of 3 floats, so that's a recipe for confusion. The number of vertices is not vertex.size(), but rather one third of that. I'm not sure if that's your only problem, but it's a problem.
You should have the same number of normals as vertices.