利用unity和steamVR完成场景漫游(⑦) 雪的shader

第一步定义一些属性:

 接下来我们要做的就是计算对应像素的法向量是否与下雪的方向一致(如果一致,那么就将该像素置为雪的颜色,这个道理和平行光的原理很类似)。

我们使用点乘(dot product)计算方向是否一致。两个单位向量之间的点乘等于这两个向量之间夹角的余弦值。CG中自带了一个dot函数为我们做两向量的点乘计算。这样的话,当我们计算出的点乘结果为1,则说明两向量间余弦值为1,即两者夹角为0,说明两者方向一致,而结果为-1时,说明两者方向相反。所以我们不必算出最后的角度,仅仅通过点乘结果就可以判断两向量之间方向的关系。

单位向量是指大小为1的向量,也就是说当向量v满足sqrt(v.x*v.x+v.y*v.y+v.z*v.z)=1时,此向量为单位向量。不要认为单位向量就是(1,1,1)啊!!!

如果要使用点乘的结果来表示两向量之间的角度,首先要将两个向量的长度变为单位长度,也就是将两个向量变到单位向量再计算点乘。

知道这些后,我们在shader中定义以下属性。

Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _Bump ("Bump", 2D) = "bump" {}
    _Snow ("Snow Level", Range(0,1) ) = 0
    _SnowColor ("Snow Color", Color) = (1.0,1.0,1.0,1.0)
    _SnowDirection ("Snow Direction", Vector) = (0,1,0)
    _SnowDepth ("Snow Depth", Range(0,0.3)) = 0.1
}

第二步声明一些变量:

sampler2D _MainTex;
sampler2D _Bump;
float _Snow;
float4 _SnowColor;
float4 _SnowDirection;
float _SnowDepth;

第三步自定义Input结构体:

struct Input {
        float2 uv_MainTex;
        float2 uv_Bump;
        float3 worldNormal;
        INTERNAL_DATA
    };

第四步完善最终的渲染函数:

void surf (Input IN, inout SurfaceOutput o) {
 
    //该像素的真实颜色值
    half4 c = tex2D (_MainTex, IN.uv_MainTex);
 
    //从凹凸贴图中得到该像素的法向量
    o.Normal = UnpackNormal (tex2D (_Bump, IN.uv_Bump));
 
    //得到世界坐标系下的真正法向量(而非凹凸贴图产生的法向量,要做一个切空间到世界坐标系的转化)和雪落
    //下相反方向的点乘结果,即两者余弦值,并和_Snow(积雪程度)比较
    if(dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz)>lerp(1,-1,_Snow))
        //此处我们可以看出_Snow参数只是一个插值项,当上述夹角余弦值大于
        //lerp(1,-1,_Snow)=1-2*_Snow时,即表示此处积雪覆盖,所以此值越大,
        //积雪程度程度越大。此时给覆盖积雪的区域填充雪的颜色
        o.Albedo = _SnowColor.rgb;
    else
        //否则使用物体原先颜色,表示未覆盖积雪 
        o.Albedo = c.rgb;
    o.Alpha = 1;
}

完整的积雪shader:

Shader "Custom/XXXXXXXXX" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Bump ("Bump", 2D) = "bump" {}
        _Snow ("Snow Level", Range(0,1)) = 0
        _SnowColor ("Snow Color", Color) = (1.0,1.0,1.0,1.0)
        _SnowDirection ("Snow Direction", Vector) = (0,1,0)
        _SnowDepth ("Snow Depth", Range(0,0.3)) = 0.1
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        CGPROGRAM
        #pragma surface surf Lambert
        sampler2D _MainTex;
        sampler2D _Bump;
        float _Snow;
        float4 _SnowColor;
        float4 _SnowDirection;
        float _SnowDepth;
        struct Input {
               float2 uv_MainTex;
            float2 uv_Bump;
            float3 worldNormal;
            INTERNAL_DATA
        };
        void surf (Input IN, inout SurfaceOutput o) {
 
            //该像素的真实颜色值
               half4 c = tex2D (_MainTex, IN.uv_MainTex);
 
            //从凹凸贴图中得到该像素的法向量
            o.Normal = UnpackNormal (tex2D (_Bump, IN.uv_Bump));
 
            //得到世界坐标系下的真正法向量(而非凹凸贴图产生的法向量)和雪落
            //下相反方向的点乘结果,即两者余弦值,并和_Snow(积雪程度)比较
            if(dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz)>lerp(1,-1,_Snow))
                //此处我们可以看出_Snow参数只是一个插值项,当上述夹角余弦值大于
                //lerp(1,-1,_Snow)=1-2*_Snow时,即表示此处积雪覆盖,所以此值越大,
                //积雪程度程度越大。此时给覆盖积雪的区域填充雪的颜色
                   o.Albedo = _SnowColor.rgb;
            else
                //否则使用物体原先颜色,表示未覆盖积雪 
                o.Albedo = c.rgb;
           o.Alpha = 1;
}
        ENDCG
    } 
    FallBack "Diffuse"
}
总结自:https://www.cnblogs.com/polobymulberry/p/4316683.html




猜你喜欢

转载自blog.csdn.net/carotadream/article/details/80160368