欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

程序员文章站 2022-05-24 23:46:22
...

看到Color Spread Post-Processing Effect Tutorial in Unity上的颜色传播效果图还不错,看到效果图那刻,就知道如何实现了。

先来看看我们实现的最终效果

效果

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

实践

准备一个颜色鲜艳的场景

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

灰化图像

            fixed4 frag (v2f i) : SV_Target {
                fixed4 col = tex2D(_MainTex, i.uv);
                return LinearRgbToLuminance(col);
            }

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

2D屏幕颜色传播效果

简单的添加一个2D屏幕UV中心的效果,是个最简单的思路
Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

                float2 centerPos = 0.5;
                float dist = length(i.uv - centerPos);
                bool color = false;
                if (_SpreadingRadius != 0) {
                    color = step(dist, _SpreadingRadius);
                }
                fixed4 col = tex2D(_MainTex, i.uv);
                return lerp(LinearRgbToLuminance(col), col, color);

3D世界坐标颜色传播效果

接下来是扩展到3D坐标

确定世界坐标传播中心点

            float3 _SpreadingCenterPos;

将屏幕深度转为世界坐标

之前写的一篇:Unity Shader - 根据片段深度重建片段的世界坐标

核心Shader伪代码:

float depth = Linear01Depth(tex2D(_DepthTex, i.uv).r);
wp = _camWorldPos.xyz + _frustumCornerRay.xyz * depth;

世界坐标半径才着色

            fixed4 frag (v2f i) : SV_Target {
                // depth to world pos
                float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * depth;
                float3 centerPos = _SpreadingCenterPos;
                float3 vec = wp - centerPos;
                // 判断半径着色
                float dist = dot(vec, vec);
                bool color = false;
                if (_SpreadingRadius != 0) {
                    color = step(dist, _SpreadingRadius * _SpreadingRadius);
                }
                fixed4 col = tex2D(_MainTex, i.uv);
                return lerp(LinearRgbToLuminance(col), col, color);
            }

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

添加边缘柔和

            fixed4 frag (v2f i) : SV_Target {
                // depth to world pos
                float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * depth;
                float3 centerPos = _SpreadingCenterPos;
                float3 vec = wp - centerPos;
                // 判断半径着色
                float dist = length(vec);
                float tint = 0;
                tint = step(dist, _SpreadingRadius);
                float fadeOutWidth = _BoundaryFadeOutWidth;
                if (tint == 0 && fadeOutWidth != 0) {
                    tint = 1 - saturate((dist - _SpreadingRadius) / fadeOutWidth); // 这里可以优化为乘法
                }
                fixed4 col = tex2D(_MainTex, i.uv);
                return lerp(LinearRgbToLuminance(col), col, tint);
            }

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

添加噪点来过渡

用回我自己的Noise
Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

                // depth to world pos
                float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * depth;
                float3 centerPos = _SpreadingCenterPos;
                float3 vec = wp - centerPos;
                // 判断半径着色
                float dist = length(vec);
                float radius = _SpreadingRadius;

                float2 noiseUV = wp.xz * _WorldPosScale;
                float noise = tex2D(_NoiseTex, noiseUV).r * _NoiseScale;
                return noise;

看看效果
Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效
混合效果

只要用我们的着色半径减去看似随机的噪点值即可。

            fixed4 frag (v2f i) : SV_Target {
                // depth to world pos
                float depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * depth;
                float3 centerPos = _SpreadingCenterPos;
                float3 vec = wp - centerPos;
                // 判断半径着色
                float dist = length(vec);
                float radius = _SpreadingRadius;

                float2 noiseUV = wp.xz * _WorldPosScale;
                float noise = tex2D(_NoiseTex, noiseUV).r * _NoiseScale;
                // return noise;

                radius -= noise;

                float tint = 0;
                tint = step(dist, radius);
                float fadeOutWidth = _BoundaryFadeOutWidth;
                if (tint == 0 && fadeOutWidth != 0) {
                    tint = 1 - saturate((dist - radius) / fadeOutWidth); // 这里可以优化为乘法
                }

                fixed4 col = tex2D(_MainTex, i.uv);
                return lerp(LinearRgbToLuminance(col), col, tint);
            }

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

给0~1边缘的着色

                // boundary color
                bool isBoundary = tint > 0 && tint < 1;
                fixed4 bc = _BoundaryTintColor;
                bc = lerp(1, lerp(1, bc, _BoundaryTintColor.a), isBoundary);

                // tint source color
                fixed4 tintCol = tex2D(_MainTex, i.uv);
                // gray color
                fixed4 grayCol = LinearRgbToLuminance(tintCol);
                return lerp(grayCol, tintCol, tint) * bc;

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效
Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

给0~1边缘添加亮度

                fixed4 bc = _BoundaryTintColor + _BoundaryBrightness;

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

最后添加整体应用的强度

                // combined col
                fixed4 combinedCol = lerp(grayCol, tintCol, tint) * bc;
                // whole intensity
                return lerp(tintCol, combinedCol, _WholeIntensity);

Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效

Project

backup : UnityShader_ColorSpreading_2018.3.0f2

References