why the gl_ClipDistance[] doesn't work? - opengl

I just can't understand why the gl_ClipDistance doesn't work. The result is the same as I didn't set the gl_ClipDistance.
I had set glEnable(GL_CLIP_DISTANCE0+2) by application.
the vertex shader is like this:
#version 410
uniform mat4 mvpMatrix;
//.......some other uniforms here
in vec2 vVertex;
uniform vec4 clip_plane=vec4(1.0,1.0,0.0,0.85);
uniform vec4 clip_sphere=vec4(0.0,0.0,0.0,10.0);
void main(void)
{
//........some other code,include vec2 worldPos
vec4 worldPosition=vec4(worldPos.x,height,worldPos.y,1.0);
gl_ClipDistance[0]=dot(worldPosition,clip_plane);
gl_ClipDistance[1]=length(worldPosition.xyz/worldPosition.w-clip_sphere.xyz)-clip_sphere.w;
gl_Position = mvpMatrix * position;
}
PS:after told by good men, I had known that " glEnable(GL_CLIP_DISTANCE0+2) " is not right. so I set "glEnable(GL_CLIP_DISTANCE0) ;glEnable(GL_CLIP_DISTANCE1) ;",but it still didn't work.
Then,I tried to only set "glEnable(GL_CLIP_DISTANCE0)"and"gl_ClipDistance[0]=-1.0" ,but what make me confused is that my model just still stay there,didn't disappear.
Anybody know how this happen?

I had set glEnable(GL_CLIP_DISTANCE0+2) by application.
But not GL_CLIP_DISTANCE0 and GL_CLIP_DISTANCE1.
From gl_ClipDistance:
Values written into gl_ClipDistance planes that are not enabled have no effect.
Enable GL_CLIP_DISTANCE0 and GL_CLIP_DISTANCE1 if you intend to write to gl_ClipDistance[0] and gl_ClipDistance[1].

You are invoking undefined behavior here.
GL_CLIP_DISTANCE0 + 2 is actually the third clip distance in gl_PerVertex.gl_ClipDistance [...].
Name
gl_ClipDistance — provides a forward-compatible mechanism for vertex clipping
Description
[...]
The number of varying components consumed by gl_ClipDistance will match the size of the array, no matter how many planes are enabled. The shader must also set all values in gl_ClipDistance that have been enabled via the OpenGL API, or results are undefined. Values written into gl_ClipDistance planes that are not enabled have no effect.
Since you have enabled clipping against gl_ClipDistance [2] but have not written anything to it, your per-vertex output is actually only an array of 2 clip distances, and the third is undefined. Clipping against something that is undefined will produce unpredictable behavior.
There is a requirement that the array be sized to include the highest enabled clip plane. That means if you enable GL_CLIP_DISTANCE2, gl_ClipDistance [] needs to have a size of 3. GLSL automatically resizes that array if you index it using a constant integer expression (as you have done when you use 0 and 1), but it only resizes it to 2, not 3.

Related

How can I determine the limit on Vertex Shader outputs?

