Passing data to the vertex shader
Vertex fetching (vertex pulling) provides inputs to
vertex shader, the first programmable stage in OpenGL pipeline.
In GLSL, the mechanism for getting data in and out of shaders is to declareglobal variables with the in and out storage qualifiers.
Vertex attributes are how vertex data is introduced into the OpenGLpipeline. To declare a vertex attribute, declare a variable in the vertexshader using the in storage qualifier.
The following code we declare the variable offset as an input attribute.
// "offset" is an input vertex attribute
layout (location = 0) in vec4 offset;
void main(void)
{
const vec4 vertices[3] = vec4[3](vec4( 0.25, -0.25, 0.5, 1.0),
vec4(-0.25, -0.25, 0.5, 1.0), vec4( 0.25, 0.25, 0.5, 1.0));
// Add "offset" to our hard-coded vertex position
gl_Position = vertices[gl_VertexID] + offset; }
The above code adds the variable offset as an input to vertex shader. The input will be filled automatically by vertex fetch stage. We can tell this stage what to fill the variable by using functions--glVertexAttrib*().
Prototype:
void glVertexAttrib4fv(GLuint index,
const GLfloat * v);
index is used to reference the attribute
v is apointer to the new data to put into the attribute.
layout (location = 0)
a layout qualifier, set the location of the vertex attribute to zero. This location is the value we’ll pass in index to refer to the attribute.
// Our rendering function
virtual void render(double currentTime)
{
const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f, _ 0.0f, 1.0f };
glClearBufferfv(GL COLOR, 0, color);
// Use the program object we created earlier for rendering
glUseProgram(rendering_program);
GLfloat attrib[] = { (float)sin(currentTime) * 0.5f, (float)cos(currentTime) * 0.6f,
0.0f, 0.0f };
// Update the value of input attribute 0
glVertexAttrib4fv(0, attrib);
// Draw one triangle
glDrawArrays(GL_TRIANGLES, 0, 3;
}
Passing Data from Stage to Stage
We can also send data from shader stage to shader stage using the same in and out keywords.
For example, if your vertex shader declares a variable called vs_color using the out keyword, it would match up with a variable named vs_color declared with the in keyword in the fragment shader stage.
Modify the vertex shader:
#version 410 core
// "offset" and "color" are input vertex attributes layout (location = 0) in vec4 offset;
layout (location = 1) in vec4 color;
// "vs_color" is an output that will be sent to the next shader stage out vec4 vs_color;
void main(void)
{
const vec4 vertices[3] = vec4[3](vec4( 0.25, -0.25, 0.5, 1.0),
vec4(-0.25, -0.25, 0.5, 1.0), vec4( 0.25, 0.25, 0.5, 1.0));
// Add "offset" to our hard-coded vertex position gl_Position = vertices[gl_VertexID] + offset;
//_Output a fixed value for vs_color
vs color = color;
}
the fragment shader:
#version 430 core
// Input from the vertex shader
in vec4 vs_color;
// Output to the framebuffer
out vec4 color;
void main(void)
{
// Simply assign the color we were given by the vertex shader // to our output
color = vs_color;
}
Interface Blocks
we can group together a number of variables into an interface block.
#version 410 core
// "offset" is an input vertex attribute layout (location = 0) in vec4 offset;
layout (location = 1) in vec4 color;
// Declare VS_OUT as an output interface block
out VS_OUT
{
vec4 color; // Send color to the next stage
} vs_out;
void main(void)
{
const vec4 vertices[3] = vec4[3](vec4( 0.25, -0.25, 0.5, 1.0),
vec4(-0.25, -0.25, 0.5, 1.0), vec4( 0.25, 0.25, 0.5, 1.0));
// Add "offset" to our hard-coded vertex position
gl_Position = vertices[gl_VertexID] + offset;
//_Output a fixed value for vs_color
vs out.color = color;
}
a block name (VS_OUT)
instance name (vs_out)
Interface blocks are matched between stages using the block name, but are referenced in shaders using the instance name.
#version 410 core
// Declare VS_OUT as an input interface block
in VS_OUT
{
vec4 color; // Send color to the next stage
} fs_in;
// Output to the framebuffer
out vec4 colour;
void main(void)
{
// Simply assign the color we were given by the vertex shader // to our output
color = fs_in.color;
}
Matching interface blocks by block name but allowing block instances tohave different names in each shader stage serves two important purposes: First, it allows the name by which you refer to the block to be different ineach stage, avoiding confusing things such as having to use vs_out in afragment shader, and second, it allows interfaces to go from being single items to arrays when crossing between certain shader stages, such as the vertex and tessellation or geometry shader stages as we will see in a shortwhile.
interface blocks are only for moving data from shaderstage to shader stage. (只能用于在shader之间交换数据) You can’t use them to group together inputs to the vertex shader or outputs from the fragment shader.