VBO colors of vertices using shaders - opengl

I am displaying a geometry (file format: .stl) with OpenGL (PyOpenGL and Python). Geometry data has the form and is assembled from triangles.
I save to VBO data of; vertices, normals and colors. As the normal is only defined per 3 vertices (triangle) and I define color vector for every vertex, the data in VBO has the form:
VBO = [v1x, v1y, v1z,...vNx, vNy, vNz,
n1x, n1y, n1z,...nNx, nNy, nNz,
R1, G1, B1,...RN, GN, BN]
In words; first I save all vertices, then I "append" (use of glBufferSubData) all normals (number of normals is 3-times less then number of vertices and vertice's colors) and then I append color vectors of each vertex (use of glBufferSubData).
I would like to know if this is good idea, as I have problems painting each vertex in different color. The code for drawing is:
glPushMatrix()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3,
GL_FLOAT,
0,
None)
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3,
GL_UNSIGNED_BYTE,
0,
self.data_size_vertices+self.data_size_normals)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vbo_id)
glDrawArrays(GL_TRIANGLES,
0,
self.N_vertices)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) # reset
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
glPopMatrix()
I think I am having problems with glColorPointer(). Can someone point out the problem? I have also seen two more ways to save the data to VBO:
create separate VBO for vertices, VBO for normals and VBO for colors
one VBO but has the form: [v1, c1, v2, c2, v3, c3, n1, ....]
Is any of this two a better solution (more common in practice)? And do I have to assign a normal of triangle to each vertex although it is the same (for 3 vertices that define a triangle)? As I would like to get the display as shown below (left: current state, middle: plan, right: ideal - the point is the shading of surfaces), I would like to ask you to give me some directions about how to achieve this (using shaders).

You will have to duplicate the normal for each vertex. For OpenGL, a vertex is a set of attributes (like position, color, normal, texcoords, ...). A vertex is referenced by its index, so the i-th vertex will be composed of the i-th element of all enabled attribute arrays.
A common layout for vertex attributes is to interleave the attribs per vertex, like
v1x, v1y, v1z, n1x, n1y, n1z, R1, G1, B1, v2x, ...
That way, all data which is fetched for processing a single is local close to each other, increasing cache efficiency. You can use the stride parameter of the attrib pointers to set it up for such a layout.
The "current state" image looks to me like it should look when no normal array is enabled (and lighting still is enabled). The GL will then reuse the currently set normal vector for all vertices, resulting in the shading you see. Looking at the "ideal" image, I would conclude that the blue color is correct for the object, so I do not see what is wrong with your color array.

Related

How does OpenGL know how to use the normal data with glDrawElements()?

I spent days to construct a working example of rendering a cube in OpenGL with simple lighting
I have:
vertices = {...};
normals = {...};
vertex_indices = {...};
normal_indices = {...};
(1) I setup my VBOs
glBufferSubData(GL_ARRAY_BUFFER, 0, vertSize, &vertices[0]); // vertices
glBufferSubData(GL_ARRAY_BUFFER, vertSize, normSize, &normals[0]); // normals
(2) I enable my vertex pointers
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,..)
glEnableVertexAttribArray(1);
glVertexAttribPointer(1,..)
(3) I also setup my index buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indcSize, & vertex_indices[0], GL_STATIC_DRAW);
and then call glDrawElements in my render method
glDrawElements(GL_TRIANGLES, (int)vertex_indices.size(), GL_UNSIGNED_INT, 0);
I don't pass the normal indices anywhere but everything seems to work fine.
I don't think I understand glDrawElements correctly. How did the lighting work without the normal indices? was glDrawElements suppose to only get the vertex indices?
I don't think I understand glDrawElements correctly. How did the lighting work without the normal indices? was glDrawElements suppose to only get the vertex indices?
In OpenGL, there are no separate indices per attribute. As far as OpenGL is concerned, a vertex is an n-tuple of all attributes, like position, color, normal vector, tex coords, whatever.
In the case of your cube, you will need at least 24 vertices. There are only 8 corner positions, but each corner is connected to 3 different faces, each with a different normal. This means, that you need 3 separate vertices at each corner, all at the same position, but all differing by their normal direction.
Consequently, glDrawElements works with only one index array, and this is the index into all enabled vertex attribute arrays at the same time. Your normal_indices array is not used at all. If it still works as intended, your normal data happens to be organized in the correct way.