I'm trying to introduce multiple shadow casters, and in the process I'm passing a transformed position for each light in the VS output. The shader compiler reports errors as a result of the output size exceeding some internal limit, but I've been thus far unable to determine what the limit actually is (or how to find it).
The output structure is as follows:
out VS_OUT
{
vec3 FragPos;
vec3 Normal;
vec3 Colour;
vec2 TexCoord;
vec4[MAX_SHADOW_CASTERS] LightSpaceFragPos;
} vso;
Compilation has failed at MAX_SHADOW_CASTERS value 64 and 32, at the very least.
Additionally, any suggestions around improving the capacity of the array would be appreciated. These values are naturally per fragment, so a universal texture/buffer would be impractical as far as I understand.
The maximum number of varying vector variables (that's what the interface between the vertex and fragment shader stages are called - and in earlier GLSL versions those actually had the keyword varying instead of in/out) can be queryied via glGetIntegerv with GL_MAX_VARYING_VECTORS as the pname parameter argument.

The difference between a color attribute and using gl_Color

Most GLSL shaders are using a attribute for the color in the vertex shader, which will be forwarded as varying to the fragment shader. Like this:
attribute vec4 position;
attribute vec4 color;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = color;
gl_Position = mvp * position;
};
Setting the color can be done with glVertexAtribPointer() to pass one color per vertex or with glVertexAttrib4fv() to pass a global color for all vertexes. I try to understand the difference to the predefined variable gl_Color in the vertex shader (if there is any difference at all). i.e.
attribute vec4 position;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = gl_Color;
gl_Position = mvp * position;
};
and using glColorPointer() to pass one color per vertex or glColor4fv() to use a global color for all vertexes. To me the second shader looks better (= more efficient?), because it uses less attributes. But all tutorials & online resources are using the first approach - so I wonder if I missed anything or if there is no difference at all.
What is better practice when writing GLSL shaders?
To me the second shader looks better (= more efficient?), because it uses less attributes.
It does not use fewer attributes. It just uses fewer explicit attribute declarations. All of the work needed to get that color value to OpenGL is still there. It's still being done. The hardware is still fetching data from a buffer object or getting it from the glColor context value or whatever.
You just don't see it in your shader's text. But just because you don't see it doesn't mean that it happens for free.
User-defined attributes are preferred for the following reasons:
User-defined attributes make it clear how many resources your shaders are using. If you want to know how many attributes you need to provide to a shader, just look at the global declarations. But with predefined attributes, you can't do this; you have to scan through the entire vertex shader for any gl_* names that name a predefined attribute.
User-defined attributes can do more things. If you want to pass integer values as integers to the vertex shader, you must use a user-defined attribute. If you need to pass a double-precision float to the vertex shader, again, a predefined attribute cannot help you.
Predefined attributes were removed from core OpenGL contexts. OSX, for example, does not allow the compatibility profile. You can still use OpenGL 2.1, but if you want to use any OpenGL version 3.2 or greater on OSX, you cannot use removed functionality. And the built-in vertex attributes were removed in OpenGL 3.1.
Predefined attributes were never a part of OpenGL ES 2.0+. So if you want to write shaders that can work in OpenGL ES, you again cannot use them.
So basically, there's no reason to use them these days.
if I remember correctly gl_Color is deprecated remnant from the old style API without VAO/VBO using glBegin() ... glEnd(). If you go to core profile there is no gl_Color anymore ... so I assume you use old OpenGL version or compatibility profile.
If you try to use gl_Color in core profile (for example 4.00) you got:
0(35) : error C7616: global variable gl_Color is removed after version 140
Which means gl_Color was removed from GLSL 1.4
It is not entirely matter of performance but the change in graphic rendering SW architecture or hierarchy of the GL calls if you want.

Am I able to initiate blank variables and declare them afterwards?

I would like to do something like this:
vec4 text;
if (something){
text = texture(backgroundTexture, pass_textureCoords);
}
if (somethingElse){
text = texture(anotherTexture, pass_textureCoords);
}
Is this valid GLSL code, and if not, is there any suitable alternative?
The answer depends on what something and somethingElse actually are.
If this is a uniform control flow, which means that all shader invocations execute the same branch, then this is perfectly valid.
If they are non uniform expressions, then there are some limitations:
When a texture uses mipmapping or anisotropic filtering of any kind, then any texture function that requires implicit derivatives will retrieve undefined results.
To sum it up: Yes, this is perfectly valid glsl code but textures in non-uniform controls flow have some restrictions. More details on this can be found here.
Side note: In the code sample you are not declaring the variables afterwards. You are just assigning values to them.
Edit (more info)
To elaborate a bit more on what uniform and non-uniform control flow is: Shaders can (in general) have two types of inputs. Uniform variables like uniform vec3 myuniform; and varyings like in vec3 myvarying. The difference is where the data comes from and how it can change during an invocation:
Uniforms are set from application side, and are (due to this) constant over an invocation (where invocation simplified means draw command).
Varyings are read from vertex inputs (in the vertex shader) or are passed and interpolated from previous shader stages (e.g. in the fragment shader).
Uniform control flow now means, that the condition of the corresponding if statement only depends on uniforms. Everything else is non-uniform control flow. Let's have a look at this fragment shader example:
//Uniforms
uniform vec3 my_uniform;
uniform sampler2D my_sampler;
/Varyings
in vec2 tex_coord;
in vec2 ndc_coords;
void main()
{
vec3 result = vec3(0,0,0);
if (my_uniform.y > 0.5) //Uniform control flow
result += texture(my_sampler, tex_coord).rgb;
if (ndc_coords.y > 0.5) //Non-uniform control flow
result += texture(my_sampler, tex_coord).rgb;
float some_value = ndc_coords.y + my_uniform.y;
if (some_value > 0.5) //Still non-uniform control flow
result += texture(my_sampler, tex_coord).rgb;
}
In this shader only the first texture read happens in uniform control flow (since the if condition only depends on a uniform variable). The other two reads are in non-uniform control flow since the if condition also depends on an varying (ndc_coords).

