近期热门
粉丝8
关注 0
获赞 8
移动端下雪系统的实现

[U3D] 移动端下雪系统的实现

[复制链接]
2419 3 0 6 5年前 举报
先上最终效果:

https://v.qq.com/x/page/k081225eqx7.html



做完下雨做下雪,(下雨文章地址:https://blog.csdn.net/yxriyin/article/details/84630503)下雪其实和下雨有很多类似的地方。类似的部分我就不再仔细说明,主要还是看不同的部分。个人认为下雪比下雨更加困难。



首先还是从雪粒子开始,雪粒子无法像雨一样根据深度来直接判断阻挡,因为雨是垂直下落的,但雪不是,雪是会有各种方向的,所以这里需要做实实在在的碰撞来处理遮挡。

        private void OnTriggerEnter(Collider other)
        {
            SnowManager.inst.reclaim(this);
        }

1.png

就是用了一个触发器,就可以看到雪被挡住了。因为自带的物理引擎性能也很好,这样做还可以接受。

然后要开始处理积雪。第一步还是要实现一个雪的材质,起码要看上去像雪。

基本原理就是雪是白色的,然后加上一个法线,模拟雪表面的纹理。

                            VertexOutputBaseSimple1 vertForwardBase(VertexInput1 v)
                            {
                                    UNITY_SETUP_INSTANCE_ID(v);
                                    VertexOutputBaseSimple1 o;
                                    UNITY_INITIALIZE_OUTPUT(VertexOutputBaseSimple1, o);
                                    float4 posWorld = mul(unity_ObjectToWorld, v.vertex);
                                    o.pos = UnityObjectToClipPos(v.vertex);
                                    o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                                    o.pack0.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
                                    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                                    float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                                    float tangentSign = v.tangent.w * unity_WorldTransformParams.w;
                                    float3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
                                    o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
                                    o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
                                    o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
                           
                                    o.vlight = ShadeSH9(float4(worldNormal, 1));
                                    o.depthuv = mul(depthMat, float4(worldPos, 1));
                                    TRANSFER_SHADOW(o);
                                    UNITY_TRANSFER_FOG(o, o.pos);
                                    return o;
                            }

                                    float3 H = normalize(_WorldSpaceLightPos0.xyz + viewDir);
                                    float NdotH = max(0, dot(worldNormal, H));
                                    float nl = dot(float3(i.tSpace0.z, i.tSpace1.z, i.tSpace1.z), _WorldSpaceLightPos0.xyz);
                                    float NdotL = dot(worldNormal, _WorldSpaceLightPos0.xyz);
                                    float NdotV = dot(worldNormal, viewDir);
                                    float3 shadow = atten * _LightColor0.rgb;
                                    float y = NdotL * shadow;
                                    float2 uv_ramp = float2(_Strength * NdotV, y);
                                    float3 ramp = tex2D(_SnowTex, uv_ramp.xy);
                                    half ssatten = 1.0;
                                    half3 specular = saturate(pow(NdotH, _Shininess * 128.0) * _Specular);
                                    float shadow1 = SHADOW_ATTENUATION(i);
                                    c.rgb = lerp(albedo.rgb * _Color * shadow * nl * _LightColor0.rgb + albedo.rgb * _Color * 0.5, i.vlight, coverage) + coverage * (ramp + albedo * (specular) * shadow);
                                    c.rgb *= shadow1;

这样就有了基本的感觉。
2.png
然后是处理雪的逐渐覆盖,首先想到的就是利用柏林噪声生成fbm,来逐步覆盖雪地。

                                    float f;
                                    float3 q = worldPos;
                                    f = 0.5000*noise(q);
                                    q = q * 2.02;
                                    f += 0.2500*noise(q);
                                    q = q * 2.03;
                                    f += 0.1250*noise(q);
                                    q = q * 2.01;
                                    f += 0.0625*noise(q);
                                    float NdotD = saturate(dot(normal, _WorldSpaceLightPos0.xyz));
                                    float coverage = NdotD - lerp(1, -1, _cover);
                                    coverage = saturate(coverage);
                                    coverage = f * _noise - lerp(1, -1, coverage) + max(-0.1,i.tSpace1.z * _cover);

可以看到地面和球体都有部分被雪覆盖的痕迹。 接下来依然要处理遮挡部分,和下雨是一样的。
3.png

4.png


最后是运动痕迹,和以前的草思路一样。

                                    float4 grassuv1 = mul(MoveMatrix, float4(worldPos, 1));
                                    float2 grassuv2 = grassuv1.xy / grassuv1.w * 0.5 + 0.5;
    #if UNITY_UV_STARTS_AT_TOP
                                    grassuv2.y = 1 - grassuv2.y;
    #endif
                                    float4 n = tex2D(_MoveTex, grassuv2);
                                    n.xz = (n.xz - 0.5) * 2;
                                    n.y *= _cover;
                                    //coverage *= (1 - n.y * 0.1 * f);
                                   
                                    UNITY_LIGHT_ATTENUATION(atten, i, worldPos)
                                    float4 c = 0;
                                    float3 worldNormal;
                                    worldNormal.x = dot(i.tSpace0.xyz, normal);
                                    worldNormal.y = dot(i.tSpace1.xyz, normal);
                                    worldNormal.z = dot(i.tSpace2.xyz, normal);
                                    worldNormal = normalize(worldNormal);
                                   
                                    c.rgb += albedo.rgb * i.vlight;
                                    float3 H = normalize(_WorldSpaceLightPos0.xyz + viewDir);
                                    float NdotH = max(0, dot(worldNormal, H));
                                    float nl = dot(float3(i.tSpace0.z, i.tSpace1.z, i.tSpace1.z), _WorldSpaceLightPos0.xyz);
                                    float NdotL = dot(worldNormal, _WorldSpaceLightPos0.xyz);
                                    float NdotV = dot(worldNormal, viewDir);
                                    float3 shadow = atten * _LightColor0.rgb;
                                    float y = NdotL * shadow;
                                    float2 uv_ramp = float2(_Strength * NdotV, y);
                                    float3 ramp = tex2D(_SnowTex, uv_ramp.xy);
                                    half ssatten = 1.0;
                                    half3 specular = saturate(pow(NdotH, _Shininess * 128.0) * _Specular);
                                    float shadow1 = SHADOW_ATTENUATION(i);
                                    c.rgb = lerp(albedo.rgb * _Color * shadow * nl * _LightColor0.rgb + albedo.rgb * _Color * 0.5, i.vlight, coverage) + min(1.03, coverage * (coverage * 0.05 + 1)) * (ramp + albedo * (specular) * shadow);
                                    c.rgb *= shadow1;

                                    if (needLine > 0.5 && coverage > 0.7 && n.y > 0.1)
                                    {
                                            c.rgb *= (1 - pow(1 - n.y * f, 5) * 0.3  * pow(coverage, 5));
                                    }
10.png
然后说下这个雪的问题。

顶点片段着色器并不复杂,而且可以适当减少噪声计算来获得好的帧率。问题大的反而是为了处理雪的碰撞,以及雪的速度较慢,会积累大量的例子在屏幕里。

所以改良措施就是直接用雪粒子特效代替,因为粒子特效是多线程优化过的,也支持碰撞,性能会好不少。

其他应该和下雨类似,需要自己整合到项目中。

最后是插件地址:

https://assetstore.unity.com/packages/vfx/shaders/mobilesnowsystem-135279
---------------------


0
点赞
0
打赏
6
添加到收藏夹

0

点击复制链接

使用微信扫码分享
一次扣10个券
全部评论3
您需要登录后才可以回帖 登录

感谢分享,论坛有你更精彩
5年前
回复

使用道具 举报

厉害了大佬 感谢分享
5年前
回复

使用道具 举报

感谢楼主分享
5年前
回复

使用道具 举报

您当前使用的浏览器IE内核版本过低会导致网站显示错误

请使用高速内核浏览器或其他浏览器