How do I pass uniforms between different shader programs in OpenGL? - opengl

I'm wondering if there is a way to communicate data between two separate shader programs.
I have one geometry shader that uses a uniform float, and I would like to send the value of that float to a fragment shaders that is used by another program.
Is this possible? I know that OpenGL uses pre-defined global variables, but is there a way to create my own?
Geometry shader from program 1:
uniform float uTime;
Fragment shader from program 2:
if (uTime > 0.){
...
}

I would like to send the value of that float to a fragment shaders that is used by another program. Is this possible?
There is no "interface" between different shader programs.
If you want to use the same uniform in your second shader program, then you simply need to declare and upload that same uniform in your second shader program, just like you did it for your first shader program.
(I am not getting into uniform buffer objects for the rest of this answer, since you used top-level uniform variables in the unnamed block. But, you can use a uniform buffer object holding your uniform values, which you then bind to both shader programs.)
So: Declare the uniform in the fragment shader of your second shader program just like you did with the geometry shader of your first shader program:
uniform float uTime;
void main(void) {
...
if (uTime > 0.){
...
}
...
}
Then, as usual, compile and link that program and obtain the location of the uniform in that second shader program via glGetUniformLocation() once:
// do once:
GLint uTimeLocationInSecondShaderProgram = glGetUniformLocation(yourSecondShaderProgram, "uTime");
and then send a value to the uniform via e.g. glUniform1f() whenever the value changes (e.g. once per render loop iteration):
// do before drawing:
float time = ...; // <- whatever time you also used in your first shader program
glUseProgram(yourSecondShaderProgram);
glUniform1f(uTimeLocationInSecondShaderProgram, time);

Related

GLSL subroutines and shader uniforms. Why are my uniforms optimized out?

Okay, I'm trying to use some of my shader uniform variables that is used inside of subroutine functions only (so there is no call to this variables outside of subroutine functions at all).
Important part is: I don't call this subroutine functions directly inside shader main, instead I have subroutine uniform array which I fill with glUniformSubroutinesuiv and use this syntax to call them:
my_subroutines[i]();
My problem is that all of that uniform variables are optimized out.
What I've already checked:
subroutine functions themselves are not optimized out (I found them
via glGetActiveSubroutineName and they are here after shader
linking). It's true always, even if there is no calls to them inside
of shader main.
If I call my subroutine function directly by it's name inside of shader main then uniforms are not optimized out (found them via glGetActiveUniform)
So, is this normal behaviour? How can I keep my uniform variables without doing some stupud things like that:
void main()
{
vec4 color;
//force use of uniform variables to prevent them be optimized out
color += 0.0001*(uniform_variable0 + uniform_variable1 + ... + uniform_variableN);
//call my subroutines here (that uses the same uniforms ... cmon glsl)
color = subroutines_array[0](color);
color = subroutines_array[1](color);
...
color = subroutines_array[N](color);
FragColor = color;
}
Found that I'm doing it wrong:
void main()
{
vec4 color;
//so i never updated my color here, and that's why uniforms was cut out
subroutines_array[0](color);
subroutines_array[1](color);
...
subroutines_array[N](color);
FragColor = color;
}

Multiple Shaders in OpenGL

