Unity用CG来编写Shader,CG代码可以编译成OpenGL的Shader语言代码也可以编译成DirectX的Shader
Shader "Shader/TestShader" // Shader名字
{
// 1.Unity Shader会有一些盒子(POSITION、NORMAL、TEXCOORD0)可以存放任意的数据类型(float,float2,float3,float4)
// 2.盒子的名字是渲染管线所传送数据的描述,顶点Shader参数要严格按照盒子名字来绑定变量,当我们拿到盒子中该数据后,该盒子我们就可以自由使用了
// 3.通过shader函数参数变量,来绑定盒子(float4 vertex:POSITION或者定义结构绑定),这样渲染管线会将对应盒子的数据传到参数变量中
// 4.(重点)经过顶点Shader之后,这些盒子,除了SV_开头的盒子,其他盒子都可以由自己来管理,自己决定盒子存放什么样数据,也就是经过顶点Shader之后POSITION盒子中可以不存放坐标,可以存放想要的数据
// 5.顶点传给片元的数据都是经过三角形面的三个顶点插值计算而来,传递所使用哪些盒子可以自定义。
// 6.顶点Shader指定了哪些盒子,那么渲染管线插值完成以后,仍然把数据存放到对应盒子里面。片元着色Shader只要去对应盒子里去拿就可以了
Properties
{
// 变量名字("显示名字", 属性类型) = 默认值
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM // Cg代码的开始;
#pragma vertex vert // 告诉我们的编译器vert代码在哪里;
#pragma fragment frag // 告诉我们的编译器frag代码在哪里;
// Unity 封装Shader API;
#include "UnityCG.cginc"
#include "Lighting.cginc"
//盒子:1.POSITION:模型坐标,2.TEXCOORD0:纹理坐标,3.NORMAL法线坐标
//进入顶点Shader后,盒子中存放什么数据,由编程者自己控制
struct appdata
{
float4 vertex : POSITION; // 顶点Shader开始的时候, 模型顶点坐标
float2 uv : TEXCOORD0; // 顶点Shader开始的时候,纹理坐标
};
struct v2f //vertex to fragment,这个结构的数据插值后的结果传递给fragment shader
{
float2 uv : TEXCOORD1; //uv并不会直接传给frag,在管线中对uv插值,将插值后的uv数据传给frag // uv和TEXCOORD1(盒子)绑定,
float4 vertex : SV_POSITION;//vertex和SV_POSITION绑定
};
sampler2D _MainTex; //Texture
float4 _MainTex_ST; // 引擎写死的变量名字;Tilling和Offset
// 顶点Shader;
v2f vert (appdata v)//也可以这样写:v2f vert (float4 vertex:POSITION,float2 uv:TEXCOORD0)
{
v2f o;
// 坐标空间的转换;
o.vertex = UnityObjectToClipPos(v.vertex);
// (v.uv.xy * _MainTex_ST.xy + _MainTex.zw)
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
// 着色调用次数-----> 顶点调用次数;
// 着色好了,就把颜色,放到我们的SV_Target;
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
// 纹理采样:
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}