内容会持续更新,有错误的地方欢迎指正,谢谢!
渲染流程的任务:从一个三维的场景出发,渲染出一张二维的图像。
《Real-Time Rendering》中将渲染流程分成三个阶段:应用阶段、几何阶段、光栅化阶段。
主要负责顶点坐标变换、屏幕映射。
顶点坐标变换:模型坐标—>世界坐标—>观察坐标—>裁剪坐标—>屏幕坐标
MVP矩阵能将顶点从模型空间转换到裁剪空间。顶点着色器(有多少个顶点就会运行多少次)的最基本的任务就是通过MVP矩阵(模型-视图-投影矩阵)把顶点坐标从模型空间转换到裁剪空间中。从裁剪空间到屏幕空间是Unity自动完成的。
投影矩阵:投影矩阵并没有进行真正的投影,而是为后面真正的投影做准备。投影是个降维的过程,从三维降到二维,但真正的投影发生在后面的屏幕映射中,通过齐次除法获得二维坐标。
通过三角形设置和遍历计算每个图元覆盖了哪些像素:这时三维模型已经投影到了二维平面上,但屏幕是一个个小的像素格子,光栅化就是在选格子嘛。
三角形设置:计算光栅化一个三角网格所需的信息,它的输出是为下一步骤做准备。
三角形遍历:找到哪些像素被三角网格覆盖的过程。对应像素会生成一个片元,而片元中的状态是对三个顶点的信息进行插值得到的。
为这些像素计算它们的颜色:光栅化后得到了格子,要搞上颜色,且没法将一个格子一半涂成白色一半涂成黑色,所以我们追求高像素屏幕,像素越高,效果越好。这时候会用到片元着色器(有多少个像素就会运行多少次)负责给每个像素上色。
各种测试用于决定每个片元的可见性,涉及了很多测试工作。比如:模板测试(限制渲染区域)、深度测试(不小于深度缓冲区中该片元的深度值就舍弃该片元)等测试。如果一个片元通过了所有测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行混合,最后再写入颜色缓冲区。也就是将片元的颜色值一个个地堆叠起来。
MipMap这个东西在二维比较常见,三维通常会用到LOD。
MipMap:给一张图通过图像处理自动生成多张低分辨率的图。为了解决图像无限缩小(960w平方公里的图片相对于你手机来说,那就是无限缩小)引起的失真问题。
LOD:层次细节,对同一个物体,就是它根据离摄像机的远近来使用不同的模型。不过,LOD分几个级别,美术就得做几套资源给你,不像MipMap一样电脑帮你自动生成。
虽然是一个经验模型,但已经能满足大多数的需求了,很常用。
公式:
C light是入射光线的颜色和强度
M specular是材质的高光反射系数
n是法线方向
h是由视角方向v和光照方向l 共同决定的,是一个半角向量
n和h做点积。
法线贴图呈现为蓝紫色,美术可以用软件生成。法线贴图的每个像素的RGB存的是模型法线的XYZ。若要实现外表凹凸不平的效果,常用的方法是使用一张法线贴图来修改模型表面的法线,以便为模型提供更多的细节,这种方法又被称为法线映射。
另外,渐变纹理(又叫坡度图)可用于渲染卡通风格;遮罩纹理可给模型增加更多的细节,让其某些地方看起来更亮一些,有些地方更暗一些。
Unity Shader的基本结构:根目录、Property属性、 SubShader子着色器、Fallback回滚。
其中,一个SubShader中可以有多个Pass,但Pass数目过多,会造成渲染性能降低,因为一个Pass定义了一次完整的渲染流程。
SubShader可以理解成由Tags(标签:告诉Unity怎样渲染这个对象)和RenderSetup(渲染状态设置:是否开启深度测试等)和Pass三部分组成。
在材质面板上显示属性的Shader代码:(注意a2v和v2f这两个结构体的使用)
Shader"Unity Book/Chapter5/Simple Shader"
{
Properties
{
_Color("Color Tint",Color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//在Cg代码中,我们需要定义一个与属性名称和类型都匹配的变量
uniform fixed4 _Color;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
fixed3 color : COLOR0;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
}
前言:
G-buffer:所有物体在不进行光照运算的情况下被绘制,然后对每个像素生成一组数据,这些数据包括位置、法线、高光颜色等。
正题:
所有的渲染路径的核心都是光照的处理。相比较逐顶点光照,游戏开发者更喜欢逐像素光照,但逐像素光照有一个显著的缺点:每个光源会让每个在它光照范围的物体增加一个渲染批次,所以才会有一个物体最多受4个光源影响的限制。
所以,延迟渲染是光照问题的救星!
那到底采用哪个?