# 第三章 管线一览

## 本章我们会学到什么

• OpenGL管线的每个阶段做什么的
• 如果连接着色器和固定功能管线阶段
• 如果创建一个程式同时使用图形管线的每个阶段

## 顶点属性

``````#version 450 core

// '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;
}
``````

``````void glVertexAttrib4fv(GLuint index, const GLfloat* v);
``````

``````// 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.5,
(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);
}
``````

## 在着色器阶段间传递数据

``````#version 450 core

// 'offset' and 'colour' 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;
}
``````

``````#version 450 core

// Input from the vertex shader
in vec4 vs_color;

// Output to the framebuffer
out vec4 color;

void main(void)
{
// Simply assign the colour we were given by the vertex shader to our output
color = vs_color;
}
``````

### 数据块接口(Interface Blocks)

``````#version 450 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 colour;    // 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;
}
``````

``````#version 450 core

// Declare VS_OUT as an input interface block
in VS_OUT
{
vec4 colour;    // Send color to the stage
} fs_in;

// 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 = fs_in.color;
}
``````

## 细分曲面(Tessellation)

``````void glPatchParameteri(GLenum pname, GLint value);
``````

``````layout (vertices = N) out;
``````

``````#version 450 core

layout (vertices = 3) out;

void main(void)
{
// Only if I am invocation 0 ...
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
// Everybody copies their input to their output
gl_out[gl_InvocationID].gl_Position =
gl_in[gl_InvocationID].gl_Position;
}
``````

### 细分曲面引擎(The Tessellation Engine)

``````#version 450 core

layout (triangles, equal_spacing, cw) in;

void main(void)
{
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +
gl_TessCoord.y * gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position);
}
``````

``````void glPolygonMode(GLenum face, GLenum mode);
``````

`face`参数指明我们想影响哪个类型的多边形。因为我们想要影响所有东西，故我们设置它为`GL_FRONT_AND_BACK`.`mode`表明我们想要如何渲染多边形。我们想要渲染为线框模式(即直线)，我们将这个参数设置为`GL_LINE`。其他模式我们很快就会解释的。我们的三角形示例在使用细分曲面以及清单3.7、清单3.8的着色器之后，渲染结果如图示3.1:

figure3.1

``````#version 450 core

layout (triangles) in;
layout (points, max_vertices = 3) out;

void main(void)
{
int i;

for (i = 0; i < gl_in.length(); i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
}
``````

figure3.2

## 图元组装、修剪和光栅化(Primitive Assembly,Clipping, and Rasterization)

### 视口变换(Viewport Transformation)

``````void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
void glDepthRange(GLdouble nearVal, GLdouble farVal);
``````

formula3.1

### 剔除(Culling)

formula3.2

``````void glFrontFace(GLenum mode);
``````

`mode`可被设置为`GL_CW`或者`GL_CCW`(其中`GL_CW`表示顺时针，`GL_CCW`表示逆时针)。这被称为三角形的环绕方向(winding order)，顺时针和逆时针表示三角形顶点出现在窗体空间的次序。缺省情况下，环绕方向为逆时针，这意味着顶点次序为逆时针的三角形被认为是正面，顶点次序为顺时针的三角形被认为是背面。如果环绕方面被设置为`GL_CW`，那前面方程式中的a的含义在剔除过程中也就和前述相反。图示3.3以可观的方式展示方才所述。

figure3.3

### 光栅化

``````#version 450 core

out vec4 color;

void main(void)
{
color = vec4(sin(gl_FragCoord.x * 0.25) * 0.5 + 0.5,
cos(gl_FragCoord.y * 0.25) * 0.5 + 0.5,
sin(gl_FragCoord.x * 0.15) * cos(gl_FragCoord.y * 0.15),
1.0);
}
``````

figure3.3

`gl_FragCoord`是片段着色器可用的内置变量中的一个。不过，和其他着色器阶段一样，我们可以为片段着色器定义自定义的输入，这些输入会在光栅化前的任何一个阶段进行填充。比如，如果我们有一个简单的程式只有一个顶点着色器和片段着色器，我们可以从顶点着色器传递数据给片段着色器。

``````#version 450 core

// '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));
const vec4 colors[] = vec4[3](vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.0, 1.0, 0.0, 1.0),
vec4(0.0, 0.0, 1.0, 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[gl_VertexID];
}
``````

``````#version 450 core

// 'vs_color' is the color produced by the vertex shader
in vec4 vs_color;

out vec4 color;

void main(void)
{
color = vs_color;
}
``````

figure3.5

## 帧缓冲运算

### 像素运算

``````#version 450 core

layout (local_size_x = 32, local_size_y = 32) in;

void main(void)
{
// Do nothing
}
``````

## 使用OpenGL扩展(Extensions)

figure3.6

### 使用扩展增强OpenGL

``````const GLubyte* glGetStringi(GLenum name, GLuint index);
``````

``````int sb7IsExtensionSupported(const char* extname);
``````

• 将之前不合法的东西修正，可以根据OpenGL规范简单地移除一些限制。
• 添加可以传递给现有函数的标记或者扩展参数的值的范围。
• 扩展GLSL，添加新的功能、内置函数、变量或者数据类型。
• 添加全新的函数到OpenGL

``````#extension GL_ABC_foobar_feature : enable
``````

``````#define GL_ABC_foobar_feature 1
``````

``````#if GL_ABC_foobar_feature
// Use functions from the foobar extension
#else
// Emulate or otherwise work around the missing functionality
#endif
``````

``````#extension GL_ABC_foobar_feature : require
``````

``````typedef void
(APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);

PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback = NULL;
``````

``````#include <glext.h>
#include <glxext.h>
#include <wglext.h>
``````

``````void* sb7GetProcAddress(const char* funcname);
``````