Learn ComputeShader 09 Night version lenses
这次将要制作一个类似夜视仪的效果
第一步就是要降低图像的分辨率, 这只需要将id.xy除上一个数字然后再乘上这个数字
可以根据下图理解,很明显通过这个操作在多个像素显示了相同的颜色,并且很多像素颜色被丢失了,自然就会有降低分辨率的效果
效果:
但是这样图像太锐利了,我们加入噪声去解决这个问题
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
uint2 index =(uint2(id.x,id.y)/3*3);
float noise =random((float2)id.xy,time);
float3 srcColor =lerp(source[index].rgb*2,source[index].rgb,noise);
float3 finalColor = srcColor;
output[id.xy] = float4(finalColor, 1);
}
这样以后得到的结果就更接近低分辨率相机的效果
夜视仪通常都是绿色的,我们首先计算出灰度值,然后用灰度值乘上我们设置的一个类似夜视仪的绿色,灰度值越大颜色就越接近我们设置的颜色,反之越接近黑色。最后再将这个颜色与原始颜色根据强度进行插值,
夜视仪上通常有滚动的扫描线。
我们首先将像素的y坐标转换到0-1的范围内,然后生成一个周期性的值模仿扫描线的循环,然后加上0.3避免扫描线的强度过大,最后将它限制在0-1范围内
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
uint2 index =(uint2(id.x,id.y)/3*3);
float noise =random((float2)id.xy,time);
float3 srcColor =lerp(source[index].rgb*2,source[index].rgb,noise);
float3 grayScale = (srcColor.r + srcColor.g + srcColor.b) / 3.0;
float3 tinted = grayScale * tintColor.rgb;
float3 finalColor = lerp(srcColor,tinted, tintStrength);
float uvY = (float)id.y/ (float)source.Length.y;
float scanline = saturate(smoothstep(0.1,0.2, frac(uvY*lines + time*3)) +0.3);
finalColor = lerp(source[id.xy].rgb*0.5,finalColor,scanline);
output[id.xy] = float4(finalColor, 1);
}
效果:
最后就是制作夜视仪的望远镜的效果 。主要原理可参照下面的图片
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
uint2 index =(uint2(id.x,id.y)/3*3);
float noise =random((float2)id.xy,time);
float3 srcColor =lerp(source[index].rgb*2,source[index].rgb,noise);
float3 grayScale = (srcColor.r + srcColor.g + srcColor.b) / 3.0;
float3 tinted = grayScale * tintColor.rgb;
float3 finalColor = lerp(srcColor,tinted, tintStrength);
float uvY = (float)id.y/ (float)source.Length.y;
//float scanline = saturate(smoothstep(0.1,0.2, frac(uvY*5+time*3)) +0.3);
float scanline = frac(uvY*2);
finalColor = lerp(source[id.xy].rgb*0.5,finalColor,scanline);
float2 pt = (float2)id.xy;
float2 center = float2(source.Length * 0.5);
center.x -= radius * 0.7;
float leftLense = incircle(pt, center, radius, edgewidth);
center.x += radius * 1.4;
float rightLense = incircle(pt, center, radius, edgewidth);
float inVision = saturate(leftLense + rightLense);
float3 black = float3(0, 0, 0);
finalColor = lerp(black, finalColor, inVision);
output[id.xy] = float4(finalColor, 1);
}
最终效果: