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).
Related
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.
I have a mesh with many thousands of vertices. The model represents a complex structure that needs to be visualized both in its entirety but also in part. The user of my application should be able to define a minimum and maximum value for the Z-Axis. Only fragments with a position between these limits should be rendered.
My naive solution would be to write a Fragment shader somewhat like this:
#extension GL_EXT_texture_array : enable
uniform sampler2DArray m_ColorMap;
uniform float m_minZ;
uniform float m_maxZ;
in vec4 fragPosition;
in vec3 texCoord;
void main(){
if (fragPosition.z < m_minZ || fragPosition.z > m_maxZ) {
discard;
}
gl_FragColor = texture2DArray(m_ColorMap, texCoord);
}
Alternatively I could try to somehow filter out vertices in the vertex shader. Perhaps by setting their position values to (0,0,0,0) if they fall out of range.
I am fairly certain both of these approaches can work. But I would like to know if there is some better way of doing this that I am not aware of. Some kind of standard approach for slicing models along an axis.
Please keep in mind that I do not want to use separate VBO's for each slice since they can be set dynamically by the user.
Thank you very much.
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.
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.
I'm trying to write a shader using cg (for ogre3d). I can't seem to parse a working shader that I'd like to use as a starting point for my own code.
Here's the declaration for the shader:
void main
(
float2 iTexCoord0 : TEXCOORD0,
out float4 oColor : COLOR,
uniform sampler2D covMap1,
uniform sampler2D covMap2,
uniform sampler2D splat1,
uniform sampler2D splat2,
uniform sampler2D splat3,
uniform sampler2D splat4,
uniform sampler2D splat5,
uniform sampler2D splat6,
uniform float splatScaleX,
uniform float splatScaleZ
)
{...}
My questions:
iTexCoord0 is obviously an input parameter. Why is it not declared uniform?
(oColor is obviously an output parameter. No question)
covMap1 - splat6 are textures. Are these parameters or something loaded into the graphics card memory (like globals)? The ogre definition for the shader program doesn't list them as parameters.
Are splatScaleX and splatScaleZ also parameters? The ogre definition for the shader program also doesn't list these as parameters.
Does the order of declaration mean anything when sending values from an external program?
I'd like to pass in an array of floats (the height map). I assume that would be
uniform float splatScaleZ,
uniform float heightmap[1024]
)
{...}
If I don't pass one of the parameters will the shader just not be executed (and my object will be invisible because it has no texture)?
Is there a better way to debug these than just hit/miss and guess?
iTexCoord0 is obviously an input parameter. Why is it not declared uniform?
Uniforms are not the same things as input parameters. iTexCoord is a varying input, which is to say that for every vertex, it can have a unique value. This is set with commands like glVertexAttribPointer. Things like vertex coordinates, normals, texcoords, vertex colors, are examples of what you might use a varying input for.
Uniforms are the other hand are intended to be static for an entire draw call, or potentially for the entire frame or life of the program. They are set with glUniform* commands. A uniform might be something like the modelview matrix for an object, or the position of the sun for a lighting calculation. They don't change very often.
[edit] These specific commands I think actually work with GLSL, but the theory should be the same for CG. Lookup a cg specific tutorial to figure out the exact commands to set varyings and uniforms.
covMap1 - splat6 are textures. Are these parameters or something loaded into the graphics card memory (like globals)? The ogre definition for the shader program doesn't list them as parameters.
My CG is a little rusty, but if its the same as GLSL then the sampler2d is a uniform that takes an index that represent which sampler you want to sample from. When you do something like glActiveTexture(GL_TEXTURE3), glBindTexture(n), then you set the sampler uniform to "3" you can sample from that texture.
Does the order of declaration mean anything when sending values from an external program?
No, the variables are referred to in the external program by their string variable names.
If I don't pass one of the parameters will the shader just not be executed (and my object will be invisible because it has no texture)?
Unknown. They will likely have "some" initial value, though whether that makes any sense and will generate anything visible is hard to guess.
Is there a better way to debug these than just hit/miss and guess?
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_b.html
See section B.3.8