shader是什么
现在我们开始走进shader, Shader 中文翻译 着色器,先来看一段wiki的介绍 计算机图形学领域中,着色器(英语:shader)是一种计算机程序,原本用于进行图像的浓淡处理(计算图像中的光照、亮度、颜色等),但近来,它也被用于完成很多不同领域的工作,比如处理CG特效、进行与浓淡处理无关的影片后期处理、甚至用于一些与计算机图形学无关的其它领域。 使用着色器在图形硬件上计算渲染效果有很高的自由度。尽管不是硬性要求,但目前大多数着色器是针对GPU开发的。GPU的可编程绘图管线已经全面取代传统的固定管线,可以使用着色器语言对其编程。构成最终图像的像素、顶点、纹理,它们的位置、色相、饱和度、亮度、对比度也都可以利用着色器中定义的算法进行动态调整。调用着色器的外部程序,也可以利用它向着色器提供的外部变量、纹理来修改这些着色器中的参数。
在早些时候,显示卡的每一项功能都是由固定硬件模块实现的。 比如实现光照、阴影、着色、等每一项工作都需要对应的集成电路来完成。 这样以来,可以实现的效果就非常有限,由于当时 PC 机并没有大规模流行, 真正需要显示卡的地方其实是图形工作站, 工作站的渲染工作类型相对固定,所以采用固定管线是可以胜任的,但随着个人PC的流行,采用固定管线的方案就逐渐被配抛弃了,当然这里面还有很多公司之间里的利益博弈。 是用固定管线并不意味着你不需要写代码了,只不过你编写程序的创造力受到的很大限制。对于这些功能你只能选择用或不用、无法有其他修改。 编程时需要把它们一个个串联起来, 实现一个复杂效果的过程,简直可以戏称为 “花式调开关”。固定管线被抛弃的另一个重要原因是,计算资源无法灵活配置,造成浪费。
打个比方说,你是一个老板。手下有 100 名工人。工厂有 3 种工作。“制作电饭煲” 、“制作微波炉” 、“制作台灯” ,这 3 种工作都有对应的厂区,因为无法预测未来工作每一种产品的订单量,所以你只能预先分配这些工人,一旦订单种类不均衡,便会出现有些厂区忙的要死,有些却被闲置的现象。 为了避免浪费,同时解放更多的功能,可编程管线诞生了。有了它厂区不再是固定的,而是当订单确定后,再组成一个个临时的厂区。 这样对于任何一种任务,都可以做到最大限度的提升效率,这种可以随机应变的 “厂区” 便是可编程管线。以前固定管线的所有功能,现在都可以通过编程来实现了,且编程带来的灵活性大大提高了渲染性能。 需要一种语言来控制这些 “工人” 组成临时的生产线,这便是着色器存在的意义。本文中提及的 GLSL 是一种在 OpenGL 中使用的着色器语言,但并不是唯一的着色器语言。 除了 GLSL 还有微软的 HLSL 和英伟达的 CG ,这些我们只要了解即可。 重点来了: 着色器被用来同时处理大量的数据,比如屏幕上的一整块像素群,或者一个模型结构的所有顶点。并行计算适用于这样的情况,而且当今的GPU也设计有多核结构来极大的提高处理效率。
兼容性
web页面长久以来以容易扩散,方便传播的优点著称,随着js引擎的越来强大,html5标准的统一,更加令人兴奋的是WebGL 1.0基于OpenGL ES 2.0,提供了3D图形的API[5]。让我们能够使用由JavaScript编写的句柄和OpenGL Shading Language(GLSL)编写的着色器代码组成程序运行在html5 canvas,而且兼容性也出奇的不错。为我们进行一端开发多端运行,创造了无限可能。如果你有想法,你都可以在ie10下跑一跑,使用第三方插件IEWebGL,(这里对于webgl2.0, 由于目前兼容性问题,暂不启用)
shader里有什么
顶点着色器处理每个顶点,将顶点的空间位置投影在屏幕上,即计算顶点的二维坐标。同时,它也负责顶点的深度缓冲(Z-Buffer)的计算。顶点着色器可以掌控顶点的位置、颜色和纹理坐标等属性,但无法生成新的顶点。顶点着色器的输出传递到流水线的下一步。如果有之后定义了几何着色器,则几何着色器会处理顶点着色器的输出数据,否则,光栅化器继续流水线任务。 像素着色器(英语:pixel shader)也叫片段着色器(英语:fragment shader),用于计算“片段”的颜色和其它属性,此处的“片段”通常是指单独的像素。最简单的像素着色器只有输出颜色值;复杂的像素着色器可以有多个输入输出[2]。像素着色器既可以永远输出同一个颜色,也可以考虑光照、做凹凸贴图、生成阴影和高光,还可以实现半透明等效果。像素着色器还可以修改片段的深度,也可以为多个渲染目标输出多个颜色。 对于图形流水线的一般描述
- 中央处理器(CPU)发送指令(编译的着色器程序)和几何数据到位于显卡内的图形处理器(GPU)。
- 顶点着色器执行几何变换和光照计算。
- 若几何着色器位于图形处理器内,它便会修改一些几何信息。
- 计算后的几何模型被三角化(分割为三角形)。
- 三角形被映射为2×2的像素块。
一个着色器程序分为两大部分,即 “顶点着色器” 与 “片元着色器” 简单来说,前者多用于模型构建,后者用于在光栅化时表现出更多细节,一个着色器程序必须同时包含这两部分,程序会先通过 “顶点着色器” 处理再交与 “片元着色器” 渲染细节 举个例子:比如你想绘制一个蓝色四面体,那就需要用到 8 个顶点 和 “蓝” 这两个参数。 其中 8 个顶点数据先传入 “顶点着色器” 这时一个四面体的模型便建立了,而 “蓝色” 这一参数属于纹理细节,将在 “片元着色器” 中被处理。
// 顶点着色器 .vsh
attribute vec4 position;
attribute vec4 color;
uniform mat4 u_ViewMatrix;
varying vec4 colorVarying;
void main(void) {
colorVarying = color;
gl_Position = position;
}
// 片段着色器 .fsh
varying lowp vec4 colorVarying;
uniform mat4 u_ViewMatrix;
void main(void) {
gl_FragColor = colorVarying;
}
内置变量:
- gl_Position 绘制区域顶点坐标
- gl_FragColor 依据顶点坐标进行绘制的颜色
存储限定字:
- const 编译时常量,或只读的函数参数
- attribute 由应用程序传输给顶点着色器的逐顶点的数据
- varying 由顶点着色器传输给片段着色器中的插值数据
- uniform 在图元处理过程中其值保持不变,由应用程序传输给着色器
图解存储限定字
变量类型
灵活定义和取值
mat4 m4 = mat4(1.0); 就表示单位矩阵,就是对角线为1.0,其他都为0的矩阵, 如果传入的数值大于1,又没有达到矩阵元素的数量,就会出错, 例如:
mat4(1.0,2.0)// mat4对象要有16个元素
- vec2,vec3,vec4的向量分量名分别为2维,3维,4维
| 分量访问符 | 符号描述 |
|---|---|
| (x,y,z,w) | 与位置相关的分量 |
| (r,g,b,a) | 与颜色相关的分量 |
| (s,t,p,q) | 与纹理坐标相关的分量 |
内置函数
语句
for循环的进行内联展开的限制
1. 只允许一个循环变量,循环变量必须是int或者float
2. 循环表达式必须是i++,i--, i+= 常量表达式 或 i-= 常量表达式(假设i为循环变量)
3. 条件表达式必须是循环变量与整型常量的比较
4. 在循环体内,循环变量不可被赋值