写在前面:

这个系列来源于书籍冯乐乐老师的《unity shader 入门精要》,
参考的代码库“https://github.com/candycat1992/Unity_Shaders_Book”
我自己跟着写了一遍代码,并在代码块里给shader代码加上了比较详细的注释
更为仔细的解释和unity shader原理和知识书里都有,本blog不做详细解释,推荐买书来看。
本项目的所有代码在https://github.com/takashiwangbh/Unity-shader-effect-reproduction/tree/main

介绍

这一part使用shader来通过颜色来可视化模型的顶点属性,简而言之就是使用shader来给物体上色,那为什么不直接用一个材质在unity里上色然后应用呢,那样多简单。虽然简单,但是那样还是有局限性的,只能实现颜色纹理等基础属性。但是使用Shader 允许你直接操作每个顶点和像素,实现高度自定义的效果。例如这一节要实现的False Color 可视化:展示模型的法线、切线、UV 坐标等几何属性。

物体和shader的创建

在unity中,创建一个球,然后再创建一个材质,将材质应用到球上,再创建一个shader应用到材质上。

shader代码

Shader "Unity Shaders Book/Chapter 5/False Color" { // 定义了一个名为 "False Color" 的着色器
   SubShader { // 一个子着色器
       Pass { // 着色器的一个 Pass
           CGPROGRAM // 开始编写 CG 代码
           
           #pragma vertex vert // 指定顶点着色器函数为 vert
           #pragma fragment frag // 指定片段着色器函数为 frag
           
           #include "UnityCG.cginc" // 包含 Unity 的常用 CG 工具函数
           
           struct v2f { // 定义顶点到片段的结构体
               float4 pos : SV_POSITION; // 顶点的屏幕坐标
               fixed4 color : COLOR0; // 输出到片段的颜色
           };
           
           v2f vert(appdata_full v) { // 顶点着色器
               v2f o; // 定义一个输出结构体
               o.pos = UnityObjectToClipPos(v.vertex); // 将模型空间的顶点转换为裁剪空间坐标
               
               // 可视化法线 (Normal)
               o.color = fixed4(v.normal * 0.5 + fixed3(0.5, 0.5, 0.5), 1.0);
               // 将法线值从 (-1,1) 转换为 (0,1),以便用颜色显示
               
               // 可视化切线 (Tangent)
               o.color = fixed4(v.tangent.xyz * 0.5 + fixed3(0.5, 0.5, 0.5), 1.0);
               // 同样对切线进行归一化和偏移,用颜色展示
               
               // 可视化双切线 (Binormal)
               fixed3 binormal = cross(v.normal, v.tangent.xyz) * v.tangent.w;
               // 计算双切线,通过法线和切线的叉积计算,乘以切线的 w 值
               o.color = fixed4(binormal * 0.5 + fixed3(0.5, 0.5, 0.5), 1.0);
               // 对双切线归一化并用颜色显示
               
               // 可视化第一套纹理坐标 (UV1)
               o.color = fixed4(v.texcoord.xy, 0.0, 1.0);
               // 使用第一套 UV 坐标,将其 XY 直接映射为颜色的 RG 分量
               
               // 可视化第二套纹理坐标 (UV2)
               o.color = fixed4(v.texcoord1.xy, 0.0, 1.0);
               // 使用第二套 UV 坐标,映射为颜色
               
               // 可视化第一套纹理坐标的分数部分
               o.color = frac(v.texcoord); // frac() 提取小数部分
               if (any(saturate(v.texcoord) - v.texcoord)) { 
                   // 检查 UV 是否超出 (0,1) 范围,若超出,则标记
                   o.color.b = 0.5; // 蓝色通道设为 0.5 表示标记
               }
               o.color.a = 1.0; // 设置透明度为 1
               
               // 可视化第二套纹理坐标的分数部分
               o.color = frac(v.texcoord1); // 同理提取第二套 UV 的小数部分
               if (any(saturate(v.texcoord1) - v.texcoord1)) { 
                   // 检查第二套 UV 是否超出范围
                   o.color.b = 0.5;
               }
               o.color.a = 1.0;
               
               // 可视化顶点颜色
               // o.color = v.color; // 如果需要可视化模型的顶点颜色,取消注释
               
               return o; // 返回计算好的数据
           }
           
           fixed4 frag(v2f i) : SV_Target { // 片段着色器
               return i.color; // 输出顶点着色器计算的颜色
           }
           
           ENDCG // 结束 CG 代码
       }
   }
}

结果

就这样,一个球体就被渲染上了不同的颜色
在这里插入图片描述

Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