Is there a way to create the verts/indices of a cube that can be well represented by line drawing mode as well as render correctly in triangles mode?

Attempting to switch drawing mode to GL_LINE, GL_LINE_STRIP or GL_LINE_LOOP when your cube's vertex data is constructed mainly for use with GL_TRIANGLES presents some interesting results but none that provide a good wireframe representation of the cube.
Is there a way to construct the cube's vertex and index data so that simply toggling the draw mode between GL_LINES/GL_LINE_STRIP/GL_LINE_LOOP and GL_TRIANGLES provides nice results? Or is the only way to get a good wireframe to re-create the vertices specifically for use with one of the line modes?
The most practical approach is most likely the simplest one: Use separate index arrays for line and triangle rendering. There is certainly no need to replicate the vertex attributes, but drawing entirely different primitive types with the same indices sounds highly problematic.
To implement this, you could use two different index (GL_ELEMENT_ARRAY_BUFFER) buffers. Or, more elegantly IMHO, use a single buffer, and store both sets of indices in it. Say you need triIdxCount indices for triangle rendering, and lineIdxCount for line rendering. You can then set up you index buffer with:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(triIdxCount + lineIdxCount) * sizeof(GLushort), 0,
GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
0, triIdxCount * sizeof(GLushort), triIdxArray);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
triIdxCount * sizeof(GLushort), lineIdxCount * sizeof(GLushort),
lineIdxArray);
Then, when you're ready to draw, set up all your state, including the index buffer binding (ideally using a VAO for all of the state setup) and then render conditionally:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
if (renderTri) {
glDrawElements(GL_TRIANGLES, triIndexCount, GL_UNSIGNED_SHORT, 0);
} else {
glDrawElements(GL_LINES, lineIdxCount, GL_UNSIGNED_SHORT,
triIndexCount * sizeof(GLushort));
}
From a memory usage point of view, having two sets of indices is a moderate amount of overhead. The actual vertex attribute data is normally much bigger than the index data, and the key point here is that the attribute data is not replicated.
If you don't strictly want to render lines, but just have a requirement for wireframe types of rendering, there are other options. There is for example an elegant approach (never implemented it myself, but it looks clever) where you only draw pixels close to the boundary of polygons, and discard the interior pixels in the fragment shader based on the distance to the polygon edge. This question (where I contributed an answer) elaborates on the approach: Wireframe shader - Issue with Barycentric coordinates when using shared vertices.

OpenGL avoid calling glDrawElements multiple times

