问题背景
恐怖游戏在黑夜或者某些场景下,需要用雾或者黑暗遮盖视野,搭建游戏氛围
效果
场景中,雾会遮挡场景和怪物,但是在玩家视野内雾会消散,距离玩家越近雾越薄。
当前是第三人称视角,但是可以轻松的把这个效果转换为第一人称视角。
原理
正如屏幕空间的高度雾,这里做一个屏幕空间的视野雾。
采用特殊的材质在相机前方绘制一个能遮盖相机的矩形。如果矩形覆盖的像素点在视野内,就降低雾效果,否则绘制雾效果。
实现
urp下使用RenderFeature + 自定义shader实现
简略步骤
在相机节点下放置一个Plane,隐藏它
编写shader并创建材质
像素着色器代码如下,原理为采样深度,根据深度计算出当前像素的世界坐标,根据坐标和玩家位置的关系确定雾效果
float4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
//计算屏幕uv
float2 screenUV = GetNormalizedScreenSpaceUV(input.positionCS);
//采样深度
#if UNITY_REVERSED_Z
float depth = SampleSceneDepth(screenUV);
#else
// Adjust Z to match NDC for OpenGL ([-1, 1])
float depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(screenUV));
#endif
//根据深度计算当前像素所代表的世界空间坐标
float3 worldPos = ComputeWorldSpacePosition(screenUV, depth, UNITY_MATRIX_I_VP);
//计算角色位置和当前渲染的像素所代表的世界坐标的距离
float distanceVal = distance(worldPos, _PosWS);
//做过渡
float t = (max(distanceVal - (_Range * 0.8), 0)) / (_Range * 1.2);
//计算透明度,透明度越低雾越薄
float alpha = lerp(0, 1, saturate(t * t));
//返回像素颜色
return float4(_Color.rgb, alpha * _Color.a);
}
创建并且配置RenderFeature到URP管线的自定义Renderer
自定义Pass中的核心代码,使用指定的材质绘制隐藏的Plane
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if(null == Renderer)
{
if(null != SceneFogController.Instance)
{
Renderer = SceneFogController.Instance.Renderer;
}
}
if (null == FogMat || null == Renderer)
{
return;
}
var cmd = CommandBufferPool.Get("FogPass");
cmd.DrawRenderer(Renderer, FogMat, 0, 0);
//Matrix4x4 material = new Matrix4x4();
//material.SetTRS(_renderer.transform.position, _renderer.transform.rotation, Vector3.one);
//cmd.DrawMesh(_renderer.gameObject.GetComponent<MeshFilter>().sharedMesh, material, FogMat);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}