Substituting color with vertex attributes - opengl

I have a large set of vertices and currently use glColorPointer to specify their color. The problem is, that glColorPointer only accepts a size of 3 or 4 as its first parameter but the value of R, G and B for each vertex is identical.
Of course, I could use glVertexAttribPointer to specify each color value as an attribute of size one and duplicate it in a shader, but I'm looking for a way to do this in the fixed function pipeline.
Calling glColor1* is unfortunately out of the question given the amount of vertices (Yes, I tried it).
Any creative solution that squeezes the value into something else is also OK.

I think without shaders this won't be possible since, well, glColorPointer only accepts a size of 3 or 4, like you already found out (there should also be no glColor1, only glColor3 and glColor4).
You might trick glColorPointer to use your tightly packed array by specifying a size of 3 but a stride of 1 (ubyte) or 4 (float). But this will give you a color of (Ri, Ri+1, Ri+2) for vertex i and there is no way to adjust it to (Ri, Ri, Ri), since the color matrix is not applied to per-vertex colors but only to pixel images.
So without shaders you don't have much creativity left. What you could do is use a 1D texture of size 256, which contains all the grey colors from (0, 0, 0) to (255, 255, 255) in order. Then you can just use your per-vertex color as 1D texture coordinate into that texture. But I'm not sure if that would really buy you anything in either space or time.
The easy and straightforward way is to use vertex attributes and a shader to implement the unpacking of the attribute into the fragment color. This takes just a few lines of shader code and should be the preferred solution. The real difficulty here is the artificial restriction, not the problem space itself. Such cases should be handled by lifting the restriction.

You can store the color information in an 1D texture (with only one channel), then you can use a vertex shader which reads the proper color based on the gl_vertexID.

Related

OpenGL geometry shader, setting input size

I've written my first geometry shader with success. It takes in lines and outputs a little triangle at the center of each.
I could do the same thing for triangles easily enough, but what about a cube? Is there a way to get a geometry shader to operate on an arbitrary number of points, or at the very least more than 3? I know I could compute the center myself and do another drawing operation, but I'd like to know if it's possible inside the shader.
Thanks.
Geometry shaders take as input a primitive, not a number of vertices. I mean yes, a specific primitive is made of a specific number of vertices. But GS's don't take vertex counts; they take primitives.
There are a number of special primitive types that allow GS's to access more vertices than those in the base primitive type. But these are for referencing vertices adjacent to the main primitive's vertices, and it's difficult to try to make them work as a general mechanism for consuming X vertices.
So you can only use a vertex count that matches a primitive's vertex count: 1, 2, 3, 4, or 6. Outside of these specific vertex counts, you can't make a GS do what you're trying to do.
You can attempt to employ tessellation, as patch vertex counts are user-specified (though limited by the implementation). But tessellation is more restrictive in terms of generating vertices.

Passing Array to Vertex Shader as Attribute

