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
Related
I'm trying to understand uniform samplers and textures in GLSL. Right now, I understand basic uniforms, in that if I have
uniform float someFloat;
in my shader, I would write (pseudocode) such as
someFloatLoc = glGetUniformLocation(program, "someFloat")
glUniform1f(someFloatLoc, 3.14159)
to set the value of the uniform.
However, if I instead have
uniform shader1d t1;
uniform shader2d t2;
in my shader, what is the corresponding OpenGL function to set the texture? I would expect to find something like glUniformshader2d(uniform_loc, texture) wherein texture is an array specifying the texture, but so far my research leads me to a large number of functions, like glActiveTexture, glGenTextures, glBindTextures, glTexImage2d, and constants like GL_TEXTURE1. But all I'm trying to do is assign an array specifying the texture to a specific shader uniform samplerXd foo so I then can compute the output color based on fetchTexel(foo, texture_coord).
My question can be summarized as follows:
How can I mimic the functionality of glUniform1f for a uniform float in a GLSL shader, but for a uniform sampler instead?
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.
When seeing some OpenGL examples, some use the following types of variables when declaring them at the top of the shader:
in
out
and some use:
attribute
varying
uniform
What is the difference? Are they mutually exclusive?
attribute and varying were removed from GLSL 1.40 and above (desktop GL version 3.1) in core OpenGL. OpenGL ES 2 still uses them, but were removed from ES 3.0 code.
You can still use the old constructs in compatibility profiles, but attribute only maps to vertex shader inputs. varying maps to both VS outputs and FS inputs.
uniform has not changed; it still means what it always has: values set by the outside world which are fixed during a rendering operation.
In modern OpenGL, you have a series of shaders hooked up to a pipeline. A simple pipeline will have a vertex shader and a fragment shader.
For each shader in the pipeline, the in is the input to that stage, and the out is the output to that stage. The out from one stage will get matched with the in from the next stage.
A uniform can be used in any shader and will stay constant for the entire draw call.
If you want an analogy, think of it as a factory. The in and out are conveyor belts going in and out of machines. The uniform are knobs that you turn on a machine to change how it works.
Example
Vertex shader:
// Input from the vertex array
in vec3 VertPos;
in vec2 VertUV;
// Output to fragment shader
out vec2 TexCoord;
// Transformation matrix
uniform mat4 ModelViewProjectionMatrix;
Fragment shader:
// Input from vertex shader
in vec2 TexCoord;
// Output pixel data
out vec4 Color;
// Texture to use
uniform sampler2D Texture;
Older OpenGL
In older versions of OpenGL (2.1 / GLSL 1.20), other keywords were used instead of in and out:
attribute was used for the inputs to the vertex shader.
varying was used for the vertex shader outputs and fragment shader inputs.
Fragment shader outputs were implicitly declared, you would use gl_FragColor instead of specifying your own.
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).
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.