一.如何获取屏幕空间坐标
1.SV_POSITION 语义,该语义是获取经过MVP矩阵变换的坐标值,而经过顶点着色器之后,裁剪和投影过程为渲染管线自动进行(只需在顶点着色器中手动将顶点从Object空间转换到Clip空间即可),完成这两个过程后执行片元着色器前,顶点将会被转换到屏幕空间上来,所有SV_POSITION的x和y分量即为该顶点在屏幕空间下的坐标。
2.使用VPOS,VPOS为二维变量,其中存储的即是屏幕空间坐标,如果与SV_POSITION同时使用会重复定义,解决办法见参考,其中也印证了1内容。Unity - Manual: Shader semantics
3.使用Unity自带宏,ComputeScreenPos。
二.溶解Shader的基本思路
目的:这种基于屏幕空间的Shader大多应用于当摄像头靠近某些物体时,会产生的溶解效果,如靠近树叶、草丛或人物。
思路:
方法一:
1.计算当前摄像头与物体的距离。
2024.1.18方案(可行):
1.直接将顶点转换至摄像机空间下,通过Lenght函数计算与摄像机的距离。
2.使用smoothstep(0,开始溶解距离,顶点到摄像机距离)将距离映射到0~1范围。
图1 输出pos到Camera的距离作为r通道输出
2.判断该距离是否超过设定阈值,该阈值即为smoothstep中的第二个变量。
3.输出。
方法二:基于Dither算法的溶解效果
思想和上述差不多,假如了颜色抖动的算法。
代码:
方法一
screenPos.xy = floor(screenPos.xy * 0.1) * 0.5;
float checker = frac(screenPos.r + screenPos.g);
fixed4 c = tex2D (_MainTex, i.uv);
float disRamp = smoothstep(0,_Distance,i.vertexCameraDis)- 1;
float noise = disRamp * checker;
clip(noise);
return c;
方法二:
fixed4 col = tex2D(_MainTex, i.uv);
float posViewDis = distance(i.posWS, _WorldSpaceCameraPos.xyz);
float disRamp = smoothstep(0.5,1,posViewDis);
// float disRamp = smoothstep(0,1,length(i.posVS));
float4x4 thresholMatrix =
{ 1.0 / 17.0, 9.0 /17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
};
float2 pos = i.screenPos.xy /i.screenPos.w;
pos *= _ScreenParams.xy;
half noise = disRamp - thresholMatrix[fmod(pos.x,4)] * thresholMatrix[fmod(pos.y,4)];
clip(noise);
// col = float4(thresholMatrix[fmod(pos.x,4)] * thresholMatrix[fmod(pos.y,4)]);
return col;
参考: