Created
March 10, 2020 04:09
-
-
Save stilllisisi/39a297bf12bd6838db8855de7683e475 to your computer and use it in GitHub Desktop.
【游戏-渲染】移动端下雪系统的实现
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //首先还是从雪粒子开始,雪粒子无法像雨一样根据深度来直接判断阻挡,因为雨是垂直下落的,但雪不是,雪是会有各种方向的,所以这里需要做实实在在的碰撞来处理遮挡。 | |
| private void OnTriggerEnter(Collider other) | |
| { | |
| SnowManager.inst.reclaim(this); | |
| } | |
| //就是用了一个触发器,就可以看到雪被挡住了。因为自带的物理引擎性能也很好,这样做还可以接受。 | |
| //然后要开始处理积雪。第一步还是要实现一个雪的材质,起码要看上去像雪。 | |
| //基本原理就是雪是白色的,然后加上一个法线,模拟雪表面的纹理。 | |
| 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; | |
| //然后是处理雪的逐渐覆盖,首先想到的就是利用柏林噪声生成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); | |
| //接下来依然要处理遮挡部分,和下雨是一样的。 | |
| // https://gist.github.com/stilllisisi/df902526a65aec5475276ccefecb1745 | |
| //最后是运动痕迹,和以前的草思路一样。 | |
| // https://gist.github.com/stilllisisi/78a21dbe1a53c47ea02b4c5818c05f5d | |
| 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; | |
| 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)); | |
| } | |
| //改良措施就是直接用雪粒子特效代替,因为粒子特效是多线程优化过的,也支持碰撞,性能会好不少。 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gameinstitute.qq.com/community/detail/128952