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).
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.
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.
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;
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've written plenty of
#version 330 core
GLSL shaders I'd like to reuse along with the OpenSceneGraph (OSG) 3.2.0 framework, and try to figure out how to get the state from the OSG I need to pass in by uniforms, and how to set them without having to change well-tested shader code, as well as how to populate arbitrarily named attributes.
This (version 140, OpenGL 3.1)
http://trac.openscenegraph.org/projects/osg/browser/OpenSceneGraph/trunk/examples/osgsimplegl3/osgsimplegl3.cpp
and this (version 400)
http://trac.openscenegraph.org/projects/osg/browser/OpenSceneGraph/trunk/examples/osgtessellationshaders/osgtessellationshaders.cpp
example give rise to a notion of aliasing certain attribute and uniform names to "osg_", but I'd like to use arbitrary names for the uniforms,
uniform mat4 uMVMatrix;
/*...*/
and to refer, or let the OSG refer, to the attributes by their numbers only, so sth like this
/*...*/
layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aST;
as used in my legacy shaders, I'd like the OSG framework to populate with the vbo it already maintains for the "Drawables", or, at least, use an API call and do it myself.
I addition, I'd like to populate uniforms for lights and shawdowmaps by means of the scenegraph and the visitors; "somewhere" and "somehow" in the SG there must be light and esp shadow information be aggregated for default shading, so I'd like simply like to use this data and tailor it to fit to my custom shaders.
So the fundamental question is
How to populate arbitrary GLSL 330 shaders with data from within OSG without having to resent to redundant uniform assignment - providing my "u[..]Matrix" manually in addition to the "osg_[...]" uniform set by OSG - or changing attribute names in the shader sources?
I just stumbled upon this, turns out, you can just use your own names after all, if you just specify the layout location (so far I only tried it for the vertex position, so you might have to take care of using the correct layout location as osg would specify them, i.e. vertex position at 0, normal at 1 (which is not done the example of the link though))
layout (location = 0) in vec3 vertex;
this is enough to use the variable named vertex in the shader.
The link also provides an example to use custom names for matrices: you create an osg::Uniform::Callback class that uploads the matrix to the uniform.
when you create the osg::Uniform object, you specify the name of your choosing and add the callback.