I'm migrating our graphics ending from using the old fixed pipeline functions to making use of the programmable pipeline. Our simplest model is just a collection of points in space where each point can be represented by different shapes. One of these being a cube.
I'm basing my code off the cube example from the OpenGL superbible.
In this example the cubes are placed at somewhat random places whereas I will have a fixed lit of points in space. I'm wondering if there is a way to pass that list to my shader so that a cube is drawn at each point vs looping through the list and calling glDrawElements each time. Is that even worth the trouble (performance wise)?
PS we are limited to OpenGL 3.3 functionality.
Is that even worth the trouble (performance wise)?
Probably yes, but try to profile nonetheless.
What you are looking for is instanced rendering, take a look at glDrawElementsInstanced and glVertexAttribDivisor.
What you want to do is store the 8 vertices of a generic cube (centered on the origin) in one buffer, and also store the coordinates of the center of each cube in another vertex attribute buffer.
Then you can use glDrawElementsInstanced to draw N cubes taking the vertices from the first buffer, and translating them in the shader using the specific position stored in the second buffer.
Something like this:
glVertexAttribPointer( vertexPositionIndex, /** Blah .. */ );
glVertexAttribPointer( cubePositionIndex, /** Blah .. */ );
glVertexAttribDivisor( cubePositionIndex, 1 ); // Advance one vertex attribute per instance
glDrawElementsInstanced( GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices, NumberOfCubes );
In your vertex shader you need two attributes:
vec3 vertexPosition; // The coordinates of a vertex of the generic cube
vec3 cubePosition; // The coordinates of the center the specific cube being rendered
// ....
vec3 vertex = vertexPosition + cubePosition;
Obviously you can have also a buffer to store the size of each cube, or another one for the orientation, the idea remains the same.
In your example every cube uses its own model matrix per frame.
If you want to keep that you need multiple drawElements calls.
If some cubes don't move (don't need a per frame model matrix) you should combine these cubes into one VBO.

Post GPU scaling colouring in OpenGL without shaders

I am writing a program to plot the distribution of a stream of live noisy data. The plots look something like
The scene is lit with 3 lights - 2 diffuse and 1 ambient - to allow modeling to be revealed once filtering is applied to the data
Currently vertical scaling and vertex colour assignment is done by my code before sending the vertices to the GPU using:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(c_vertex), &(vertex_store[0][0].x));
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, sizeof(c_vertex),&(vertex_store[0][0].r));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(c_vertex),&(vertex_store[0][0].nx));
glDrawElements(GL_TRIANGLES, (max_bins-1)*(max_bins-1)*2*3, GL_UNSIGNED_INT, vertex_order);
The use of older functions is so that I can let the fixed pipeline do the lighting calculations with out me writing a shader [something I have not done to the depth needed to do lighting with 3 sources]
To speed up processing I would like to send unscaled data to the GPU and apply a matrix with X and Z scale of 1 and Y scale of the appropriate value to make the peaks reach to +1 on the y axis. After this I would then like the GPU to select the colour for the vertex depending on its post scaling Y value from a look-up table which I assume would be a texture map.
Now I know I can do the last paragraph IF I write my own shaders - but that the necessitates writing code for lighting which I want to avoid doing. Is there anyway of doing this using the buffers in the drawing code above?
After
this I would then like the GPU to select the colour for the vertex
depending on its post scaling Y value from a look-up table which I
assume would be a texture map.
You really should write your own shaders for that. Writing a shader for 3 light sources isn't more complicated as writing one for just one and making a loop around it.
However, I think what you asked for could still be done with the fixed function pipeline. You can use a 1D texture for the colors, enable texturing and the automatic texture coordinate generation, the latter via the glTexGen() family of functions.
In your specific case, the best appraoch seems to set up a GL_OBJECT_LINEAR mapping for s (the first and only texture coordinate that you would need for a 1D texture):
glEnable(GL_TEXTURE_GEN_S);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
What the GL now will do is calcualte s as a function of your input vertex cooridnates (x,y,z,w) such that:
s=a*x + b*y + c*z + d*w
where a,b,c and d are just some coefficients you can freely choose. I'm assuming your original vertices just need to be scaled along y direction by a scaling factor V, so you can just set b=V and all other to zero:
GLfloat coeffs[4]={0.0f, V, 0.0f, 0.0f);
glTexGenfv(GL_S, GL_OBJECT_PLANE, coeffs);
Then, you just have to enable texture mapping and provide a texture to get the desired lookat.

Draw rectangle from squares of different colours in Opengl

