in my shaders I like to use a syntax like this:
layout (location = 0) in vec3 aPos;
So that I can just use the index 0 in glVertexAttribPointer and the such, saving the effort for the glGetAttribLocation call. I'd like to do the same with uniform values, but if I do
layout (location = 2) uniform float offset;
My vertex shader fails to compile. Is there any way to achieve the same behavior and not use glGetUniformLocation?
OpenGL 4.3 or the ARB_explicit_uniform_location extension allows you to specify uniform locations within the shader using that syntax. So your shader #version needs to be 430 or you need to activate the extension in your shader to be able to use this syntax.
Related
I am compiling this shader with glslangValidator, and am using OpenGL 4.3 Core Profile with the extension GL_ARB_gl_spirv, and using the GLAD webservice to generate function pointers to access the Core OpenGL API, and SDL2 to create the context, if that is of any use.
If I have a fragment shader like so:
#version 430 core
//output Fragment Color
layout (location = 0) out vec4 outFragColor;
//Texture coordinates passed from the vertex shader
layout (location = 0) in vec2 inTexCoord;
uniform sampler2D inTexture;
void main()
{
outFragColor = texture(inTexture, inTexCoord);
}
How would I be able to set which texture unit inTexture uses?
From what I have read online through documents, I cannot use glGetUniformLocation to get the location of this uniform to use in glUniform1i, because of the fact I am using SPIR-V, instead of GLSL directly.
What would I need to do to set it in a fashion like glUniform1i? Do I need to set the location in the layout modifier? The binding? I've tried to use Uniform Buffer Objects, but apparently sampler2D can only be a uniform.
Since GLSL 4.20, you have the ability to set the binding point for any opaque type like samplers from GLSL code directly. This is done through the binding layout qualifier:
layout(binding = #) uniform sampler2D inTexture;
The # here is whatever binding index you want to use. This is the index you use when binding the texture: glActiveTexture(GL_TEXTURE0 + #). That is, you don't need to use glProgramUniform to set the uniform's value anymore; you already set it in the shader.
If you want to modify the binding dynamically (and you shouldn't), GLSL 4.30 offers the ability to set the location for any non-block uniform value via the location layout qualifier:
layout(location = #) uniform sampler2D inTexture;
This makes # the uniform's location, which you can pass to any glProgramUniform call.
I'm doing my first steps with OpenGL and stumbled upon a problem in my vertex shader program:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 inputTransform;
void main()
{
gl_Position = inputTransform * vec4(aPos, 1.0);
}
compiles and works well, but when I change the first line to
#version 130 core
because I'm bound to use OpenGL 3.0 at max, it first complains about the "location" statement. When I remove it, the remaining error message for the line
layout in vec3 aPos;
is
ERROR: 0:2: 'in' : syntax error syntax error
What's wrong here - how do I have to declare input variables in this version of the language?
Input layout qualifiers have been added in GLSL version 1.50 wich corresponds to OpeneGL version 3.2
See OpenGL Shading Language 1.50 Specification; - 4.3.8.1 Input Layout Qualifiers; page 37.
An input layout qualifier consists of the keyword layout followed by the layout-qualifier-id-list.
It is not sufficient to remove the layout-qualifier-id-list alone, you have to remove the keyword layout too:
in vec3 aPos;
The syntax error is caused by the fact, that it is not a proper syntax, that layout is directly followed by in.
Either you have to ask for the attribute index by glGetAttribLocation after the program is linked, or you have to specify the attribute location by glBindAttribLocation before the shader program is linked.
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.
In a GLSL vertex shader I have:
#version 330
layout (location=0) uniform mat4 wm_;
layout (location=1) uniform mat4 vm_;
...more code...
I get no compile errors when the shader is compiled. Later, I am assert()ing on glGetUniformLocation for wm_ and vm_ returning the locations specified in the shader source. The asserions fire, as glGetUniformLocation returns different values (it do not return -1, that is, the uniforms don't get optimized away, they get assigned what appear to be valid but different locations.)
Can anyone explain this behavior?
Explicit uniform locations are supported since GLSL 4.30 or by extension GL_ARB_explicit_uniform_location.
The compiler here is too tolerant and allows syntax that is not supported in GLSL 3.30
This should be considered as a driver bug.
On the OpenGL FBO wiki page there is this snippet:
You can also use layout syntax to define this directly in the shader,
as you would for attribute indices:
layout(location = 0) out vec4 mainColor;
layout(location = 1) out vec2 subsideraryInfo;
This seems to indicate that attribute indices can be specified within a shader, which would simplify things a bit my removing the need for my code to specify attribute locations and such using glBindAttribLocation.
Yes you can do that starting from GLSL 3.30 (OpenGL 3.3). Read here: http://www.opengl.org/registry/doc/GLSLangSpec.3.30.6.clean.pdf (page 35).