Unity Shader PostProcessing - 10 - ColorSpreading 颜色传播后效
程序员文章站
2022-05-24 23:46:22
...
文章目录
看到Color Spread Post-Processing Effect Tutorial in Unity上的颜色传播效果图还不错,看到效果图那刻,就知道如何实现了。
先来看看我们实现的最终效果
效果
实践
准备一个颜色鲜艳的场景
灰化图像
fixed4 frag (v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.uv);
return LinearRgbToLuminance(col);
}
2D屏幕颜色传播效果
简单的添加一个2D屏幕UV中心的效果,是个最简单的思路
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);
}
添加边缘柔和
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);
}
添加噪点来过渡
用回我自己的Noise
// 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;
看看效果
混合效果
只要用我们的着色半径减去看似随机的噪点值即可。
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);
}
给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;
给0~1边缘添加亮度
fixed4 bc = _BoundaryTintColor + _BoundaryBrightness;
最后添加整体应用的强度
// combined col
fixed4 combinedCol = lerp(grayCol, tintCol, tint) * bc;
// whole intensity
return lerp(tintCol, combinedCol, _WholeIntensity);
Project
backup : UnityShader_ColorSpreading_2018.3.0f2