I am doing some LBS, and I need to use more than 4 weights, and indices (Let's say I need 60 float values, and 60 int values).
I am using GLSL version 1.30, so I cannot use Shader Storage Buffer Object. Since this weight, and index information will be different for each vertex, cannot use uniform, and I guess there is no way to define an array with a fixed size (for example float arr[16]) if you are not using uniform. Additionally, for attribute inputs, I can only use vec/mat 2,3 or 4.
So, do you have any idea how I can solve this problem?
A first approach would be to just pass them as normal vertex attributes. There is though a driver specific maximum number of vertex attributes.
A better approach, that should work with every driver and with an arbitrary amount of attributes (not infinite, but pretty many) is, to store the vertex attributes in a texture.
A simple setup would be to create a NxM texture, where N=#vertex_attributes and M=#vertices. Each vertex has then only one attribute, that indicates a line of the texture. In the vertex shader you can then read one line of the texture per vertex and have all your attributes.

Fastest way to draw many textured quads in OpenGL 3+

Since GL_QUADS has been removed from OpenGL 3.1 and above, what is the fastest way to draw lots of quads without using it? I've tried several different methods (below) and have ranked them on speed on my machine, but I was wondering if there is some better way, since the fastest way still seems wasteful and inelegant. I should mention that in each of these methods I'm using VBOs with interleaved vertex and texture coordinates, since I believe that to be best practice (though I may be wrong). Also, I should say that I can't reuse any vertices between separate quads because they will have different texture coordinates.
glDrawElements with GL_TRIANGLE_STRIP using a primitive restart index, so that the index array looks like {0, 1, 2, 3, PRI, 4, 5, 6, 7, PRI, ...}. This takes in the first 4 vertices in my VBO, treats them as a triangle strip to make a rectangle, and then treats the next 4 vertices as a separate strip. The problem here is just that the index array seems like a waste of space. The nice thing about GL_QUADS in earlier versions of OpenGL is that it automatically restarts primitives every 4 vertices. Still, this is the fastest method I can find.
Geometry shader. I pass in 1 vertex for each rectangle and then construct the appropriate triangle strip of 4 vertices in the shader. This seems like it would be the fastest and most elegant, but I've read, and now seen, that geometry shaders are not that efficient compared to passing in redundant data.
glDrawArrays with GL_TRIANGLES. I just draw every triangle independently, reusing no vertices.
glMultiDrawArrays with GL_TRIANGLE_STRIP, an array of all multiples of 4 for the "first" array, and an array of a bunch of 4's for the "count" array. This tells the video card to draw the first 4 starting at 0, then the first 4 starting at 4, and so on. The reason this is so slow, I think, is that you can't put these index arrays in a VBO.
You've covered all the typical good ways, but I'd like to suggest a few less typical ones that I suspect may have higher performance. Based on the wording of the question, I shall assume that you're trying to draw an m*n array of tiles, and they all need different texture coordinates.
A geometry shader is not the right tool to add and remove vertices. It's capable of doing that, but it's really intended for cases when you actually change the number of primitives you're rendering dynamically (e.g. shadow volume generation). If you just want to draw a whole bunch of adjacent different primitives with different texture coordinates, I suspect the absolute fastest way would be to use tessellation shaders. Just pass in a single quad and have the tessellator compute texture coordinates procedurally.
A similar and more portable method would be to look up each quad's texture coordinate. This is trivial: say you're drawing 50x20 quads, you would have a 50x20 texture that stores all your texture coordinates. Tap this texture in your vertex program (or perhaps more efficiently in your geometry program) and send the result in a varying to the fragment program for actual rendering.
Note that in both of the above cases, you can reuse vertices. In the first method, the intermediate vertices are generated on the fly. In the second, the vertices' texture coordinates are replaced in the shader with cached values from the texture.

What color does a fragment get if there are two vertices at the very same position with two different colors?

I have a question concerning the OpenGL rendering pipeline.
I have recently been reading theory about the GLSL's Geometry Shader. I think I do understand the basics of how to emit new geometry and assign colors to the new vertices. I am, however, not sure what color a fragment would get if one of those new vertices would have the very same position as one coming in from the Vertex shader.
Consider this example:
I far as I understand it, I am able to handle a single vertex with the Vertex shader. I make some transformation and store the position in glPosition. It is furthermore possible to assign a color to that vertex, e.g. by storing it to glFrontColor. As an example, I give it the color red. If all channels have 32 bits, that would be 0xFFFFFFFF'00000000'00000000'00000000, right?.
Next, Geometry shader is involved. I want my geometry shader to emit some additional vertices. At least one of them is at the very same position as the original vertex coming in from the Vertex shader. However, it is assigned another color, e.g. green. That would be 0x00000000'FFFFFFFF'00000000'00000000, right?
Sooner or later, after every vertex has been dealt, the rasterization takes place. As I understand, both vertices are rasterized and will therefore become the very same fragment. So, there we go. What color will that particular fragment get? Is there some kind of automatic blending and the fragment becomes yellow? Or is red or rather green?
This question might be silly. But I am simply not clear on that and would appreciate if somebody could clarify that for me.
If there is no blending (which I assume), how could I possibly create a blending effect?
Assuming you're rendering points (which seems to be what you're describing), the two vertices with the different colors will result in two fragments (one for each vertex) at the same location. What final color will be written to the output depends on the Z values for each, the blending function set and the order in which they are processed (which is effectively random -- you can't count on either order unless you do some extra sync stuff, so you need to set your blend func/Z-culling such that it doesn't matter).
I think they will be Z-Fighting, if they have the exact same values for x y and z.
About blending:
This is separate from the programmable pipeline, so you don't have to do most of the work in the shaders for it.
First enable blending with glEnable(GL_BLEND),
then specify your desired blending function with glBlendFunc, most commonly glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
Now the vertices only need an alpha value set at gl_FragColor.a and their color will blend.

OpenGL glColorPointer repeat colors?

Imagine that you've got one of these guys:
(source: codesampler.com)
Aka GL_TRIANGLE_STRIP. If you wanna color it using different colors, you could use:
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorArray);
glEnableClientState(GL_COLOR_ARRAY);
Where each "item" in the color array matches a vertex point in the strip. But what if the colors just alternate between two different colors? Feels unnecessary to define a color for each vertex, if there's only two "real" different colors. So my question is if it's possible to define a colorArray with just two colors in it, and somehow make opengl alternate between those two when it's looping over the vertex array.
And yeah I'm a complete noob at opengl so maybe this is a stupid question...
You can do this by using OpenGL Color Index Mode. However, be aware that, in my experience, this actually is slower on most modern graphics card than just specifying each vertex color.
In color index mode, you send a separate color array, then each vertex specifies an index into the array, instead of a full rgb/rgba. It's more memory efficient, but not as optimized in most hardware drivers.
You could use a vertex shader to do this by sending in a boolean flag for each vertex describing what color to be. Really the simplest/fastest thing is probably just to submit the color for each vertex.
If opengl had the ability to have multiple vertex streams and indices that might work (but also would probably not be worth it).