Currently I have following setup which is working fine for far.
struct Vertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoord;
}
std::vector<Vertex> vertices;
The Vertex-Attributes:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::texCoord));
Now I want to increase my performance by changing the vertex attributes to from float to short.
I tried to start with the vertex positions.
OpenGL's Vertex Specification Best Practices tells me this:
Positions [...]
To do this, you rearrange your model space data so that all positions are packed in a [-1, 1] box around the origin. You do that by finding the min/max values in XYZ among all positions. Then you subtract the center point of the min/max box from all vertex positions; followed by scaling all of the positions by half the width/height/depth of the min/max box. You need to keep the center point and scaling factors around.
When you build your model-to-view matrix (or model-to-whatever matrix), you need to apply the center point offset and scale at the top of the transform stack (so at the end, right before you draw).
I also read this Thread.
That's why I added this preprocessing step mapping all vertices to [-1,1]
for (auto& v : vertices) {
v.position = (v.position - center) * halfAxisLengths;
}
and recale it in the vertex-shader
vec4 rescaledPos = vec4(in_pos, 1.0) * vec4(halfAxisLengths, 1.0) + vec4(center, 0.0);
gl_Position = P * V * M * rescaledPos;
My vertex attribute using GL_SHORT instead of GL_FLOAT, and normalize set to GL_TRUE:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_SHORT, GL_TRUE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position));
As result I just get a chaos of triangles, but not my model with increased fps.
Is this the correct way to set vertex attributes to short?
Or do I have to change my complete Vertex structure?
If yes, what's the best way to do this (glm vectors with shorts?).
An working example would be great, I couldn't find any.
I adjusted the data structure for the vertex buffer:
struct newVertex {
GLshort position[4]; // for GL_SHORT
GLint normal; // for GL_INT_2_10_10_10_REV
GLshort texCoord[2]; // for GL_SHORT
};
As a result I get ~20% increased performance.
Or do I have to change my complete Vertex structure?
Yes, OpenGL will not magically do the conversion for you. But then if performance is your goal…
Now I want to increase my performance by changing the vertex attributes to from float to short.
This would actually hurt performance. GPUs are optimized for processing vectors as floating point values. This in turn influences the memory interface, which is designed to give best performance for 32 bit aligned accesses. Bysubmitting as 16 bit short integer you're forcing the current line of GPUs to perform suboptimal memory access and an intermediary conversion step.
If performance is your goal stick to single precision float. If you don't believe me: Benchmark it.
Related
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);
}
I am trying to do some simple graphics processing with OpenGL, but I am having trouble having 2 objects where one of them is static and the other moves. The objects are a simple cube and a square that represents the floor. I want the cube to move down until it touches the floor (as if it were moving). I can render the falling cube on its own, and I can get the floor on its own. But when I want to have them both in the same scene I am having issues as they either both fall down (the cubes behaviour), or both stay in the same place (the floors behaviour). Which one of these two options occurs is due to whether I push and pop my model matrix - when I do pop and push, they stay static, when I don't, they fall down (I guess this makes sense as I draw the floor then the cube.
This is my code in the draw phase of the program:
//Clear the screen to the colour specified earlier, as well as the depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID); // Use our shader
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
//RENDER THE FLOOR
pushMat(Model); //PUSH - WHEN ACTIVE, CUBE AND FLOOR FALL. WHEN COMMENTED OUT, BOTH FLOOR AND CUBE ARE STATIC
MVP = Projection * View * Model; //These are all matrices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, floorVertexBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//FLOOR COLOURS
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer2);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, 2*3); //2 triangles, of 3 vertices each
Model = popMat(); //POP - WHEN ACTIVE, CUBE AND FLOOR FALL. WHEN COMMENTED OUT, BOTH FLOOR AND CUBE ARE STATIC
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//RENDER THE CUBE
pushMat(Model); //PUSH - WHEN ACTIVE, CUBE AND FLOOR FALL. WHEN COMMENTED OUT, BOTH FLOOR AND CUBE ARE STATIC
Model = translate(Model, vec3(0.0f, deltaY, 0.0f)); //deltaY is the change in the y position of the cube, it is calculated earlier in this draw loop
MVP = Projection * View * Model;
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, cubeVertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//CUBE COLOURS
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//DRAW CUBE
glDrawArrays(GL_TRIANGLES, 0, 12 * 3); //12 triangle, of 3 vertices each
Model = popMat(); //FINAL POP - WHEN ACTIVE, CUBE AND FLOOR FALL. WHEN COMMENTED OUT, BOTH FLOOR AND CUBE ARE STATIC
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
Code for my push and pop functions:
stack<mat4> modelViewStack; //This is initialised with the identity matrix in the main function
void pushMat(mat4 m)
{
modelViewStack.push(m);
}
mat4 popMat()
{
mat4 temp = modelViewStack.top();
modelViewStack.pop();
return temp;
}
Any clues as to how I get it so the floor stays in one place and the cube moves down? I'm happy to help explain any code, provide more of my code, or answer any questions in general. Thanks for any help.
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
This call needs to appear before each call to glDrawArrays. Right now, it's only being called once, before you render everything, which means both objects are receiving the same MVP matrix.
Also, I would reconsider the logic of implementing this logic using a Matrix Stack. That was how it worked in Legacy OpenGL (because everything depended on Global State, and some other reasons) but it's not obvious that this is the best solution today, when we can simply associate Matrices with individual objects and simply bind them as needed.
I have a piece of OpenGL code that renders meshes. I use VBOs to render them. Now, meshes consist of vertices that have the following attributes:
glm::vec3 position;
glm::vec2 uv;
glm::vec4 color;
glm::vec3 normal;
glm::vec3 tangent;
glm::vec3 binormal;
Currently, I render the vertices on per-vertex basis like this:
// Upload a vector of vertices
glBindBuffer(GL_ARRAY_BUFFER, &m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex), &m_vertices[0], GL_STATIC_DRAW);
// Set the "layout" of the vertex attributes
// Binormal
glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) * 3 + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Tangent
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) * 2 + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Normal
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Color
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) + sizeof(glm::vec2)));
// UV
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3)));
// Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) 0);
// Draw
glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_SHORT, 0);
Now, I've seen people do it a bit differently. Some upload all the vertex positions first, then the UV data, then normals and so on. To do a rough visualization of the data layout:
// P = position, U = uv, N = normal
// Per-vertex layout
PUNPUNPUNPUNPUNPUNPUNPUNPUNPUNPUNPUN
// Per-attribute layout
PPPPPPPPPPPPUUUUUUUUUUUUNNNNNNNNNNNN
Is there any difference between these two layouts? Is one or the other causing any performance issues, especially if data gets updated constantly?
The first layout you're describing is typically called "interleaved", and is mostly considered advantageous. The reasoning is that it results in more local memory access patterns, which are more cache friendly.
One good reason to use a different layout would be if some of the attributes are updated much more frequently than others. In the extreme case, where some of them are static, while others are updated frequently, it might actually be beneficial to keep the static attributes in one VBO, with GL_STATIC_DRAW usage, and use a separate buffer with GL_DYNAMIC_DRAW usage for the attributes that change frequently.
#leemes brings up another interesting case in a comment above: If you often use only a subset of the attributes for draw calls, it might also be worth grouping them differently. In that case, you could have the attributes that are always used in an interleaved layout, and keep the more rarely used ones separate.
With all that said, you will often have bigger bottlenecks in your rendering pipeline, so the difference might be difficult to measure outside targeted synthetic benchmarks. Still, I think it's mostly worth it to keep everything as streamlined as possible. Particularly since most computers/devices run on battery power these days, where you don't want to waste anything.
I'm trying to send a color attribute to my GLSL shader.
The colors are stored in a tightly packed byte array with 3 consecutive bytes making up an RGB triplet.
The shader expects a vec3 so I call glVertexAttribPointer to send normalized float values to the shader.
glBindBuffer(GL_ARRAY_BUFFER, attributeBuffers[COLOR]);
glBufferData(GL_ARRAY_BUFFER, mesh.n_vertices() * 3 * sizeof(GLubyte), color, GL_STATIC_DRAW);
// a little later
glEnableVertexAttribArray(attributes[COLOR]);
glBindBuffer(GL_ARRAY_BUFFER, attributeBuffers[COLOR]);
glVertexAttribPointer(attributes[COLOR], 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
What happens is that:
The colors don't seem to arrive in the shader, the vertices are colored in a single green color
The application takes a massive performance hit
When I manually normalize the color values, copy them to a float array and send that to OpenGL it renders without any problem:
glBindBuffer(GL_ARRAY_BUFFER, attributeBuffers[COLOR]);
glBufferData(GL_ARRAY_BUFFER, mesh.n_vertices() * 3 * sizeof(GLfloat), colorf, GL_STATIC_DRAW);
// a little later
glEnableVertexAttribArray(attributes[COLOR]);
glBindBuffer(GL_ARRAY_BUFFER, attributeBuffers[COLOR]);
glVertexAttribPointer(attributes[COLOR], 3, GL_FLOAT, GL_FALSE, 0, 0);
I tested this on an AMD graphics card with an OpenGL 3.0 context.
Why is this happening? Am I missing something?
As per Bahbar's suggestion I am now aligning the color triplets to 32-bits and it works flawlessly. Colors arrive correctly in the shader and there is no performance hit at all.
I have a model with for which all matdexs (read matrix index) are either 0, 1, and 2 roughly evenly distributed. bonebends[matdex[whichvertex]] tells us which matrix should be used on this vertex.
initializing, c++:
std::vector< GLint > matdex; //initialized to 0, 1, or 2 for each vertex loaded, not shown for brevity
std::vector<glm::mat4> bonebends;
int frames=0;
bonebends.push_back(glm::mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)); //identity matrices initially
bonebends.push_back(glm::mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1));
bonebends.push_back(glm::mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)); // thats 3 bones
ver_ind = glGetAttribLocation(shaderID, "VER_IND");
boneID = glGetUniformLocation(shaderID, "BONE_MATRIX[0]");
glGenBuffers(1, &ind_buff);
glBindBuffer(GL_ARRAY_BUFFER, ind_buff);
glBufferData(GL_ARRAY_BUFFER, matdex.size() * sizeof(GLint), &matdex[0], GL_STATIC_DRAW);
periodically in main loop, c++:
glEnableVertexAttribArray(3); //IND
glBindBuffer(GL_ARRAY_BUFFER, ind_buff);
glVertexAttribPointer( ver_ind, 1, GL_INT, GL_FALSE, 0, (void*)0 );
//ALSO LOOK HERE
glUniformMatrix4fv(boneID, 3 , GL_FALSE, &bonebends[0][0][0]);
frames+=1;
float cs=cos(3.14*2.0*(frames/100.0));
float sn=sin(3.14*2.0*(frames/100.0));
// LOOK HERE
bonebends[0]=glm::mat4(
cs , 0,-sn,0 ,
0 , 1, 0,0 ,
sn, 0, cs,0 ,
0 , 0, 0,1 );
in the shader, glsl:
layout(location = 3) in int VER_IND;
uniform mat4 BONE_MATRIX[3];
in the main function of shader, glsl:
gl_Position = BONE_MATRIX[VER_IND] * vec4(VER_POS,1); //VER_POS is the vertex's coordinates
I hoped this would make all the vertices with a coinciding matdex of 0 to rotate, and the rest remain stationary. Instead this displays the model (which is otherwise rendered correctly) spinning, as if all matdexs values are equal to 0. Which a little couting tells me they are not. I don't know how to debug VER_IND in the shader. I tried
using uint instead of int for all incarnations of matdex, which didn't make a difference.
Changing BONE_MATRIX[VER_IND] to BONE_MATRIX[0] in shader, which made it crash(???)
Changing the second and fourth argument of glUniformMatrix4fv(boneID, 3 , GL_FALSE, &bonebends[0][0][0]); in various ways, didn't help.
changed matdexs values such that none of them were 0, and it still rotates as if the shader is only using BONE_MATRIX[0].
Changing the line below // LOOK HERE to bonebends[1]=glm::mat4( results in the model not spinning at all.
From this I concluded that its only ever using the first of BONE_MATRIX[3], probably because the shader isn't receiving it correctly. I can post the whole thing but its a bit lengthy. I would like to know what I am doing wrong and how to get information back from the shader.
There are a lot of problems.
First, matdex is empty. So you're not getting any actual information.
Second,
layout(location = 3) in int VER_IND;
glVertexAttribPointer( ver_ind, 1, GL_INT, GL_FALSE, 0, (void*)0 );
These two things cannot work together. glVertexAttribPointer can only feed floating-point inputs. If you use integer formats like GL_INT, they will be converted to floats. If you want to feed integer inputs, you must use glVertexAttribIPointer (note the I).
Or just make VER_IND a float. And pass GLubytes instead of GLints. Really, there's no point in taking up all of that memory.
Third:
glEnableVertexAttribArray(3); //IND
glVertexAttribPointer( ver_ind, 1, GL_INT, GL_FALSE, 0, (void*)0 );
The first parameter of both of these functions should be the same, if you're trying to enable ver_ind.
Fourth:
//ALSO LOOK HERE
glUniformMatrix4fv(boneID, 3 , GL_FALSE, &bonebends[0][0][0]);
I don't see where you use glUseProgram to set the program you wanted to change the uniform data on.
Fifth:
// LOOK HERE
bonebends[0]=glm::mat4(
Changing a value after you have uploaded it does not magically cause the uploaded value to change.
There may be (and likely are) more problems, but the code you posted is incomplete and I don't intend to be your personal debugger. At the very least, start with code that you know works, then make the smallest change leading towards what you want. Get that working, then make another change. And so on. You did a bunch of stuff all at once, and it didn't work out.