顶点:即组成模型三角面的点,包含(位置、法线、切线、纹路坐标、颜色)等信息。
顶点着色器主要是对顶点进行处理,可以经过矩阵变换实现平移、旋转、缩放等。还可以计算灯光等修改顶点颜色。
片元着色器是接收:顶点着色器传过来的数据,进行颜色像素颜色计算。顶点着色器里的值被传入片元着色器时会被进行一次插值计算。(比如顶点着色的颜色会被插值计算到对应三角形像素中)
我们来看一些示例:
一、固定颜色
Shader "MyShader/VFShaderTest" {
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainColor ("显示颜色", Color) = (1, 0, 0, 1)
}
SubShader
{
Pass
{
CGPROGRAM // CG语言的开始
// 编译指令 着色器名称 函数名称
#pragma vertex vert // 顶点着色器, 每个顶点执行一次
#pragma fragment frag // 片段着色器
// 导入头文件
#include "UnityCG.cginc"
// 声明属性变量, 必须与外部属性变量名称一致
fixed4 _MainColor;
// 顶点着色器
half4 vert(half4 vertexPos: POSITION): SV_POSITION
{
// 将局部坐标系下坐标转换为裁剪坐标系下坐标
return UnityObjectToClipPos(vertexPos);
}
// 片元着色器
fixed4 frag(): COLOR
{
return _MainColor;
}
ENDCG // CG语言的结束
}
}
FallBack "Diffuse"
![](https://i-blog.csdnimg.cn/blog_migrate/5b270d2096aa8c2623ce9c1b58669602.png)
二、光照
主要技术点,向量点乘得到一个向量在另一个向量投影。也就是两个向量越接近垂直值越小。以此判断来设置直射灯光面最亮。第一个是兰伯特光照,第二个是半兰伯特光照半兰伯特光照是在兰伯特光照基础上加0.5解决背面太暗的问题。
Shader "MyShader/VFShaderLight" {
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_DiffuseColor("漫反射颜色", Color) = (1, 0, 0, 1)
}
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM // CG语言的开始
// 编译指令 着色器名称 函数名称
#pragma vertex vert // 顶点着色器, 每个顶点执行一次
#pragma fragment frag // 片段着色器, 每个像素执行一次
// 导入头文件
#include "UnityCG.cginc"
// 声明属性变量, 必须与外部属性变量名称一致
fixed4 _DiffuseColor;
struct appdata // 顶点着色器输入结构体
{
half4 vertexPos: POSITION; // 局部坐标系下顶点坐标
half3 vertexNormal: NORMAL; // 局部坐标系下顶点法线向量
};
struct v2f // 顶点着色器输出结构体
{
half4 clipPos: SV_POSITION; // 裁剪坐标系下顶点坐标
half3 worldNormal: Normal; // 裁剪坐标系下顶点法线向量
half3 worldLightDir : TEXCOORD0; // 光照方向
};
// 顶点着色器
v2f vert(appdata data)
{
v2f o;
o.clipPos = UnityObjectToClipPos(data.vertexPos); // 等价于: mul(UNITY_MATRIX_MVP, data.vertexPos)
o.worldNormal = UnityObjectToWorldNormal(data.vertexNormal); // 将局部坐标系下法线转换为世界坐标系下法线
o.worldLightDir = UnityWorldSpaceLightDir(data.vertexPos); // 计算世界坐标系下顶点指向光源的向量
return o;
}
// 片元着色器
fixed4 frag(v2f input) : COLOR
{
//点乘得到一个向量在另一个向量投影。也就是两个向量越接近垂直值越小
half factor = dot(input.worldNormal, input.worldLightDir);
//return _DiffuseColor * factor + UNITY_LIGHTMODEL_AMBIENT; // Lambert光照模型
return _DiffuseColor * (0.5 * factor + 0.5) + UNITY_LIGHTMODEL_AMBIENT; // 半Lambert光照模型
}
ENDCG // CG语言的结束
}
}
FallBack "Diffuse"
}
![](https://i-blog.csdnimg.cn/blog_migrate/42a1a6e5624516177b21d00e9ca31434.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ee0337ede8af91ea3c16c028220b0fb8.png)
三、贴图
Shader "MyShader/VFShaderTexture" {
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainTex("2阶贴图", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM // CG语言的开始
// 编译指令 着色器名称 函数名称
#pragma vertex vert // 顶点着色器, 每个顶点执行一次
#pragma fragment frag // 片段着色器, 每个像素执行一次
// 导入头文件
#include "UnityCG.cginc"
// 声明属性变量, 必须与外部属性变量名称一致
sampler2D _MainTex;
struct appdata // 顶点着色器输入结构体
{
half4 vertexPos: POSITION; // 顶点坐标
half2 uv_MainTex: TEXCOORD0; // 纹理uv坐标
};
struct v2f // 顶点着色器输出结构体
{
half4 clipPos: SV_POSITION; // 屏幕坐标
half2 uv_MainTex: TEXCOORD0; // 纹理uv坐标
};
// 顶点着色器
v2f vert(appdata data)
{
v2f o;
o.clipPos = UnityObjectToClipPos(data.vertexPos); // 等价于: mul(UNITY_MATRIX_MVP, data.vertexPos)
o.uv_MainTex = data.uv_MainTex;
return o;
}
// 片元着色器
fixed4 frag(v2f input) : COLOR
{
return tex2D(_MainTex, input.uv_MainTex);
}
ENDCG // CG语言的结束
}
}
FallBack "Diffuse"
}
![](https://i-blog.csdnimg.cn/blog_migrate/7be65921f51eeea0669fda4b914ba898.png)