Two layouts with the same location in GLSL 4.4

Is it possible to have two layouts with the same location equate to two different input variables of different types in a shader? Currently, my program is not explicitly assigning any location for the vertex, texture, normal vertex arrays. But in my shader, when I have selected the location 0 for both my vertex position and texture coords, it gives me a perfect output. I wanted to know if this is just a coincidence or is it really possible to assign to the same location? Here is my definition of the input variables in the vertex shader:
#version 440
layout (location = 0) in vec4 VertexPosition;
layout (location = 2) in vec4 VertexNormal;
layout (location = 0) in vec2 VertexTexCoord;
Technically... yes, you can. For Vertex Shader inputs (and only for vertex shader inputs), you can assign two variables to the same location. However, you may not attempt to read from both of them. You can dynamically select which one to read from, but it's undefined behavior if your shader takes a path that reads from both variables.
The relevant quote from the standard is:
The one exception where component aliasing is permitted is for two input variables (not block members) to a vertex shader, which are allowed to have component aliasing.This vertex-variable component aliasing is intended only to support vertex shaders where each execution path accesses at most one input per each aliased component.
But this is stupid and pointless. Don't do it.

Names of `out` variables in a fragment shader

I'm having some problem understanding one line in the most basic (flat) shader example while reading OpenGL SuperBible.
In chapter 6, Listing 6.4 and 6.5 it introduces the following two very basic shaders.
6.4 Vertex Shader:
// Flat Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
// Transformation Matrix
uniform mat4 mvpMatrix;
// Incoming per vertex
in vec4 vVertex;
void main(void)
{
// This is pretty much it, transform the geometry
gl_Position = mvpMatrix * vVertex;
}
6.5 Fragment Shader:
// Flat Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
// Make geometry solid
uniform vec4 vColorValue;
// Output fragment color
out vec4 vFragColor;
void main(void)
{
gl_FragColor = vColorValue;
}
My confusion is that it says vFragColor in the out declaration while saying gl_FragColor in main().
On the other hand, in code from the website, it has been corrected to 'vFragColor = vColorValue;' in the main loop.
What my question is that other then being a typo in the book, what is the rule for naming out values of shaders? Do they have to follow specific names?
On OpenGL.org I've found that gl_Position is required for the out of the vertex shader. Is there any such thing for the fragment shader? Or it is just that if there is only one output, then it will be the color in the buffer?
What happens when there is more then one out of a fragment shader? How does the GLSL compiler know which one to use in the buffer?
As stated in the GLSL specification for version 1.3, the use of gl_FragColor in the fragment shader is deprecated. Instead, you should use a user defined output variable like the
vFragColor variable described in your fragment shader. As you said, it's a typo.
What is the rule for naming out values of shaders?
The variable name can be anything you like, unless it collides with any existing names.
What happens when there is more then one out of a fragment shader? How does the GLSL compiler know which one to use in the buffer?
When there is more than one out in the fragment shader, you should assign slots to the fragment shader outputs by calling BindFragDataLocation. You can then say which slots will render to which render target by calling DrawBuffers.
The specification states that if you have one output variable in the fragment shader defined, it will be assigned to index 0 and output 0. For more information, I recommend you take a look at it yourself.
gl_FragColor was the original output variable in early versions of GLSL. This was the color of the fragment that was to be drawn.
Your initial confusion is justified, as there's no reason to declare that out variable and then write to glFragColor.
In later versions it became customizable, such that you could give arbitrary names to your output variables. You can map these arbitrary outputs to specific buffers with the command glBindFragDataLocation.
I'm not 100% positive, but I believe if you don't call this function before linking, then your output variables will be randomly assigned to buffers. If you only have one output, then it should always be assigned to buffer 0.