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.
Related
The correspondence between sampler uniforms and texture units used by glActiveTexture apparently can't be queried with opengl, and I can't find good documentation on how to find which texture unit is mapped to which sampler uniform. Here is what I have been able to find:
If there is only sampler uniform in a program, then it is mapped to gl_TEXTURE0
If there are multiple sampler uniforms in a single program stage, then they are mapped in the order they are declared in the shader.
If the vertex and fragment shaders have disjoint sets of sampler uniforms, then the samplers in the vertex shader come first and are followed by the samplers in the fragment shader.
This behavior appears to be defined by the specification.
So for example if the vertex shader defines:
uniform sampler2D color;
And the fragment shader defines:
uniform sampler2D tex;
uniform sampler2D norm;
Then color gets mapped to gl_TEXTURE0, tex gets mapped to gl_TEXTURE1, and norm gets mapped to gl_TEXTURE2. But if instead the vertex shader defines:
uniform sampler2D norm;
Then it is not clear how the different textures get mapped. This is additionally complicated by the possibility of having layout qualifiers or separate shader stages.
I can't seem to find documentation on this anywhere. Everything I know about it either comes from my own experimentation or answers on Stackoverflow or the OpenGL forum. Does anyone know of a comprehensive set of rules for how this works in all possible cases, or a way to query the texture unit that a sampler corresponds to?
Here is what I have been able to find:
If there is only sampler uniform in a program, then it is mapped to gl_TEXTURE0
If there are multiple sampler uniforms in a single program stage, then they are mapped in the order they are declared in the shader.
If the vertex and fragment shaders have disjoint sets of sampler uniforms, then the samplers in the vertex shader come first and are followed by the samplers in the fragment shader.
This behavior appears to be defined by the specification.
None of this is true. OK, the first one is true, but only by accident.
All uniform values which are not initialized in the shader are initialized to the value 0. The spec makes this quite clear:
Any uniform sampler or image variable declared without a binding qualifier is initially bound to unit zero.
A sampler uniform's value is the integer index of the texture unit it represents. So a value of 0 corresponds to GL_TEXTURE0. All uninitialized sampler uniforms should have a value of 0.
If the behavior you describe is happening, then that implementation is in violation of the OpenGL specification.
Unless you use the layout(binding = ) syntax to assign a uniform's texture unit, you must manually in your OpenGL code assign each sampler uniform a value for its texture unit. This is done by setting its uniform value, just like any other integer uniform: you call glUniform1i with the location corresponding to that uniform. So if you want to associate it with texture image unit index 4, you call glUniform1i(..., 4), where ... is the uniform location for that uniform.
You have to set the index of the texture unit to sampler uniform (similar as setting the value of a uniform variable of type int). e.g. value 1 for GL_TEXTURE1.
See OpenGL 4.6 API Compatibility Profile Specification; 7.10 Samplers; page 154:
Samplers are special uniforms used in the OpenGL Shading Language to identify
the texture object used for each texture lookup. The value of a sampler indicates the texture image unit being accessed. Setting a sampler’s value to i selects texture image unit number i.
e.g.
layout (location = 11) uniform sampler2D color;
layout (location = 12) uniform sampler2D tex;
layout (location = 13) uniform sampler2D norm;
glUniform1i(11, 0); // 0: GL_TEXTURE0
glUniform1i(12, 1); // 1: GL_TEXTURE1
glUniform1i(13, 2); // 2: GL_TEXTURE2
Since GLSL version 4.2 this can be done in the fragment shader by specifying binding points - See OpenGL Shading Language 4.20 Specification - 4.4.4 Opaque-Uniform Layout Qualifiers; page 60:
#version 420
layout (binding = 0) uniform sampler2D color;
layout (binding = 1) uniform sampler2D tex;
layout (binding = 2) uniform sampler2D norm;
I have a UBO defined in my vertex shader as follows:
layout (std140) uniform matricesBuffer
{
mat4 MVPMatrix;
mat4 modelMatrix;
};
I spent ages figuring out why the matrix I needed wasn't getting through. Then I added the same uniform block to the fragment shader, and it magically worked. So my question is, I know there are specifications about interface matching between shader programs/stages when using separable shaders in a pipeline, but from what I've read these only describe the in and out variables, but this uniform block, or UBO it is, should be accessible from just the vertex shader, as I linked the UBO to that binding point. I'm confused about this, any info would be appreciated.
Edit: I've been trying some things, putting just:
layout (std140) uniform anyName
{
mat4 worldMatrix;
};
in the fragment shader makes it work. And if I change "anyName" to certain names it either works or doesn't. For example if it starts with the letter R it doesn't work, then most other letters it works. So confused.
I need to setup a 'dependent texture' such that the return values from one texture lookup are used to determine where to look up from a second texture.
Can you point me to the right gl API calls I would need to do this?
I need to setup a 'dependent texture' such that the return values from one texture lookup are used to determine where to look up from a second texture.
This can be done using shaders, only.
Can you point me to the right gl API calls I would need to do this?
You were asking for the API calls: Well here they are:
glCreateShader to create new shader objects
glShaderSource to load the shader source code into the shader objects
glCompileShader to compile the loaded shader sources
glCreateProgram to create a program object
glLinkProgram to link the shader objects into a program
glUseProgram to actually use the shader program created with the above calls
glUniform1i to set the fragment shaders sampler uniforms to the texture units sourced
Also, you were not asking for them, but you need them as well, here are the required GLSL language elements:
sampler… uniforms to bind the texture units to
The texture GLSL function to fetch a texture sample. Use the value of a sampled texture to determine the texture coordinate for the next one.
Like this.
uniform sampler2D coord_texture;
uniform sampler2D sampling_texture;
uniform vec2 InvWinSize;
void main(void){
vec2 uv = gl_FragCord.st*InvWinSize;
vec2 tex_coord = texture(coord_texture, uv).st;
vec4 sampled = texture(sampling_texture,tex_coord);
}
I accessed the first texture with the screen coordinates, but you can use whatever uv you need, for examples, uv coming from a vertex shader:
uniform sampler2D coord_texture;
uniform sampler2D sampling_texture;
in vec2 uv;
void main(void){
vec2 tex_coord = texture(coord_texture, uv).st;
vec4 sampled = texture(sampling_texture,tex_coord);
}
I'm working with openGL.
I have vertex and fragment shaders that work fine when used just with each other, but when I add the tesselation shaders, uniforms that were previously recognized on the program are said to be not referenced in the shaders.
Is this an specificity that I'm not aware about?
This is in my .cpp:
program = new Shader("tessVshader.glsl", "tessFshader.glsl", "tessGshader.glsl");
// Removed tesselation specific just to try to compile w/ geo shader
...
program->SetUniform("Modelview", model * view);
program->SetUniform("NormalMatrix", normalMatrix);
And this is tessGshader.glsl first lines:
uniform mat4 Modelview;
uniform mat3 NormalMatrix;
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
This is the output:
Uniform Modelview is not referenced in the shaders.
Is the Shader class written by you? If yes, some of its code would be helpful.
If GL shader objects are properly created, make sure that you have a call to glUseProgram(...) before trying to access the uniforms. Otherwise openGL will be unable to find them.
And btw, ensure that you can see compile/linking time errors in your glsl code. Look up the function glGetInfoLog, if you dont use it already.
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.