笔记:OpenGL SuperBible - Shaders 2

本文深入探讨了OpenGL中如何通过顶点着色器进行数据传递,包括顶点属性的定义及使用,以及如何从一个着色器阶段传递数据到下一个阶段。此外还介绍了接口块的概念及其在着色器间数据交换中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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. 









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值