Ylisar 发表于 2022-4-25 13:28

Unity Shader 代码结构简单说明

Unity顶点/片元着色器的Shader代码结构
Shader "命名"
{
    Properties {} //属性声明区域,可以声明一系列自定义的变量
    SubShader // 子着色器SubShader代码块,可以有多份
    {
      Pass
      {
      }
    }
    Fullback "备用着色器名称" // 如果所有SubShader都不能运行,则使用这个配置的Unity内置着色器,俗称备胎。
}需要注意的点

float、half、fixed 的差异

精度差异, float的精度为 32 位, half 的精度为16 位, fixed 的精度为 8 位。使用场景分别是

[*]float 用来做坐标点相关的运算
[*]half用来做 uv、大部分向量相关的运算
[*]fixed 颜色相关的运算
需要合理使用不同精度的变量,如果全部都使用float,则会浪费很多空间性能。
如何在顶点着色器上把顶点的坐标从模型空间转换到裁剪空间

一开始拿到的是模型空间的坐标,需要经过的转换有
模型空间->世界空间->相机空间->裁剪空间

[*]可以直接使用 MVP 矩阵进行转换
[*]分别用不同的矩阵进行不同空间的转换,并把有需要使用到的某个空间坐标系传入通用插值器,提供给光栅化阶段进行插值并把设置到片元。
下面是最简单的一个采样纹理的Shader代码,每个块的对应功能都会写到注释。
Shader "HTA/HS_shader" //shader的名字,可在材质上通过选择对应的名字生效对应的Shader
{
    //属性声明区域
    Properties
    {
      _Float("Float", Float) = 0.0 // 声明一个浮点数
      _Range("Range", Range(0.0, 1.0)) = 0.0 // 声明一个范围
      _Vector("Vector", Vector) = (0.0, 0.0, 0.0, 0.0) // 声明一个向量
      _Color("Color", Color) = (1, 1, 1, 1) // 声明一个颜色
      _Texture("Texture", 2D) = "while" {} // 声明一张2D图片
    }

    // SubShader代码块,里面可以有多个 Pass 代码块,每个Shader语义块里可以有多个SubShader代码块。
    // 当Unity需要加载这个Shader时,会扫描所有SubShader语义块,然后选择一个能够在目标平台上运行的SubShader,如果都不支持,则会使用 Fallback 语义指定Unity的默认Shader。
    SubShader
    {
      //一个Pass跑一次渲染管线。从上往下执行。
      Pass
      {
            CGPROGRAM// 使用CGPROGRAM ... ENDCG 两句话表示内部的是CG代码。
            #pragma vertex vert// 声明 顶点着色器 vert
            #pragma fragment frag // 声明 片元着色器 frag
            #include "UnityCG.cginc" // 引用 UnityCG.cginc 文件,把已实现的 shader包含进来,方便直接拿到一些内置的变量。

            //定义cpu需要准备给顶点着色器的数据
            //可参考官方文档 https://docs.unity3d.com/cn/2019.4/Manual/SL-VertexProgramInputs.html
            struct appdata
            {
                float4 vertex : POSITION; // 模型顶点坐标
                float2 uv : TEXCOORD0;    // 第一套UV数据 一共有4套
            };

            //声明一个结构体,定义每个顶点数据通过硬件阶段最终产生片元时携带的数据。
            struct v2f
            {
                float4 pos : SV_POSITION; // 裁剪空间下的顶点坐标
                float2 uv : TEXCOORD0; //通用插值器,与上方的CPU准备给顶点着色器的数据里面的 TEXCOORD0 不一样,这边总共可以有16个插值器。
            };

            // Properties 区域内声明的变量,要在 Pass 块重新声明,才能成功绑定。
            sampler2D _Texture;
            float4 _Texture_ST; // Unity 的规定写法,可以获取4维向量,x.y表示缩放,z.w表示偏移

            // 顶点着色器
            v2f vert (appdata v)
            {
                v2f o; //声明顶点着色器的返回结构
               
                //float4 pos_world = mul(unity_ObjectToWorld, v.vertex); // 把顶点坐标从模型空间转换到世界空间
                //float4 pos_view = mul(UNITY_MATRIX_V, pos_world);       // 把顶点坐标从世界空间转换到相机空间
                //float4 pos_clip = mul(UNITY_MATRIX_P, pos_view);      // 把顶点坐标从相机空间转换到裁剪空间
                //o.pos = pos_clip;

                // 上面三句话分别是用不同的矩阵做不同的坐标系转换,也可以直接使用 MVP 矩阵,直接把顶点的坐标从模型空间转换到裁剪空间
                o.pos = UnityObjectToClipPos(v.vertex); // 使用内置方法把模型空间的顶点坐标转换成裁剪空间的顶点坐标进行输出
                o.uv = v.uv * _Texture_ST.xy + _Texture_ST.zw;
                return o;
            }

            // 片元着色器
            fixed4 frag(v2f i) : SV_Target
            {
                // 根据uv值对贴图的纹素进行采样,并返回对应的颜色。
                fixed4 color = tex2D(_Texture, i.uv);
                return color;
            }
            ENDCG
      }
    }
}最终能够通过放置的图片,采取到图片对应的纹素颜色,并获取到对应设置的 偏移(Tilling)、缩放值(Offset)。把每个对应片元采样到的颜色输出到屏幕中。(注意这里图片资源的 WrapMode 设置需要为 Repeat)

页: [1]
查看完整版本: Unity Shader 代码结构简单说明