Drawing a mix of quads and triangles using the geometry shader and lines_adjacency - opengl

My current rendering implementation is as follows:
Store all vertex information as quads rather than triangles
For triangles, simply repeat the last vertex (i.e. v0 v1 v2 v2)
Pass vertex information as lines_adjacency to geometry shader
Check if quad or triangle, output as triangle_strip
The reason I went this route was because I was implementing a wireframe shader, and I wanted to draw the quads without a diagonal line through them. But, I've since discarded the feature.
I'm now wondering if I should go back to simply drawing GL_TRIANGLES, and leave the geometry shader out of the equation. But that got me thinking... what's actually more efficient from a performance point of view?
In average, my scenes are composed of quads and triangles in equal amounts.
Drawing with all triangles would mean: 6 vertices per quad, 3 per triangle.
Drawing with lines_adjacency would mean: 4 vertices per quad, 4 per triangle.
(This is with indexed drawing, so the vertex buffer is the same size for both of them)
So the vertex ratio is 9:8 (triangles : lines_adjacency).
Would I be correct in assuming that with indexed drawing, each vertex is only getting processed once by the vertex shader (as opposed to once per index)? In which case drawing triangles is going to be more efficient (since there isn't an extra geometry-shader step to perform), with the only negative being the slight amount of extra memory the indices take up.
Then again, if the vertices do get processed once per index, I could see the edge being with the lines_adjacency method, considering the geometry conversion is very simple, whilst the vertex shader might be running more intensive lighting calculations.
So that pretty much sums up my question: how do vertices get treated with indexed drawing, and what sort of performance impact could be expected if including a simple geometry shader?

Geometry shaders never improve efficiency in this sort of situation, they only complicate the primitive assembly process. When you use geometry shaders, the post-T&L cache no longer works the way it was originally designed.
While it is true that the geometry shader will reuse any shared (indexed) vertices transformed in the vertex shader stage when it needs to fetch vertex data, the geometry shader still computes and emits a unique set of vertices per-output-primitive.
Furthermore, because geometry shaders are allowed to emit a variable number of data points they are unlike other shader stages. It is much more difficult to parallelize geometry shaders than it is vertex or fragment. There are just too many negative things about geometry shaders for me to suggest using them unless you actually need them.

Related

Optimize operation between fragment and vertex shader

I am learning to make a graphical engine with OpenGL. I wanted to know, should repetitive operations be moved from the vertex shader to the fragment shader, since from what I understood the vertex shader is only run once per vertex?
For instance, when normalizing a vector for the light direction, since this light is the same in the entire vertex should it be moved to the vertex shader, instead of calculating it for every pixel? Is there a particular reason to keep it in the fragment shader?
If the calculation is exactly the same: yes, it should usually be more efficient to do it in the vertex shader than the fragment shader. Some situations where it might not be more efficient:
when drawing geometry that results in fewer shaded pixels than transformable vertices -- either due to dense geometry or extreme discards/occlusion. If this is the case, usually you would want to address it by switching to lower level-of-detail geometry or smarter geometry culling.
when doing the calculation in the vertex shader requires you to send more data to the fragment shader in order to use the calculation's results. Sending more data can be slower because it requires more memory manipulation and because the rasterizer needs to interpolate more "varying" values across each polygon.
For light calculations, specifically, be mindful that moving calculations from the fragment shader to the vertex shader can affect the quality of your rendering. Particularly, normalized direction vectors at each vertex can become shorter after "varying" interpolation, which can slightly darken triangle interiors if used directly without renormalization. And, of course, moving the entire lighting calculation to the vertex shader has even more drastic effects.
But how visible these effects are depends on the frequency of textures, the resolution of geometry, the size on screen, how far away the lights are, etc. -- in some cases, the quality/performance tradeoff may make sense.

Approach for writing a GLSL fragment shader with a solid color per triangle/face

I have vertex and triangle data which contains a color for each triangle (face), not for each vertex. i.e. A single vertex is shared by multiple faces, each face potentially a different color.
How should I approach this problem in GLSL to obtain a solid color assignment for each face being rendered? Calculating and assigning a "vertex color" buffer by averaging the colors of a vertex's neighboring polys is easy enough, but this of course produces a blurry result where the colors are interpolated in the fragment shader.
What I really need shouldn't be interpolated color values at all, I'll have about 40k triangles shaded with approx 15 possible solid colors once this is working as intended.
While you maybe could do this in high end GLSL, the right way to do solid shading is to make unique vertices for every triangle. This is a trivial loop. For every vertex, count how many triangles share it. That's how often you have to replicate it. Make sure your loop to do this is O(n). Then just set each vertex color or normal to that of the triangle. Again one straight loop. Do not bother to optimize for shared colors, it is not worth it.
Edit much later, because this is a popular answer:
To do flat per face shading you can interpolate the vertex position in world or view space. Then in the fragment shader compute ddx(dFdx) and ddy(dFdy) of this variable. Take the cross product of those two vectors and normalize it - you got a flat normal! No mesh changes or per vertex data needed at all.
OpenGL does not have "per-face" attributes. See:
How can I specify per-face colors when using indexed vertex arrays in OpenGL 3.x?
Here are a few possible options I see:
Ditch the index arrays and use separate vertices for each face like starmole suggested
Create an index array for each color used. Use materials instead of vertex colors and change the material after drawing the triangles from the index array for each color.
If the geometry allows it, you can make sure the last vertex specified by the index array has the correct vertex color for the face, and then use GL_FLAT shading, or have the fragment shader only use at the last vertex color.
In addition to the other answers, you could maybe employ the gl_PrimitiveID variable, that's an input to the fragment shader (don't know since which version) and is incremented implicitly for each triangle. You could then use this to lookup the color (either from a 40k buffer texture of colors or color indices into a 15 color color map, or just some direct computation from the primitive id). But don't ask me about the performance of this approach.

