Unity-TA 成长之路(五)Unity Shader 源码初探

1、纯色显示

  主要结构,就是Shader下,包含一个SubShader和一个FallBack,FallBack不再赘述,就是上面子Shader不可用的时候调用,一般为紫色显示。而SubShader中的结构为Tag、CGPROGRAM,Tag只定义了RenderType,选用了最常用的Opaque,光照模型的使用也有注释,再有就是一个输入函数一个输出函数。颜色的展示就在surf函数中设置,o.Albedo = 1。
效果图:
纯色显示
源码:

Shader "Custom/Shader01"//Shader名
{
    SubShader
    {
        //Opaque: 用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
        //Transparent:用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。
        //TransparentCutout: 蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。
        //Background: Skybox shaders. 天空盒着色器。
        //Overlay: GUITexture, Halo, Flare shaders. 光晕着色器、闪光着色器。
        //TreeOpaque: terrain engine tree bark. 地形引擎中的树皮。
        //TreeTransparentCutout: terrain engine tree leaves. 地形引擎中的树叶。
        //TreeBillboard: terrain engine billboarded trees. 地形引擎中的广告牌树。
        //Grass: terrain engine grass. 地形引擎中的草。
        //GrassBillboard: terrain engine billboarded grass. 地形引擎何中的广告牌草。
        Tags { "RenderType" = "Opaque"}

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型,就是下面的void surf

        //float3 viewDir - 视图方向 (view direction)。为了计算视差效果(Parallax effects),边缘光照等
        //float4 with COLOR semantic -每个顶点插值后的颜色
        //float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位置信息。
        //float3 worldPos - 世界空间中的位置。
        //float3 worldRefl - 世界空间中的反射向量。 如果surface shader没有赋值o.Normal,将会包含世界反射向量。参见例子:Reflect-Diffuse shader。
        //float3 worldNormal - 世界空间中的法线向量。如果surface shader没有赋值o.Normal,将会包含世界法向量
        //float3 worldRefl; INTERNAL_DATA - 世界空间中的反射向量。如果surface shader没有赋值o.Normal,将会包含这个参数。为了获得逐像素法线贴图的反射向量,请使用WorldReflectionVector (IN, o.Normal)。参见例子: Reflect-Bumped shader。
        //float3 worldNormal; INTERNAL_DATA -世界空间中的法线向量。如果surface shader没有赋值o.Normal,将会包含世界法向量。为了获得逐像素法线贴图的法向量,请使用WorldNormalVector(IN, o.Normal)。
        //在一个贴图变量之前加上uv两个字母,就代表提取它的uv值,例如uv_MainTex
        //输入 结构体 名字不能改,只能为Input
        struct Input {
          float4 color : COLOR;
        };

        //第一个参数,纯输入的上述结构体参数。
        //第二个参数,inout标识,意思是可为输入参数也可为输出参数。
        void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = 1;//Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

2、颜色暴露

  Properties中加入一个Color属性,CGPROGRAM中加入一个Color声明,surf函数中,o.Albedo = _Color去赋值颜色。
效果图:
颜色暴露源码:

Shader "Custom/Shader02"//Shader名
{
    Properties
    {
        _Color("Color", Color) = (1, 1, 1, 1)//定义一个颜色属性
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        fixed4 _Color;//颜色,和属性中的_Color相对应,需要同名
        
        struct Input {
            float4 color : COLOR;//四元素的颜色值(RGBA)
        };
        
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = _Color;//赋值为属性中的颜色值     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

3、显示贴图

  Properties中加入一个Texture,同样CGPROGRAM中添加一个sampler2D贴图声明,Input中加入uv信息:float2 uv_MainTexture; 此处,uv+上面声明的贴图变量名,surf中将贴图颜色信息给材质:o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;
效果图:
显示贴图源码:

Shader "Custom/Shader03"//Shader名
{
    Properties {
        //属性_MainTexture
        //面板显示为Texture
        //类型为2D
        //white不是单纯的颜色名,而是是unity的build-in的textures名称
        _MainTexture ("Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        sampler2D _MainTexture;//贴图
        
        struct Input {
            float2 uv_MainTexture;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;//将贴图颜色信息给材质     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

4、法线贴图

  在上一个Shader的基础上添加一个NormalMap属性,同时CGPROGRAM添加一个NormalMap声明,Input添加一个uv_NormalMap,surf中,将法线贴图信息给材质球o.Normal = UnpackNormal (tex2D (_NormalMap, IN.uv_NormalMap));
效果图:
法线贴图源码:

Shader "Custom/Shader04"//Shader名
{
    Properties {
        //属性_MainTexture
        //面板显示为Texture
        //类型为2D
        //white不是单纯的颜色名,而是是unity的build-in的textures名称
        _MainTexture ("Texture", 2D) = "white" {}
        //法线贴图
        _NormalMap ("NormalMap", 2D) = "" {}
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        sampler2D _MainTexture;//贴图
        sampler2D _NormalMap;//法线贴图

        struct Input {
            float2 uv_MainTexture;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;//将贴图颜色信息给材质     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
            o.Normal = UnpackNormal (tex2D (_NormalMap, IN.uv_NormalMap));//UnpackNormal是unity自带的标准解压法线用的
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

5、边缘发光

  添加一个边缘发光颜色属性,一个强度属性,Input中的viewDir,是视图方向 (view direction),surf中根据视角去算强度都有详细注释说明,
源码:

Shader "Custom/Shader05"//Shader名
{
    Properties {
        //属性_MainTexture
        //面板显示为Texture
        //类型为2D
        //white不是单纯的颜色名,而是是unity的build-in的textures名称
        _MainTexture ("Texture", 2D) = "white" {}
        //法线贴图
        _NormalMap ("NormalMap", 2D) = "" {}
        //边缘发光颜色
        _RimColor ("RimColor", Color) = (0.26,0.19,0.16,0.0)
        //边缘发光强度
        _RimPower ("RimPower", Range(0.5,8.0)) = 3.0
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        sampler2D _MainTexture;//贴图
        sampler2D _NormalMap;//法线贴图
        float4 _RimColor;
        float _RimPower;

        struct Input {
            float2 uv_MainTexture;
            float2 uv_NormalMap;
            float3 viewDir;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;//将贴图颜色信息给材质     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
            o.Normal = UnpackNormal (tex2D (_NormalMap, IN.uv_NormalMap));//UnpackNormal是unity自带的标准解压法线用的
            half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));//点积求夹角的Cos,夹角越大,Cos越小     saturate是取0-1   1-()取反,夹角越大,值越大     half是一种低精度的float
            o.Emission = _RimColor.rgb * pow (rim, _RimPower);//rim的_EmissionPower次幂 * 颜色值
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

6、贴图反射叠加

  添加一个细节贴图属性,并通过“o.Albedo *=”将贴图反射叠加。
效果图
贴图反射叠加
源码:

Shader "Custom/Shader07"//Shader名
{
    Properties {
        //属性_MainTexture
        //面板显示为Texture
        //类型为2D
        //white不是单纯的颜色名,而是是unity的build-in的textures名称
        _MainTexture ("Texture", 2D) = "white" {}
        //细节贴图
        _Detail ("Detail", 2D) = "gray" {}
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque"}

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        sampler2D _MainTexture;//贴图
        sampler2D _Detail;//细节贴图

        struct Input {
            float2 uv_MainTexture;
            float2 uv_Detail;
        };
        
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;//将贴图颜色信息给材质     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
            o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb;//在原先的反射基础上,在加一层"_Detail"的反射
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}

7、通过齐次坐标还原点的真实坐标

  其实这里主要是其次坐标,他到底实现了什么呢,其实就是把透视视图的坐标还原,在这里,存储一个点的坐标,不是使用3维,而是4维,多出来的这个w就是为了反映投影,正常世界中的两条平行线是不可能相交的,但是在视野中,无限远处是可以的。
  可以看一下这边文章:https://zhuanlan.zhihu.com/p/440717663
效果图:
通过齐次坐标还原点的真实坐标

源码:

Shader "Custom/Shader08"//Shader名
{
    Properties {
        //属性_MainTexture
        //面板显示为Texture
        //类型为2D
        //white不是单纯的颜色名,而是是unity的build-in的textures名称
        _MainTexture ("Texture", 2D) = "white" {}
        //细节贴图
        _Detail ("Detail", 2D) = "gray" {}
    }

    SubShader
    {
        Tags { "RenderType" = "Opaque"}

        CGPROGRAM
        #pragma surface surf Lambert//指定响应方法为surf且采用Lambert的光照模型

        sampler2D _MainTexture;//贴图
        sampler2D _Detail;//细节贴图

        struct Input {
            float2 uv_MainTexture;
            float4 screenPos;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTexture, IN.uv_MainTexture).rgb;//将贴图颜色信息给材质     Albedo是一个rgb的值,如果给一个1,其实就是float3(1,1,1),就是反射出来的颜色为白色,如果为100,则是加强反射强度,并不会改变其颜色,为0或为负数时道理类似
            float2 screenUV = IN.screenPos.xy / IN.screenPos.w;//(x,y,z,w)的齐次坐标对应三维点(x/w,y/w,z/w)
            screenUV *= float2(9,16);
            o.Albedo *= tex2D (_Detail, screenUV).rgb;
        }
        ENDCG
    }
    FallBack "Diffuse"//如果所有subshader在当前显卡都不支持,则默认返回自带的Diffuse
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

末零

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值