I have a beamforming program running on CUDA and i have to display the output of the beam in Opengl,I have to draw a rectangle in Opengl which is composed of an array of 24x12 small squares.I have to color each of these squares with a different color based on an output from a CUDA program doing the beamforming. I have been able to draw the reactangle using a VBO to which I pass an array containing the vertices of the squares and the color of each vertices using the following a structure. The overall summary of the problem that I am facing is that I am not able to assign the colors to each of the squares correctly. Some excerpts from the code :
struct attributes {
GLfloat coords[2]; //co-ordinates of the vertices
GLfloat color[3]; //color of the vertices
};
glGenBuffers(1, &vbo_romanis); // vbo_romanis is the VBO for drawing the frame
glBindBuffer(GL_ARRAY_BUFFER, vbo_romanis);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STREAM_DRAW);
glShadeModel (GL_SMOOTH);
glUseProgram(program);
glEnableVertexAttribArray(attribute_coord);
glEnableVertexAttribArray(attribute_color);
glBindBuffer(GL_ARRAY_BUFFER, vbo_romanis);
glVertexAttribPointer(
attribute_coord2d, // attribute
2, // number of elements per vertex, here (x,y)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
sizeof(struct attributes), // next coord2 appears every 5 floats
0 // offset of first element
);
glVertexAttribPointer(
attribute_color, // attribute
3, // number of elements per vertex, here (r,g,b)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
sizeof(struct attributes), // stride
(GLvoid*) offsetof(struct attributes, color) // offset
);
/* Push each element in buffer_vertices to the vertex shader */
glDrawArrays(GL_QUADS, 0, 4*NUM_SQRS);
So I am facing 2 issues when i draw the array:
the colors not appearing as I want them to. From what I have read about Opengl, the color of the vertices once assigned cannot be changed. But since all the squares share vertices among them, the colors are probably messed up. If I give the same color to all the vertices,it works fine, but not when I want to draw all squares of different colors. So, if someone can point to how I can assign a different color to each of the squares that would really helpful.
How do I update the colors of the vertices for each frame, Do i need to redraw the entire frame or is there a way to just update the colors of the vertices only.
I am completely new to OpenGL programming and any help would be much appreciated.
It is not clear what your vertex data actually is, but this:
But since all the squares share vertices among them, the colors are
probably messed up.
implies to me that you are trying to use the following data for two adjacent squares (A-F being the vertices):
A---B---C
| | |
| | |
D---E---F
However, in OpenGL, a vertex is the set of all attributes, not just the postion. What you get here is that the colors will be smoothly interpolated between the squares. So technically, you need to duplicate the vertices B and E into B1/B2 and E1/E2, with B1,E1 beeing the color of the lieft square, and B2,E2 that of the right square, but the same coordiantes.
However, for your problem, there might be a shortcut, in form of flat shading by declaring your vaertex shader outputs as flat. Vertex shader outputs (varyings) are by default interpolated across the whole primitive. However, defining them as flat will prevent the interpolation. Instead, the value from just one vertex is used for the whole primitive. OpenGL uses the conecpt of the provoking vertex to define which vertex of a primitive will be the one defining the values for such flat outputs.
The command glProvokingVertex() might be used to specify the general rules for which vertex is to be selected, you can choose between the first and the last. If you cleverly construct your vertex data, you can get a vertex to be shared for both triangles of one square that will be the provoking vertex for both, so you can define the color for each "grid cell" with just the color of one corner vertex of the cell, and do not have any need for duplicating vertices.
As a side note: you have the commang glShadeModel(GL_SMOOTH); in your code. This is deprecated and also totally useless when you use the programmable pipeline, as your comments imply. However, conceptually, this is the exact opposite of the flat shading approach I'm suggesting here.
How do I update the colors of the vertices for each frame, Do i need
to redraw the entire frame or is there a way to just update the colors
of the vertices only.
OpenGL is not a scene graph library. It does not remember which objects you have drawn in the past and does not allow changing their attributes. OpenGL is a rendering API, so if you want something different to appear on the screen, you have to tell it to draw again. If you plan on updating the colors without changing the positions of the squares itself, you might be even better off using two non-interleaved VBOs to split color and position data. That way, you can have the positions statically in one buffer, and stream only the color updates in another.