GLSL Geometry Shaders and projection matrices

So from playing around with it so far, I gather that GLSL geometry shaders work after the input vertices are transformed by the projection/modelview matrices. In other words, the geometry shaders processes things on clip coordinate.
What if I was to use the geometry shader to transform GL_POINTS into, say, cubes made out of GL_TRIANGLES? When calculating things on clip coordinates, the resulting shape always seem to face you / ignore rotations/scaling etc.
Also, it seems that GL_TRIANGLES is not supported as one of the possible geometry output types. But I tried anyways, and it seems to work. I suppose this is video card dependent? Is it possible to make cubes if GL_TRIANGLES is not supported? Make zero width triangle strips in between spaces maybe??
You are using shaders: geometry shaders work on whatever the vertex shader passed them. If you want that to be clip-space values, then the geometry shader works on clip-space values. If your vertex shader passes them eye-space values, then the geometry shader must work on eye-space values.
What matters is what the final pre-rasterization shader stage outputs to gl_Position. That is what needs to be in homogeneous clip-space. A vertex shader that has a geometry shader behind it doesn't even need to write to gl_Position.
Also, it seems that GL_TRIANGLES is not supported as one of the possible geometry output types.
You must be using ARB_geometry_shader4, not the actual core geometry shader functionality. You probably should avoid that extension if you are able. Any hardware that has geometry shaders can run OpenGL 3.2.
In any case, the core feature doesn't support triangles as output. It supports points, line strips, and triangle strips.
Is it possible to make cubes if GL_TRIANGLES is not supported?
That's what EndPrimitive() is for. You call it when you are finished with a primitive; there's nothing that stops you from emitting a second primitive. Or third.
Also, you should be advised that this will probably be slow. Geometry shaders are not known for fast rendering performance.

Vertex shader vs Fragment Shader [duplicate]

