可编程管线Shader教程:顶点和片段着色器程序
这个教程将带你学习如何自定义一个Unity顶点和片段着色器,在此之前,你可以先参阅ShaderLab的基础篇:《Getting Started tutorial》,如果你想编写一个能与光线交互的shader,那么你可以参阅这篇文章:《Surface Shaders》
开始前我们先概述一下shader的框架:
Shader "MyShaderName" {
Properties {
// ... properties here ...
}
SubShader {
// ... subshader for graphics hardware A ...
Pass {
// ... pass commands ...
}
// ... more passes if needed ...
}
SubShader {
// ... subshader for graphics hardware B ...
}
// ... Optional fallback ...
FallBack "VertexLit"
}
顶点和片段程序
在ShaderLab开发中使用Cg/HLSL
shader通常使用Cg/HLSL程序语言编写,Cg和HLSL实际上是同一种语言(Cg语言是Microsoft和NVIDIA相互协作在标准硬件光照语言的语法和语义上达成了一致),所以我们可以交换使用这两种语言。
Pass {
// ... the usual pass state setup ...
CGPROGRAM
// compilation directives for this snippet, e.g.:
#pragma vertex vert
#pragma fragment frag
// the Cg code itself
ENDCG
// ... the rest of pass setup ...
}
Shader "Tutorial/Display Normals" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR0;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.color = v.normal * 0.5 + 0.5;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4 (i.color, 1);
}
ENDCG
}
}
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// ...
ENDCG
全部Cg 代码将在 CGPROGRAM 和 ENDCG 关键字之间编写。#pragma 将声明开始编译指令的语句。
其中#pragma vertex name 将告诉程序这里包含了一个顶点着色器
#pragma fragment name 将告诉程序这里包含了一个片段着色器
以下编译指令是只是纯 Cg 代码。它告诉程序包含了一个内置的 Cg 文件(文件里包含了我们需要的函数):
#include "UnityCG.cginc"
UnityCG.cginc 文件包含常用的声明和函数,这样我们的着色器可以保持一个比较SMALL的状态 (参见Shader include files页面的详细信息)。我们将从该文件使用 appdata_base 结构。当然,我们也可以直接在当前shader定义,这样就不用引入这个文件。
接下来,我们定义"vertex to fragment"结构 (这里命名为 v2f):v2f表示:顶点到片断程序的信息传递。这里我们传递的是位置和颜色的参数。顶点着色器将计算color并且输出给片段着色器。
我们继续通过定义顶点程序-vert函数。我们计算位置信息并且输出,输入法线作为color:o.color = v.normal * 0.5 +0.5;(这里为什么是*0.5+0.5呢?因为法线的值为-1到1,而color的值为0到1,为了让他们的值能规范匹配,否则会报错)。
接下来,我们定义一个片段程序-用于输出计算出来的颜色和1作为alpha component。
fixed4 frag (v2f i) : SV_Target
{
return fixed4 (i.color, 1);
}
就这样,我们的shader就完成了,虽然很简单,但是对于可视化网格法线是非常有用的。
当然,这个shader并无法响应灯光,这也是有趣的地方。与灯光相关,可以参考Surface Shader。
在Cg代码中使用属性
当你在shader中定义属性,你可以给它们命名类似:_Color或者_MainTex。要使用它们,你就必须要定义一个变量和对应的名称及类型。Unity会自动设定具有名称与属性匹配的Cg变量。
下面是一个关于颜色调节纹理的完整shader,当然你同样可以轻易的在纹理合成器中调用,但这里主要是为了SHOW一下:如何在Cg中使用属性。
Shader "Tutorial/Textured Colored" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_MainTex ("Texture", 2D) = "white" { }
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 texcol = tex2D (_MainTex, i.uv);
return texcol * _Color;
}
ENDCG
}
}
}
fixed4 _Color;
sampler2D _MainTex;
总结(终于要结束了)
在这篇译文中,我们SHOW了如何自定义着色器,简单几步就写出了一个shader程序,例子虽然简单,但万变不离其宗,你依然能基于此写出更加复杂绚丽的shader程序,本篇可以充分帮助你利用unity来优化渲染。
翻译自官方教程:《Shaders: Vertex and Fragment Programs》
译者:优三帝同学 2016.02.29 原帖地址:https://www.u3dc.com/archives/2152
Unity学习QQ交流群(新):139457522 (加群备注:Unity)
– – 帖子里是一堆超链? – – 貌似都点不了