How to pass data from shader to shader in OpenGL
A vertex shader receives its input data from a vertex attribute. But how does a fragment shader gets its data? Data is passed from shader to shader by using the in and out keywords.
You create an output shader variable by using the out keyword. The out variable in one shader provides the input data to the next shader declared as an in variable. The only condition is that both of these variables must have the same name.
I know, this is a bit confusing so let me show you with an example.
Both shaders below have a variable with the same name out_color. However, in the vertex shader this variable is declared with an out qualifier. Meaning that it will provide data to the next shader.
Vertex Shader
#version 450 core
//color is an input vertex attribute
layout (location =0) in vec4 color;
//out_color is an output variable that will be sent to the next shader
out vec4 out_color;
void main(){
//...Shader stuffs here
//output a color to the fragment shader through out_color;
out_color=vec4(1.0,0.0,0.0,1.0);
}
In the fragment shader below, the out_color variable is declared with an in qualifier, meaning that it receives data from the previous shader.
Fragment Shader
#version 450 core
//input from the vertex
in vec4 out_color;
//output to the framebuffer
out vec4 color;
void main(){
//...Shader stuffs here
//assign the output data to the framebuffer with the color data from the vertex shader
color=out_color;
}
Sending data through variables is quite simple. But what if you want to send data in arrays or structures from shader to shader? To achieve this, you can group variables into an Interface Block.
The declaration of an Interface Block is similar to a structure, except that you use the in/out keyword declarations. For example, the vertex shader below has an interface block called COLOROUT. This block contains variables just like an structure would and is declared as out.
Vertex Shader
#version 450 core
//color is an input vertex attribute
layout (location =0) in vec4 color;
//declare COLOROUT as an output interface block
out COLOROUT{
vec4 color; //send color to next stage
}colorout;
void main(){
//...Shader stuffs here
//output a color to the fragment shader through outcolor;
outcolor.color=vec4(1.0,0.0,0.0,1.0);
}
if you noticed, the interface block has both a block name COLOROUT (uppercase) and an interface name colorout (lowercase). Interface blocks are matched between stages using the Block name, (COLOROUT in our example). And they are referenced in the shaders using their instance names.
For example, in the fragment shader below, the data coming in from the vertex shader is matched with the block name COLOROUT. However, within the fragment shader, the block is referenced with a different instance name.
Fragment Shader
#version 450 core
//declare COLOROUT as an input interface block
in COLOROUT{
vec4 color; //send color to next stage
}fragmentColorIn;
//output to the framebuffer
out vec4 color;
void main(){
//...Shader stuffs here
//assign the output data to the framebuffer with the color data from the vertex shader
color=fragmentColorIn.color;
}
So, that is how you pass data from shader to shader. Enjoy!
PS. Sign up to my newsletter and get OpenGL development tips.