This question already has answers here:
What are Vertex and Pixel shaders?
(6 answers)
Closed 5 years ago.
I've read some tutorials regarding Cg, yet one thing is not quite clear to me.
What exactly is the difference between vertex and fragment shaders?
And for what situations is one better suited than the other?
A fragment shader is the same as pixel shader.
One main difference is that a vertex shader can manipulate the attributes of vertices. which are the corner points of your polygons.
The fragment shader on the other hand takes care of how the pixels between the vertices look. They are interpolated between the defined vertices following specific rules.
For example: if you want your polygon to be completely red, you would define all vertices red. If you want for specific effects like a gradient between the vertices, you have to do that in the fragment shader.
Put another way:
The vertex shader is part of the early steps in the graphic pipeline, somewhere between model coordinate transformation and polygon clipping I think. At that point, nothing is really done yet.
However, the fragment/pixel shader is part of the rasterization step, where the image is calculated and the pixels between the vertices are filled in or "coloured".
Just read about the graphics pipeline here and everything will reveal itself:
http://en.wikipedia.org/wiki/Graphics_pipeline
Vertex shader is done on every vertex, while fragment shader is done on every pixel. The fragment shader is applied after vertex shader. More about the shaders GPU pipeline link text
Nvidia Cg Tutorial:
Vertex transformation is the first processing stage in the graphics hardware pipeline. Vertex transformation performs a sequence of math operations on each vertex. These operations include transforming the vertex position into a screen position for use by the rasterizer, generating texture coordinates for texturing, and lighting the vertex to determine its color.
The results of rasterization are a set of pixel locations as well as a set of fragments. There is no relationship between the number of vertices a primitive has and the number of fragments that are generated when it is rasterized. For example, a triangle made up of just three vertices could take up the entire screen, and therefore generate millions of fragments!
Earlier, we told you to think of a fragment as a pixel if you did not know precisely what a fragment was. At this point, however, the distinction between a fragment and a pixel becomes important. The term pixel is short for "picture element." A pixel represents the contents of the frame buffer at a specific location, such as the color, depth, and any other values associated with that location. A fragment is the state required potentially to update a particular pixel.
The term "fragment" is used because rasterization breaks up each geometric primitive, such as a triangle, into pixel-sized fragments for each pixel that the primitive covers. A fragment has an associated pixel location, a depth value, and a set of interpolated parameters such as a color, a secondary (specular) color, and one or more texture coordinate sets. These various interpolated parameters are derived from the transformed vertices that make up the particular geometric primitive used to generate the fragments. You can think of a fragment as a "potential pixel." If a fragment passes the various rasterization tests (in the raster operations stage, which is described shortly), the fragment updates a pixel in the frame buffer.
Vertex Shaders and Fragment Shaders are both feature of 3-D implementation that does not uses fixed-pipeline rendering. In any 3-D rendering vertex shaders are applied before fragment/pixel shaders.
Vertex shader operates on each vertex. If you have a fixed polygon mesh and you want to deform it in a shader, you have to implement it in vertex shader. I.e. any physical change in vertex appearances can be done in vertex shaders.
Fragment shader takes the output from the vertex shader and associates colors, depth value of a pixel, etc. After these operations the fragment is send to Framebuffer for display on the screen.
Some operation, as for example lighting calculation, you can perform in vertex shader as well as fragment shader. But fragment shader provides better result than the vertex shader.
In rendering images via 3D hardware you typically have a mesh (point, polygons, lines) these are defined by vertices. To manipulate vertices individually typically for motions in a model or waves in an ocean you can use vertex shaders. These vertices can have static colour or colour assigned by textures, to manipulate vertex colours you use fragment shaders. At the end of the pipeline when the view goes to screen you can also use fragment shaders.

Can I use a vertex shader to display a models normals?

I'm currently using a VBO for the texture coordinates, normals and the vertices of a (3DS) model I'm drawing with "glDrawArrays(GL_TRIANGLES, ...);". For debugging I want to (temporarily) show the normals when drawing my model. Do I have to use immediate mode to draw each line from vert to vert+normal -OR- stuff another VBO with vert and vert+normal to draw all the normals… -OR- is there a way for the vertex shader to use the vertex and normal data already passed in when drawing the model to compute the V+N used when drawing the normals?
No, it is not possible to draw additional lines from a vertex shader.
A vertex shader is not about creating geometry, it is about doing per vertex computation. Using vertex shaders, when you say glDrawArrays(GL_TRIANGLES,0,3), this is what specifies exactly what you will draw, i.e. 1 triangle. Once processing reaches the vertex shader, you can only alter the properties of the vertices of that triangle, not modify in any way, shape or form, the topology and/or count of the geometry.
What you're looking for is what OpenGL 3.2 defines as a geometry shader, that allows to output arbitrary geometry count/topology out of a shader. Note however that this is only supported through OpenGL 3.2, that not many cards/drivers support right now (it's been out for a few months now).
However, I must point out that showing normals (in most engines that support some kind of debugging) is usually done with the traditional line rendering, with an additional vertex buffer that gets filled in with the proper positions (P, P+C*N) for each mesh position, where C is a constant that represents the length you want to use to show the normals. It is not that complex to write...
You could approximate this by drawing the geometry twice. Once draw it as you normally would. The second time, draw the geometry as GL_POINTS, and attach a vertex shader which offsets each vertex position by the vertex normal.
This would result in your model having a set of points floating over the surface. Each point would show the direction of the normal from the vertex it corresponds to.
This isn't perfect, but might be sufficient, depending on what it is you're hoping to use it for.
UPDATE: AHA! And if you pass in a constant scaling factor to the vertex shader, and have your application interpolate that factor between 0 and 1 as time goes by, your points rendered by the vertex shader will animate over time, starting at the vertex they apply to, and then floating off in the direction of its normal.
It's probably possible to get more or less the right effect with a cleverly written vertex shader, but it'd be a lot of work. Since this is for debugging purposes anyway, it seems better to just draw a few lines; the performance hit will not be severe.