unity shader 学习笔记(一)
Unity3D Shader 可编程着色器
常用模板:(这里说明Unlit,standard surface 另算)
这里的着色器只能实现最基本的功能,即放置贴图Texture,以及通过Tiliing和Offset进行调整
// Unlit类型的着色器写在 Pass 通道内,一个显示效果可用多个 Pass 通道叠加表示
Shader "MyShader/NewUnlitShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {} // 贴图
}
SubShader // 着色器都写在 SubShader 里面
// 可以存在多个SubShader,但一个材质最后只能按先后顺序采用一种SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass // Unlit类型的着色器写在 Pass 通道内,一个显示效果可用多个 Pass 通道叠加表示
{
CGPROGRAM
#pragma vertex vert // 顶点着色器
// #pragma geometry geo// 几何着色器
#pragma fragment frag // 片段着色器
#include "UnityCG.cginc"
struct appdata // 传入给顶点着色器的数据
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f // 顶点(V)传入给片段(f)的
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
// 顶点着色器,将处理过后的顶点数据输出给片段着色器
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); // 坐标变换。又物体自身坐标变为裁剪坐标
o.uv = TRANSFORM_TEX(v.uv, _MainTex); // TRANSFORM_TEX方法比较简单,
// 就是将模型顶点的uv和Tiling、Offset两个变量进行运算,计算出实际显示用的定点uv。
// 参考:https://blog.csdn.net/u010133610/article/details/78789940
return o; // 传递给片段着色器
}
// 片段着色器
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv); // 对贴图进行采样,得到顶点对应(UV)的颜色
return col; // 输出颜色值
}
ENDCG
}
}
}
顶点着色器
//声明
#pragma vertex vert
//传入传出数据
struct appdata // 传入给顶点着色器的数据
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f // 顶点(V)传入给片段(f)的
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
几何着色器
几何着色器的声明可放在顶点着色器和片段着色器之间(也可以打乱顺序),比如:
#pragma vertex vert // 顶点着色器
#pragma geometry geo// 几何着色器
#pragma fragment frag // 片段着色器
顶点数据会最先进入顶点着色器,然后经过几何着色器到片段着色器。如果没有编写几何着色器则直接进入片段着色器(如上例代码片段)
若有几何着色器则可写成如下最简单的形式:
// 参考: https://www.cnblogs.com/Firepad-magic/p/10698749.html
Shader "ShaderDemo/SimplePoint"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
//-------声明几何着色器
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//-------顶点向几何阶段传递数据
struct v2g {
float4 vertex:SV_POSITION;
float2 uv:TEXCOORD0;
};
//-------几何阶段向片元阶段传递数据
struct g2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2g vert(appdata v)
{
v2g o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//-------静态制定单个调用的最大顶点个数
[maxvertexcount(3)]
void geom(triangle v2g input[3], inout TriangleStream<g2f> outStream) {
for (int i = 0; i < 3; i++) {
g2f o = (g2f)0;
o.vertex = input[i].vertex;
o.uv = input[i].uv;
//-----将一个顶点添加到输出流列表
outStream.Append(o);
}
//-------restart strip可以模拟一个primitives list
outStream.RestartStrip();
}
fixed4 frag(g2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
这份代码最后的效果与之前一样,即这里的几何着色器函数 geom 没有实现特殊功能。关于几何着色器的描述可参考 https://www.cnblogs.com/Firepad-magic/p/10698749.html
几何着色器的输入输出为:
triangle v2g input[3], inout TriangleStream outStream
其中输入输出类型均可自己设置。
输入和输出都是图元类型,输入可以点,也可以是三角形,输出同样有多种类型。
此外还要指明输出多大顶点数
[maxvertexcount(3)]
这里几何着色器输入一个三角形即三个顶点,输出一个三角形,最大输出顶点数也是三个即一个三角形,所以这里既没有增加顶点也没有减少顶点。
片段着色器
// 声明
#pragma fragment frag
输入为顶点着色器或者几何着色器传入过来的数据
输出为SV_Target,通常是(fixed4)颜色值
此次shader示例图: