1
0
mirror of https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git synced 2025-08-23 12:45:29 +08:00
Files
LearnOpenGL-CN/01 Getting started/05 Shaders.md
2015-06-23 17:18:54 +08:00

99 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

本文作者JoeyDeVries由codeman001翻译自[http://learnopengl.com](http://learnopengl.com/#!Getting-started/Shaders)
##着色器
在[Hello Triangle](https://github.com/Geequlim/LearnOpenGL-CN/blob/master/01%20Getting%20started/04%20Hello%20Triangle.md) 中已经提到着色器是在GPU上运行的小程序这些程序负责处理图形渲染管线的特定阶段简单来说着色器也是一个处理输入输出的程序。着色器是非常孤立执行的程序彼此之间没有太多的交互
在前面的教程中我们大致介绍了表面着色器和如何正确使用它们。接下来我们讲接触更加流行的OpenGL着色语言
###GLSL
GLSL是写法类似C语言GLSL是专门针对图形以及向量和矩阵变化设计的。着色器通常开始生命一个版本信息然后是输入、输出列表以及常量和入口函数main函数每个着色器都是在入口函数处来处理输入参数。然后输出结果。
着色器通常具有以下结构:
#version version_number
in type in_variable_name;
in type in_variable_name;
6.2 Types 52
out type out_variable_name;
uniform type uniform_name;
int main()
{
// Process input(s) and do some weird graphics stuff
...
// Output processed stuff to output variable
out_variable_name = weird_stuff_we_processed;
}
所谓的顶点着色器就讲顶点属性作为输入的着色器顶点属性的个数主要受限于硬件实现OpenGL的保证总有至少16个四分量的顶点可以使用但是硬件可能个多些可以通过查询**GL_MAX_VERTEX_ATTRIBS**
GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
这个结果最小返回16一般情况下使用
###类型
GLSL跟一般的编程语言一样定义了一些常用的数据类型基础类型比如int,float, double, uint and bool等还用两种我们在教程中经常用到的容器类型vectors(向量) matrices矩阵稍后会提到
####向量
一个向量可以包含1-4个分量分量的类型可以是上面我们提到的基础类型向量个类型名字规则如下
- vecn: 默认向量有个n浮点型分量.
- bvecn: 有n个bool分量.
- ivecn: 有n个整型分量.
- uvecn: 有n个无符号整型分量.
- dvecn: 有n个双浮点型分量.
大多数情况下我们使用vecn因为浮点型足够满足我们大多数需求
向量的分量可以通过vec.x来访问第一个分量同时可以使用.x,.y,.z,.w来访问一个向量的四个成员同样可以使用rgba来访问颜色值对应的向量纹理坐标则可以使用stpq来访问分量的值
向量的访问方式支持趣味性和扩展性被称为交叉混合性实例如下
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
可以使用任意组合来组成新向量同时也可以把维度小的向量放在高纬度向量的构造函数里来构成新的向量如下代码
vec2 vect = vec2(0.5f, 0.7f);
vec4 result = vec4(vect, 0.0f, 0.0f);
vec4 otherResult = vec4(result.xyz, 1.0f);
###输入和输出
着色器是运行在GPU上的小程序但是麻雀虽小五脏俱全也会有输入和输出来构成完整的程序GLSL使用in和out关键字来定义输入和输出每个着色器可以是这些关键字来指定输入和输出输入变量经过处理以后会得到适合下个处理阶段可以使用的输出变量顶点着色器和片段着色器有点小却别
顶点着色器接受特定格式的输入否则不能正确使用顶点着色器直接接受输入的顶点数据但是需要在CPU一边指定数据的对应的位置前面的教程可以到对位置0的输入location=0所以顶点着色器需要一个特定的声明来确定CPU和GPU数据对应关联关系
也可以使用*glGetAttribLocation*来查询对应的位置这样可以省略layout的声明但是我觉得可以是用layout声明比较好这也可以减少GPU的一些工作
对于片段着色器有个vec4的颜色作为特定的输出因为片段处理后最终是要生产一个颜色来显示的否则将输出黑色或白色颜色作为输出
如果我们想从一个着色器向另外一个发送数据我们需要在发送方定义一个输出然后再接收方顶一个输入同时保证这两个变量类型和名字是相同的
下面是一个实例来展示如何从顶点着色器传递一个颜色值跟片段着色器使用
***顶点着色器***
#version 330 core
layout (location = 0) in vec3 position; // The position variable has attribute position 0
out vec4 vertexColor; // Specify a color output to the fragment shader
void main()
{
gl_Position = vec4(position, 1.0);
vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f);
}
***片段着色器***
#version 330 core
in vec4 vertexColor; // 从顶点着色器获得输入 (名字和类型都是一样的)
out vec4 color;
void main()
{
color = vertexColor;
}
可以看到在顶点着色器生命了一个向量*vertexColor* 有out修饰同时在片段着色器声明了一个*vertexColor* 使用in来修饰这样片段着色器就可以获取顶点着色器处理的*vertexColor*的结果了
根据上面shader可以得出下图的效果