IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Unity3D 雪覆盖shader的实现 -> 正文阅读

[人工智能]Unity3D 雪覆盖shader的实现

实现思路

回忆一下现实生活中的雪,在一个时间段内大致是从一个方向吹的,面朝吹来方向的表面会被沾上雪,背向雪吹来方向的表面则不会被沾上雪。这样听起来就和光照的处理方式非常像,因此我们就大致用lambert光照的处理方式来处理雪覆盖的效果。
指定一个方向作为雪的方向,计算顶点法线和雪方向的点积,作为混合因子,然后用该混合因子混合正常颜色和雪颜色,以及正常法线和雪的法线。

代码实现

因为我们的下雪方向是定义在世界空间内的向量,所以要把法线也都转换到世界空间来计算,因此在顶点着色器中定义了切线空间到世界空间的变换矩阵

                o.ToW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                o.ToW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                o.ToW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

在片元着色器中先提取正常表面的法线贴图和雪表面的法线贴图然后变换到世界空间,方式就是乘上我们在顶点着色器中准备好的变换矩阵。同时引入一个_BumpScale变量作为法线贴图的凹凸程度值,因为切线空间的法线贴图中(0,0,1)值代表原法线,因此只要把xy值乘上某个大于1的值同时再归一化该法线,即可使该法线更加偏向原来的偏向方向,因此就控制了法线的凹凸程度。

 				//计算法线
                fixed3 mainNormal = UnpackNormal(tex2D(_MainBumpTex, i.uv));
                mainNormal.xy *= _BumpScale;
                mainNormal.z = sqrt(1.0 - saturate(dot(mainNormal.xy, mainNormal.xy)));
                mainNormal = normalize(half3(dot(i.ToW0.xyz, mainNormal), dot(i.ToW1.xyz, mainNormal),
                                             dot(i.ToW2.xyz, mainNormal)));

                fixed3 snowNormal = UnpackNormal(tex2D(_SnowBumpTex, i.uv));
                snowNormal.xy *= _BumpScale;
                snowNormal.z = sqrt(1.0 - saturate(dot(snowNormal.xy, snowNormal.xy)));
                snowNormal = normalize(half3(dot(i.ToW0.xyz, snowNormal), dot(i.ToW1.xyz, snowNormal),
                                             dot(i.ToW2.xyz, snowNormal)));

之后进行混合即可,_SnowDir就是我们定义的下雪方向

  				//根据下雪方向和法线的点积来确定混合程度
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed4 snowColor = tex2D(_SnowTex, i.uv);
				//使用类似lambert光照计算漫反射的方式来计算混合程度
                float snowValue = saturate(dot(mainNormal, _SnowDir) * _SnowAmount);
                //混合颜色
                fixed4 finalColor = lerp(col, snowColor, snowValue);
                //混合法线
                fixed3 finalNormal = lerp(mainNormal, snowNormal, snowValue);

最后用混合后的法线做一个简单的光照,这里仅为实例,如果需要完整光照效果也可以自己扩展

                //简易lambert光照
                float lightDir = UnityWorldSpaceLightDir(i.worldPos);
                float diffuse = saturate(dot(lightDir, finalNormal)) * finalColor;
                float4 ambient = UNITY_LIGHTMODEL_AMBIENT.rgba * finalColor;

然后调整参数就可以得到如下效果。
请添加图片描述
效果2
请添加图片描述
参数面板请添加图片描述

完整代码

Shader "LX/SnowAccumulate"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _SnowTex("SnowTex",2D)="white" {}
        _MainBumpTex("MainBumpTex",2D) = "white" {}
        _SnowBumpTex("SnowBumpTex",2D) = "white" {}
        _SnowDir("SnowDir",vector)=(0,1,0)
        _SnowAmount("SnowAmount",float)=1
        _BumpScale("BumpScale",float)=1
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal:NORMAL;
                float4 tangent:TANGENT;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldNormal:TEXCOORD1;
                float4 ToW0:TEXCOORD2;
                float4 ToW1:TEXCOORD3;
                float4 ToW2:TEXCOORD4;
                float3 worldPos:TEXCOORD5;
            };

            sampler2D _MainTex;
            sampler2D _SnowTex;
            sampler2D _MainBumpTex;
            sampler2D _SnowBumpTex;
            float4 _MainTex_ST;
            float3 _SnowDir;
            float _SnowAmount;
            float _BumpScale;


            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.worldPos = worldPos;
                fixed3 worldNormal = o.worldNormal;
                fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;

                o.ToW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                o.ToW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                o.ToW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //计算法线
                fixed3 mainNormal = UnpackNormal(tex2D(_MainBumpTex, i.uv));
                mainNormal.xy *= _BumpScale;
                mainNormal.z = sqrt(1.0 - saturate(dot(mainNormal.xy, mainNormal.xy)));
                mainNormal = normalize(half3(dot(i.ToW0.xyz, mainNormal), dot(i.ToW1.xyz, mainNormal),
                                             dot(i.ToW2.xyz, mainNormal)));

                fixed3 snowNormal = UnpackNormal(tex2D(_SnowBumpTex, i.uv));
                snowNormal.xy *= _BumpScale;
                snowNormal.z = sqrt(1.0 - saturate(dot(snowNormal.xy, snowNormal.xy)));
                snowNormal = normalize(half3(dot(i.ToW0.xyz, snowNormal), dot(i.ToW1.xyz, snowNormal),
                                             dot(i.ToW2.xyz, snowNormal)));

                //根据下雪方向和法线的点积来确定混合程度
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed4 snowColor = tex2D(_SnowTex, i.uv);

                float snowValue = saturate(dot(mainNormal, _SnowDir) * _SnowAmount);
                fixed4 finalColor = lerp(col, snowColor, snowValue);

                //混合法线
                fixed3 finalNormal = lerp(mainNormal, snowNormal, snowValue);

                //简易lambert光照
                float lightDir = UnityWorldSpaceLightDir(i.worldPos);
                float diffuse = saturate(dot(lightDir, finalNormal)) * finalColor;
                float4 ambient = UNITY_LIGHTMODEL_AMBIENT.rgba * finalColor;

                return diffuse + ambient;
            }
            ENDCG
        }
    }
}

另外代码也传到github仓库里了,大家也可以关注一下哦~
我的github

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:20:36  更:2021-09-14 13:23:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/22 2:40:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码