第五章:渲染流水线
5.1 核心模块
5.2 Shader中如何设置顶点着色器?
关于POSITION和TEXCOORD0,我这里先不做介绍,我们可以认为它是一个已经实现了的变量(在这里称为语义)。UNITY引擎在底层做了很多工作。让你可以轻易的拿到顶点的位置和uv。请注意,这个时候,它是一个引用,是一个指针。它会直接指向这个”3D对象”的顶点位置和贴图。你可以对它为所欲为。
怎么为所欲为呢?
我们看图5-2。这张图非常详细,我们的渲染管线,也就是着色器(不是固定管线,注意区分两者的关系)。可以操作的两个地方,一个叫做顶点着色器(vertex shader)另外一个叫做片元着色器(像素着色器 fragment shader)。
在前面我们曾经提到过surf,其实是像素着色器的一个封装操作,你可以把void surf函数当成是fragment的一部分。主要给新手用的。高手一般不会喜欢用surf。
我们把从cpu中取得的顶点位置和uv传入到顶点着色器。我们做了一个操作。
我们让顶点中的y分量(一个顶点由x,y,z描述)以sin函数进行变化。
其实,在你大脑里就可以想象出这样一个画面了,一个浪的画面。
到这一步。其实你能想到,pc也能想到,它可以实现这个过程了。
但是...它仅仅只是在计算中实现了顶点的这种迁移。它无法光栅化让你去看到这种波动。
这是为什么呢?
你可能需要参考第六章讲的一个新的问题:空间变换的问题。
现在我提前告诉你答案。
这一步我们修改了存在显存中的顶点的y的数据。
这个时候的模型处于一个叫模型空间的世界。它对外不可见。我们需要通过一种矩阵变化的高位魔法去将它从模型空间转移到我们的观察空间(也叫裁剪空间,你可以认为是3D中的摄像机<视锥体>对它的裁剪)之后我们才能看得到。
而这个过程其实比较复杂。但是Unity提供了一个一步到位的函数:
我们设置完了数据之后,通过return(其实Unity引擎以及opengl或者directx等图形接口已经做了很多操作)将存在于顶点着色器的数据发送给片元着色器。
就...完成了顶点变形的工作。
5.3 Shader中如何设置片元(像素)着色器?
在顶点着色器里面,我们定义了一个新的v2f结构体,然后对v2f结构体赋值,传递给片元着色器。
片元着色器对颜色进行一个赋值,然后再返回出来,搞定。
以下是源码:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Unlit/t2"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
// #pragma multi_compile_fog
#include "UnityCG.cginc"
struct fromCpu
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(fromCpu v)
{
v2f o;
v.vertex.y = sin(v.vertex.x + _Time.y);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
5.4 顶点着色函数和片元着色函数真的叫做vert和frag吗?
5.5 这串代码的效果太丑了,我们做一些修改,比如加个色