您当前的位置: 首页 >  unity

Jave.Lin

暂无认证

  • 3浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader - 实现简单水体 - 浅水到深水颜色控制

Jave.Lin 发布时间:2020-03-15 14:50:18 ,浏览量:3

文章目录
  • 制作步骤
    • 准备好水体网格
    • 扰动水体网格
    • 添加水体网格色调,纹理
    • 放置海上放哨点(一些随便放的立方体)
    • 添加水的深浅透视效果
    • 添加水光效
    • 重构水顶点法线
  • 正交的相机的深度需要注意
  • 改进
  • Project
  • References
简单的模拟水的效果(3A游戏效果请绕开哦)

效果: 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

制作步骤
  • 准备好水体网格(网格脚本生成的,参考:Unity Shader - Noise 噪点图 - 实现简单山脉)
  • 扰动水体网格顶点(参考:Unity Shader - 使用Noise噪点图生成简单山脉(使用tex2Dlod控制顶点高度))
  • 添加水体网格色调,纹理
  • 放置海上放哨点(一些随便放的立方体)
  • 添加水的深浅透视效果
  • 添加水光效
  • 重构水顶点法线(参考:Unity Shader - 简单山脉 - 顶点着色器重构法线)
准备好水体网格

网格脚本生成的,参考:Unity Shader - Noise 噪点图 - 实现简单山脉 在这里插入图片描述

扰动水体网格

参考:Unity Shader - 使用Noise噪点图生成简单山脉(使用tex2Dlod控制顶点高度)

我使用了:大波浪与小波浪的叠加

                float centerH = sin(_Time.y * _BigWaveLen + v.uv.x + v.uv.y) * _BigWaveAmplitude;
                centerH += tex2Dlod(_MainTex, float4(v.uv + float2(_Time.x * _SmallWaveSpeedX, _Time.x * _SmallWaveSpeedY), 0, 0)).r * _SmallWaveAmplitude;
                v.vertex.y = centerH;

在这里插入图片描述

添加水体网格色调,纹理

着了个色调,并对uv滚动动画

                fixed4 col = tex2D(_MainTex, i.uv + float2(_Time.y * _BigWaveLen * _UVSpeed, 0));
                col.rgb *= _MainColor.rgb;

在这里插入图片描述

放置海上放哨点(一些随便放的立方体)

在这里插入图片描述

添加水的深浅透视效果

这个参考了unity内置的shader中,处理软粒子的思路:。

  • 获取深度纹理的view space的buffViewZ
  • 获取当前片段的view space的fragViewZ
  • delta = buffViewZ - fragViewZ的深度插值,来控制水体的alpha透视,或lerp的颜色过渡。
  • 还可以使用我们下面实现代码中的fade来控制浅水到深度的效果,我这里就控制海水原来的颜色(combined.rgb + _ShallowColor.rgb * (_ShallowColor.a * 2))到浅水着色变量的颜色来过渡(combined.rgb)。 combined.rgb = lerp(combined.rgb + _ShallowColor.rgb * (_ShallowColor.a * 2), combined.rgb, fade); 如果需要你可以创建一个用个纹理:_ShallowToDeepTex的纹理然后:
var shallowToDeepCol = tex2D(_ShallowToDeepTex, i.uv);
combined.rgb = lerp(combined.rgb + shallowToDeepCol.rgb * (shallowToDeepCol.a * 2), combined.rgb, fade);

下面是参考的:unity内置的shader软粒子代码:

// Soft particles fragment function
#if defined(SOFTPARTICLES_ON) && defined(_FADING_ON)
#define fragSoftParticles(i) \
    if (SOFT_PARTICLE_NEAR_FADE > 0.0 || SOFT_PARTICLE_INV_FADE_DISTANCE > 0.0) \
    { \
        float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projectedPosition))); \
        float fade = saturate (SOFT_PARTICLE_INV_FADE_DISTANCE * ((sceneZ - SOFT_PARTICLE_NEAR_FADE) - i.projectedPosition.z)); \
        ALBEDO_MUL *= fade; \
    }
#else
#define fragSoftParticles(i)
#endif

参考我手绘的一张图: 在这里插入图片描述

下面我们的实现代码

				// vert
                #if DEEP_EFF
                o.projPos = ComputeScreenPos (o.pos);
                COMPUTE_EYEDEPTH(o.projPos.z);
                #endif

				// frag
                #if DEEP_EFF    // 水深效果
                // 深度效果
                // 这里参考unity内置的shader中,实现软例子:Soft particle的写法
                // 与背景深度远时,alpha比较高,里的近则alha低
                // 先是获取深度图的view space下的z值: buffViewZ
                float buffViewZ = LinearEyeD、epth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
                // 再是获取片段的view space的z值:fragViewZ
                float fragViewZ = i.projPos.z;
                // 然后去他们之间的距离值做alpha的控制,与颜色lerp的变化
                float fade = saturate ((buffViewZ-fragViewZ) * _DeepFactor);
                combined.rgb = lerp(combined.rgb + _ShallowColor.rgb * (_ShallowColor.a * 2), combined.rgb, fade);
                combined.a *= fade;
                #endif

在这里插入图片描述

材质中暴露了一个DeepFactor参数,可以用于控制水深的系数。如下: 在这里插入图片描述

也暴露了一个浅水的颜色色调着色: 在这里插入图片描述

添加水光效

这个就是传统的经验光照模型:ambient + diffuse(HalfLambert) + specular(blinn phong)

				// frag
                #if LIGHTING_ON // 光照效果
                // ambient
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                // diffuse
                half3 L = normalize(_WorldSpaceLightPos0.xyz);
                half3 N = normalize(i.normal);
                half LdotN = dot(L, N) * 0.5 + 0.5;
                fixed3 diffuse = col.rgb * LdotN;
                // specular
                half3 specular = 0;
                half3 V = normalize(_WorldSpaceCameraPos.xyz - i.wPos);
                half3 H = normalize(L + V);
                half HdotN = max(0, dot(H, N)); // blinn-phone
                specular = _LightColor0.rgb * pow(HdotN, _SpecularGlossy * 100) * _SpecularIntensity;
                // combined color
                fixed4 combined = fixed4(ambient + diffuse + specular, col.a);
                #else // LIGHTING_OFF
                fixed4 combined = col;
                #endif

在这里插入图片描述

重构水顶点法线

参考:Unity Shader - 简单山脉 - 顶点着色器重构法线,这里不说了,参考的文章说得很清楚的。

                #if REBUILD_NORMAL // 重构法线,参考:https://blog.csdn.net/linjf520/article/details/104859710

                // reconstruct normals
                // 这个4x4数据也可以通过外部传入,可以节省顶点着色器ALU的计算量与L1 caches缓存量。
                const float4x4 offset_xz = {
                    {+1,+0, /* gap **/ +1,-1},  // 右下
                    {+0,-1, /* gap **/ -1,-1},  // 左下
                    {-1,+0, /* gap **/ -1,+1},  // 左上
                    {+0,+1, /* gap **/ +1,+1}   // 右上
                };
                // 默认向量也可以外部传入,因为上面的默认法线是可以调整的
                // 下面我讲默认法线初始化为:up
                float3 sumNormal = float3(0, 1, 0);
                float4 uv4 = 0;
                for (int i = 0; i             
关注
打赏
1664331872
查看更多评论
0.0430s