Is there a way to create multiple shaders (both vertex, fragment, even geometry and tessellation) that can be compounded in what they do?
For example: I've seen a number of uses of the in and out keywords in the later versions of OpenGL, and will use these to illustrate my question.
Is there a way given a shader (doesn't matter which, but let's say fragment shader) such as
in inVar;
out outVar;
void man(){
var varOne = inVar;
var varTwo = varOne;
var varThr = varTwo;
outVar = varThr;
}
To turn it into the fragment shader
in inVar;
out varOne;
void main(){
varOne = inVar;
}
Followed by the fragment shader
in varOne;
out varTwo;
void main(){
varTwo = varOne;
}
Followed by the fragment shader
in varTwo(
out varThr;
void main(){
varThr = varTwo
}
And finally Followed by the fragment shader
in varThr;
out outVar;
void main(){
outVar = varThr;
}
Are the in and out the correct "concepts" to describe this behavior or should I be looking for another keyword(s)?
In OpenGL, you can attach multiple shaders of the same type to a program object. In OpenGL ES, this is not supported.
This is from the OpenGL 4.5 spec, section "7.3 Program Objects", page 88 (emphasis added):
Multiple shader objects of the same type may be attached to a single program object, and a single shader object may be attached to more than one program object.
Compared with the OpenGL ES 3.2 spec, section "7.3 Program Objects", page 72 (emphasis added):
Multiple shader objects of the same type may not be attached to a single program object. However, a single shader object may be attached to more than one program object.
However, even in OpenGL, using multiple shaders of the same type does not work they way you outline it in your question. Only one of the shaders can have a main(). The other shaders typically only contain functions. So your idea of chaining multiple shaders of the same type into a pipeline will not work in this form.
The way this is sometimes used is that there is one (or multiple) shaders that contain a collection of generic functions, which only needs to be compiled once, and can then be used for multiple shader programs. This is comparable to a library of functions in general programming. You could call this, using unofficial terminology, a "library shader".
Then each shader program has a single shader of each type containing a main(), and that shader contains the specific logic and control flow for that program, while calling generic functions from the "library shaders".
Following the outline in your question, you could achieve something similar with defining a function in each shader. For example, the first fragment shader could contain this code:
void shaderOne(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Second shader:
void shaderTwo(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Third shader:
void shaderThr(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Then you need one shader with a main(), where you can chain the other shaders:
in vec4 varOne;
out vec4 outVar;
void main() {
vec4 varTwo, varThr;
shaderOne(varOne, varTwo);
shaderTwo(varTwo, varThr);
shaderThr(varThr, outVar);
}
Generate your shaders. That's what pretty much all 3D engines and game engines do.
In other words they manipulate text using code and generate source code at runtime or build time.
Sometimes they use GLSL's preprocessor. Example
#ifdef USE_TEXTURE
uniform sampler2D u_tex;
varying vec2 v_texcoord;
#else
uniform vec4 u_color;
#endif
void main() {
#ifdef USE_TEXTURE
gl_FragColor = texture2D(u_tex, v_texcoord);
#else
gl_FragColor = u_color;
#endif
}
Then at runtime prepend a string to define USE_TEXTURE.
JavaScript
var prefix = useLighting ? '#define USE_TEXTURE' : '';
var shaderSource = prefix + originalShaderSource;
Most engines though do a lot more string manipulation by taking lots of small chunks of GLSL and combining them with various string substitutions.

OpenGL 3.3 - How to change tesselataionlevel during run time?

How can I change the tesselation leveln during runtime?
My only idea is to create a bufferobject with only one variable, which I have to pass through... Are there any better solutions?
I have a tesselation control shader file which works fine:
[...]
void main()
{
if(gl_InvocationID==0)
{
gl_TessLevelInner[0]= 5.0;
gl_TessLevelOuter[0]=5.0;
gl_TessLevelOuter[1]=5.0;
gl_TessLevelOuter[2]=5.0;
}
gl_out[gl_InvocationID].gl_Position =gl_in[gl_InvocationID].gl_Position;
}
You can pass the tessellation values as uniforms or (as the values are constant for each draw call) bypass the tessellation control shader altogether. If no TCS is linked to your shader program, the values supplied with -
GLfloat outer_values[4];
GLfloat inner_values[2];
// outer_values and inner_values should be set here
glPatchParameterfv​(GL_PATCH_DEFAULT_OUTER_LEVEL​, outer_values​​);
glPatchParameterfv​(GL_PATCH_DEFAULT_INNER_LEVEL​, inner_values​​);
will be used instead. In this case the tessellation evaluation shader uses the values output from the vertex shader.

How do I pass different uniform vec4 to shader each time call glDrawElements?

As title said, how do i pass different uniform vec4 (or something else) value to shader each time call glDrawElements? Is posible to do like this:
Shader:
uniform vec4 material_ambident;
void main(void)
{
// Do somethings
}
and render() like this:
glUseProgram(program);
glUniform4fv(unf_matrial_ambident, 2, &float_array[0]);
// Bind buffer or somethings ...
glDrawElements(..);
glUniform4fv(unf_matrial_ambident, 2, &another_float_array[0]);
// Bind another buffer
glDrawElements(..);
Yes, you can change uniforms between drawing batches, in the exact way as you think.

Attaching multiple shaders of the same type in a single OpenGL program?

In reading the OpenGL specs, I have noticed throughout that it mentions that you can include multiple shaders of the same kind in a single program (i.e. more than one GL_VERTEX_SHADER attached with glAttachShader). Specifically in OpenGL 4.2, §2.11.3, Program Objects: "Multiple shader objects of the same type may be attached to a single program object...".
OpenGL pipeline programs and subroutines might apply here, but this was defined before those existed (in fact it goes back to the 2.1 spec, §2.15.2) so I am looking for a pre-GL4 example of this idea. When I did some simple testing, I found that including more than one void main() caused linking errors. Is anyone aware of a practical example where this is used?
You can put common functions in separate shader. Then compile it only once, and link in multiple programs.
It's similar how you compile your cpp files only once to get static or shared library. Then you link this library into multiple executable programs thus saving compilation time.
Let's say you have complex lighting function:
vec3 ComputeLighting(vec3 position, vec3 eyeDir)
{
// ...
return vec3(...);
}
Then for each of shader where you want to use this functionality do this:
vec3 ComputeLighting(vec3 position, vec3 eyeDir);
void main()
{
vec3 light = ComputeLighting(arg1, arg2);
gl_FragColor = ...;
}
Then you compile separately common shader and your main shader. But do the compilation of common shader only once.
I found that including more than one void main() caused linking errors
For each shader stage there must be only a main entry function.
a practical example where this is used (pre-GL4)?
You can declare a function in a shader source and not define it, and at linking time you can provide a definition from another shader source (very similar to c/c++ linking).
Example:
generate_txcoord.glsl:
#version 330
precision highp float;
const vec2 madd = vec2(0.5, 0.5);
vec2 generate_txcoord(vec2 v)
{
return v * madd + madd;
}
vertex.glsl:
#version 330
precision highp float;
in vec2 vxpos;
out vec2 out_txcoord;
vec2 generate_txcoord(vec2 vxpos); // << declared, but not defined
void main()
{
// generate 0..+1 domain txcoords and interpolate them
out_txcoord = generate_txcoord(vxpos);
// interpolate -1..+1 domain vxpos
gl_Position = vec4(vxpos, 0.0, 1.0);
}