In the vertex shader, the position of the current vertex is stored in gl_Position from what I understand. If in the tessellation shader I wanted to change that variable for a specific vertex how would I do that? Does each vertex contain it's own gl_Position variable? Is there a way to do something like vertex1.gl_Position so then OpenGL would know that I want to modify vertex1's gl_Position variable?
The tessellation control shader operates on patches, specific groups of vertices that are conceptually tessellated as a bundle. As such, the TCS's inputs are arrayed. The pre-defined VS outputs are aggregated into an array of TCS inputs in the following input interface block:
in gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[gl_MaxPatchVertices];
So gl_in[1].gl_Position is the gl_Position value output by the vertex shader for the second vertex in the patch.
Note that, while the array is sized on the maximum supported number of patch vertices, the actual limit is gl_PatchVerticesIn, the number of vertices in the tessellation patch.
Each TCS invocation outputs to a single vertex in the output patch (which may have a different number of vertices compared to the input patch). TCS outputs are also arrayed, and the built-in outputs have a similar array compared to the inputs:
out gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_out[];
Each TCS invocation is meant to write only to the output index gl_InvocationID. If a barrier is used, they can read from output vertices that were written by other invocations (or other patch outputs).
Tessellation evaluation shaders operate on individual vertices in the abstract patch generated by the primitive generator. However, all TES invocations operating on the same patch get the entire output patch from the TCS. This is arrayed in the same way as the TCS input patch, just with an array size defined by the TCS's output patch size.
If the TCS did not write to the predefined TCS outputs, the corresponding TES cannot access those outputs. As such, they're not actually special, they have no intrinsic meaning. gl_in[1].gl_Position in the TES is only a "position" if the TCS put a position data value there.
Related
I am trying to create an example of an interpolated surface.
First I created an example of an interpolated trefoil.
Here the source of my example.
Then I had to noticed that the animation is pretty slow, around 20-30FPS.
After some papers, I know that have to "move" the evaluation of the trefoil into the GPU. Thus I studied some papers about tessellation shaders.
At the moment I bind following simply vertex shader:
#version 130
in vec4 Position;
in vec3 Normal;
uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;
uniform vec3 DiffuseMaterial;
out vec3 EyespaceNormal;
out vec3 Diffuse;
void main()
{
EyespaceNormal = NormalMatrix * Normal;
gl_Position = Projection * Modelview * Position;
Diffuse = DiffuseMaterial;
}
Now I have multiply questions:
Do I use an array of vertices to pass GL_PATCHES like I already did with Triangle_Strips ? Which way is faster? DrawElements?
glDrawElements(GL_TRIANGLE_STRIP, Indices.Length, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero);
or should I use
glPatchParameteri(GL_PATCH_VERTICES,16);
glBegin(GL_PATCHES);
glVertex3f(x0,y0,z0)
...
glEnd();
What about the array of indices? How can I determine the path means in which order the patches will be passed.
Do I calculate the normals in the Shader as well?
I found some examples of tessellation shader but in #version400
Can I use this version on mobile devices as well?(OpenGL ES)
Can I pass multiple Patches to the GPU by Multithreading?
Many many thanks in advance.
In essence I don't believe you have to send anything to the GPU in terms of indices (or vertices) as everything can be synthesized. I don't know if the evaluation of the trefoil knot directly maps onto the connectivity of the resulting tessellated mesh of a bilinear patch, but this could work.
You could do with a simple vertex buffer where each vertex is the position of a single trefoil knot. Set glPatchParameteri(GL_PATCH_VERTICES​, 1). Then you could draw multiple knots with a single call to glDrawArrays:
glDrawArrays(GL_PATCHES, 0, numKnots);
The tessellation control stage can be a simple pass through stage. Then in the tessellation evaluation shader you can use the abstract patch type of quads. Then move the evaluation of the trefoil knot, or any other biparametric shape, into the tessellation evaluation shader, using the supplied [u, v] coordinates. Then you could translate every trefoil by the input vertex. The normals can be calculated in the shader as well.
Alternatively, you could use the geometry shader to synthesize the trefoil just from one input vertex position using points as input primitive and triangle strip as output primitive. Then you could just call again
glDrawArrays(GL_POINTS, 0, numKnots);
and create the trefoil in the geometry shader using the function for the generation of the indices to describe the order of evaluation and translating the generated vertices with the input vertex.
In both cases there would be no need to multithread draw calls, which is ineffective with OpenGL anyways. You are limited by the number of vertices that can be generated maximum per-patch which should be 64 times 64 for tessellation and GL_MAX_GEOMETRY_OUTPUT_VERTICES for geometry shaders.
The Khronos wiki for the Tessellation Control Shader states that
The output patch size does not have to match the input patch size.
Why is that? And why do we have to specify the input patch size at all when the control shader is able to change that before the primitive generation gets the patch?
Update
Is the following explanation correct?
The input patch (to the TCS) size is set by glPatchParameter(GL_PATCH_VERTICES, X). This has the consequence that the length of the in attribute arrays is X.
TCS:
in vec4 vs_tc_position[]; // This has a length of X
The output patch size is defined by the TCSs layout (vertices = Y) out;. This means the length of the out attribute arrays is Y.
TCS:
out vec4 tc_te_position[]; // This has a length of Y
The TCS is called Y times and passes the output directly to the TES. So, the in attribute arrays of the TES have a length of Y.
TES:
in vec4 tc_te_position[]; // This has a length of Y
The number of output patch vertices is irrelevant to the Tessellation Primitive Generation (TPG) because it only sees an abstract patch. The number of vertices of the abstract patch is defined by the TESs layout (TYPE) in;.
The TES is called for every new vertex that results from the abstract patch due to the tessellation levels defined by the TCS (when it exists) or by glPatchParameter(GL_PATCH_DEFAULT_{OUTER|INNER}_LEVEL). The TES can then interpolate the attributes based on the gl_TessCoord from the abstract patch and all the vertices (which are more like control points) from the TCS.
Example
So, the following situation could be possible.
glPatchParameteri(GL_PATCH_VERTICES, 1);
The TCS gets one vertex per patch.
layout (vertices = 5) out;
The TCS creates 5 vertices for the output patch. Somehow.
layout (quads) in;
The TPG uses a quad as an abstract patch and subdivides. Then the TES is called on every new vertex and interpolates the attribute of the 5 output vertices from the TCS with the gl_TessCoord from the abstract patch (somehow) to compute the attributes for the new vertices.
The input patch size has to be specified because you don't have to have a TCS at all.
Also, remember that the input patch size is used to interpret the stream of vertices you render with. Every X vertices is a single patch, so OpenGL needs to know what X to use. Even with a TCS, OpenGL needs to have an input size to know how many vertices to pass to the TCS operation.
As for why the input and output patch sizes can be different, that is there to give freedom to the TCS and the user to do whatever they want. TCS's are able to add, remove, or modify data however they want, including adding or removing entire values.
So a TCS can turn a single input vertex into 4 output vertices; this could be useful for something like quad tessellation.
I know that each time a vertex shader is run it basically accesses part of the buffer (VBO) being drawn, when drawing vertex number 7 for example it's basically indexing 7 vertices into that VBO, based on the vertex attributes and so on.
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 texCoords; // This may be running on the 7th vertex for example.
What I want to do is have access to an earlier part of the VBO for example, so when it's drawing the 7th Vertex I would like to have access to vertex number 1 for example, so that I can interpolate with it.
Seeing that at the time of running the shader it's already indexing into the VBO already, I would think that this is possible, but I don't know how to do it.
Thank you.
As you can see in the documentation, vertex attributes are expected to change on every shader run. So no, you can't access attributes defined for other vertices in a vertex shader.
You can probably do this:
Define a uniform array and pass in the values you need. But keep in mind that you are using more memory this way, you need to pass more data etc.
As #Reaper said you can use a uniform buffer, which can be accessed freely. But the GPU doesn't like random access, it's usually more efficient to stream the data.
You can solve this as well by just adding the data for later/earlier vertices into the array, because in C++ all vertices are at your disposal.
For example if this is the "normal" array:
{
vertex1_x, vertex1_y, vertex1_z, normal1_x, normal1_y, normal1_z, texCoord1_x, texCoord1_y,
...
}
Then you could extend it with data for the other vertex to interpolate with:
{
vertex1_x, vertex1_y, vertex1_z, normal1_x, normal1_y, normal1_z, texCoord1_x, texCoord1_y, vertex2_x, vertex2_y, vertex2_z, normal2_x, normal2_y, normal2_z, texCoord2_x, texCoord2_y,
...
}
Actually you can pass any data per vertex. Just make sure that the stride size and other parameters are adjusted in the glVertexAttribPointer parameters.
I am sorry to post a question that may be easily tested, but I don't have an OGL4+ hardware at the moment and I have to make some design decision beforehand so I wanted a clear scenario.
Suppose I have a variable produced in the vertex shader that I will not need until the fragment shader. If I also include the tessellation shaders can I do something like:
//// Vertex shader
out vec3 foo;
// Ignore foo in tessellation control and eval shader
//// Fragment shader
in vec3 foo;
Or I necessarily have to do something like:
//// Vertex shader
out vec3 fooCS;
// TCS
in vec3 fooCS;
out vec3 fooES;
//TES
in vec3 fooES;
out vec3 foo;
//// Fragment shader
in vec3 foo;
And in the latter case, should I use the [] qualifier to pass the variables?
Every shader stage that actually exists in your pipeline is responsible for feeding all values to the next one. So if you want to pass a variable from the vertex shader to the fragment shader, every intervening stage must provide that variable.
And this makes sense. Take tessellation. The whole point of tessellation is that new vertices get created. How could OpenGL automatically map the vertex shader output to arbitrary tessellation functions? Indeed, doing that mapping is why the TES exists; that's what it's for.
Same thing with the GS. It can generate new primitives and vertices.
As for using [], you will have to use it as is appropriate for the inputs and outputs of that particular stage.
My question is that all of Tesellation Control Shader Invocation produce the same result, why OPENGL has to call this shader many times for each patch.
For example: My Tesellation Control Shader calculates control points for the Bezier Surface. It take an array of three vertices, which is aggregated earlier from Vertex Shaders.
// attributes of the input CPs
in vec3 WorldPos_CS_in[];
My patch size is 3, so Tesellation Control Shader is called three times for the same input, save for gl_invocatinoID, and then all of them produce the same following control points:
struct OutputPatch
{
vec3 WorldPos_B030;
vec3 WorldPos_B021;
vec3 WorldPos_B012;
vec3 WorldPos_B003;
vec3 WorldPos_B102;
vec3 WorldPos_B201;
vec3 WorldPos_B300;
vec3 WorldPos_B210;
vec3 WorldPos_B120;
vec3 WorldPos_B111;
vec3 Normal[3];
vec2 TexCoord[3];
};
// attributes of the output CPs
out patch OutputPatch oPatch;
And, also the same information which help OpenGL divide this patch into tesellation coordinates:
// Calculate the tessellation levels
gl_TessLevelOuter[0] = gTessellationLevel;
gl_TessLevelOuter[1] = gTessellationLevel;
gl_TessLevelOuter[2] = gTessellationLevel;
gl_TessLevelInner[0] = gTessellationLevel;
It is clear that all of Tes Control Shader do same job. Does it waste resources? Why Tesellation Control Shader should be called for one time for each patch?
Well the control shader invocations don't produce exactly the same result, because the control point output is obviously different for each. But that's being pedantic.
In your program, and in all of mine so far, yes the control shader is doing exactly the same thing for every control point and the tessellation level doesn't change.
But suppose you have the shader generating new attributes for each control point, a texture normal or something? Then the shader would generate different results for each. It's nice to have the extra flexibility if you need it.
Modern GPUs try to do as much as possible in parallel. The older geometry shaders have one invocation generating multiple outputs. It's more efficient, not less, on modern GPUs to have multiple invocations each generating one output.