1 渲染流水线
指的是CPU和GPU根据一系列的顶点数据和纹理等信息,最终转换成人眼可以识别的图像的过程。
1.1 渲染流程
《实时渲染》一书将渲染流程分成3个阶段:应用阶段、几何阶段、光栅化阶段。
1.1.1 应用阶段
这个阶段由CPU负责实现,应用准备好模型、光源等渲染数据,设置好材质、纹理、Shader等渲染状态,然后输出为渲染所需的点、线、三角面等几何信息,即渲染图元,这些渲染图元将被传递给下一阶段–几何阶段。
1.1.2 几何阶段
这个阶段由GPU负责实现,处理绘制的几何相关事情,其中一个重要任务就是把顶点坐标变换到屏幕空间,然后交给光栅器处理。同时输出顶点深度值、着色等信息,传递给下一阶段。
顶点着色器就是运行在几何阶段。
1.1.3 光栅化阶段
这个阶段也是在GPU上运行,使用上个阶段传递的数据来产生屏幕上的像素,并渲染出最终图像。
片元着色器运行在光栅化阶段。
1.2 GPU流水线
GPU流水线就是GPU渲染的过程,包含几何阶段和光栅化阶段。下图展示了GPU流水线的不同阶段实现。
如上图所示,颜色表示了不同阶段的可配置性或可编程性。绿色表示该流水线阶段是完全可编程控制的,黄色表示可配置但不可编程,蓝色表示由GPU固定实现,开发者不可控制。
实线表示该Shader必须由开发者编程实现,虚线表示该Shader是可选的。
1.2.1 顶点着色器
顶点着色器是GPU流水线中几何阶段的第一步,它的输入来自CPU。处理单位是顶点,每个顶点都会调用一次顶点着色器,它们之间没有联系,互相独立,GPU可以并行化处理每个顶点,因此速度很快。
顶点着色器的工作主要是:坐标变换和逐顶点光照(计算顶点颜色)。坐标变换就是对顶点的坐标(位置)进行某种变换,这在顶点动画中非常有用。例如,通过改变顶点位置来模拟水面、布料等。但无论怎样改变,一个最基本的顶点着色器必须完成的工作是,把顶点坐标从模型空间转换到齐次裁剪空间(即透视空间)。
1.2.2 片元
一个片元并不是真正意义上的像素,而是用于计算每个像素最终颜色的状态集合,这些状态包括它的屏幕坐标、深度,以及其它从几何阶段输出的顶点信息,例如法线、纹理坐标等。
1.2.3 片元着色器
用于实现逐片元的着色操作,输出一个或多个颜色值。
2 Unity Shader 基础
在Unity中Shader总是和材质配合使用。
2.1 使用流程
- 创建一个材质;
- 创建一个Unity Shader,并赋给上一步创建的材质;
- 把材质赋给要渲染的对象;
- 在材质面板中调整Unity Shader的属性,得到满意效果;
2.2 基本结构
Properties语义块包含了一系列属性,这些属性将会出现在材质面板中。
Unity Shader的基本结构如下所示。
Shader "MyShader" {
Properties {
// 所需的各种属性
}
SubShader {
// 真正意义上的Shader代码
}
SubShader {
// 和上一个SubShader类似
}
}
2.3 Cg/HLSL语义
Unity支持的语义在不同阶段的含义如下
2.3.1 顶点着色器输入时
语义 | 描述 |
---|---|
POSITION | 模型空间中的顶点位置,通常是float4类型 |
NORMAL | 顶点法线,通常是float3类型 |
TANGENT | 顶点切线,通常是float4类型 |
TEXCOORD0 | 该顶点的纹理坐标,TEXCOORD0表示第一组,通常是float2或float4类型 |
COLOR | 顶点颜色,通常是fixed4或float4类型 |
2.3.2 从顶点着色器传递数据给片元着色器时
语义 | 描述 |
---|---|
SV_POSITION | 裁剪空间中的顶点坐标 |
COLOR0 | 用于输出第一组顶点颜色,不是必需 |
COLOR1 | 用于输出第一组顶点颜色,不是必需 |
TEXCOORD0~TEXCOORD7 | 用于输出纹理坐标,不是必需 |
2.3.3 片元着色器输出时
语义 | 描述 |
---|---|
SV_Target | 输出值将会存储到渲染目标(render target)中 |
3 基础光照
渲染包括两大部分:一个像素是否可见?这个像素是什么颜色?而颜色很大程度上依赖于光照。光照模型就是用来决定在一个像素上怎样计算光照。
3.1 标准光照模型
标准光照模型只关心直接光照,也就是直接从光源发射出来照射到物体表面后,经过一次反射直接进入摄像机的光线。
基本方法是,把进入到摄像机内的光线分为4个部分,每个部分使用一种方法来计算它的贡献度。这4个部分是。
- 自发光。描述当给定一个方向时,表面本身会向该方向发射多少辐射量。
- 高光反射。描述当光线从光源照射到模型表面,会在完全镜面反射方向散射多少辐射量。
- 漫反射。描述当光线从光源照射到模型表面时,会向每个方向散射多少辐射量。
- 环境光。描述其它所有的间接光照。
3.1.1 自发光
自发光的计算很简单,只需要在片元着色器输出最后的颜色之前,添加上材质的自发光颜色即可。
3.1.2 环境光
在Shader中,只需要通过Unity
的内置变量UNITY_LIGHTMODEL_AMBIENT
就可以得到环境光的颜色和强度信息。
3.1.3 漫反射
在漫反射中,视角位置不重要,因为反射完全随机,可以认为在任何反射方向上的分布都一样。但是,入射光线的角度很重要。
漫反射部分的计算公式如下
C d i f f u s e = ( C l i g h t ⋅ M d i f f u s e ) m a x ( 0 , n ^ ⋅ l ^ ) C_{diffuse} = (C_{light} \cdot M_{diffuse}) max(0, \hat{n} \cdot \hat{l}) Cdiffu