unity使用renderFeature生成屏幕的遮罩
之前有一个使用了GPUInstance简单实现类似For the king的那种地图遮挡效果的,这种随便百度一下就有了,就不在这里说了;现在这个是简单使用RenderFeature实现的一个地图信息遮挡(因为只是简单出demo体验王法,就简单来)!
简单说明一下原理
第一步:使用一张RT,单独绘制场景中代表视野范围的六边形的格子,这张RT就是遮罩Mask;
第二步:正常渲染场景中的所有物件
第三步:在Post-Process前,理由Mask对相机正常渲染的Buffer进行Blit
阶段性的截图
渲染mask
Blit后
缺陷
这个其实挺多问题的,但是贵在性能好呀,而且实现简单~
[*]因为是最后基于屏幕的blit,导致遮挡会直接在屏幕上,对于非垂直视图,裁剪就特别恶心了!
[*]有人说类似billboard的方式贴瓦片,但是这样在相机比较水平的时候,那就能直接看到很远了~(同样都有这个问题)
资料
以下是这次使用的代码和shader, 因为比较简单,这里就只是记录一下,放个代码而已,有兴趣自己可以copy代码下来自己跑跑。
Shader "Custom/DrawViewer"
{
Properties
{
_BaseTex("主纹理", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
}
Pass
{
ZWrite On
ZTest On
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct MeshProperties
{
float4x4 mat;
float status;
};
TEXTURE2D(_BaseTex);
SAMPLER(sampler_BaseTex);
float4 _BaseTex_ST;
StructuredBuffer<MeshProperties> _Properties;
struct Attributes
{
float4 positionOS : POSITION;
uint instanceID : SV_InstanceID;
float2 texcoord : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 uv : TEXCOORD0;
};
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
float4 pos = mul(_Properties.mat, input.positionOS);
output.positionCS = TransformWorldToHClip(pos);
output.uv.xy = input.texcoord;
output.uv.z = _Properties.status;
return output;
}
half4 frag(Varyings input) : SV_Target
{
if (input.uv.z > 0.5)
return half4(1,1,0,1);
return half4(1,0,0, 1);
}
ENDHLSL
}
}
FallBack &#34;Hidden/Universal Render Pipeline/FallbackError&#34;
}
Shader &#34;Unlit/FogBlit&#34;
{
Properties
{
DigRT (&#34;Texture&#34;, 2D) = &#34;white&#34; {}
_MainTex (&#34;Texture&#34;, 2D) = &#34;white&#34; {}
}
SubShader
{
Tags { &#34;RenderType&#34;=&#34;Opaque&#34; }
LOD 100
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include &#34;Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl&#34;
TEXTURE2D(DigRT);
SAMPLER(samplerDigRT);
float4 DigRT_ST;
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_ST;
struct Attributes
{
float4 positionHCS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4positionCS: SV_POSITION;
float2uv : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = TransformObjectToHClip(input.positionHCS);
return output;
}
half4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float4 color = SAMPLE_TEXTURE2D_X(DigRT, samplerDigRT, input.uv);
float4 color2 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv);
if (color.r < 0.5)
{
return color;
}
return color2;
}
ENDHLSL
}
}
}简单的feature代码
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class DrawFullScreenViewerFeature : ScriptableRendererFeature
{
/// <summary>
/// 画视野使用的材质
/// </summary>
public Material material;
/// <summary>
/// 最后合成阶段的材质
/// </summary>
public Material blitMaterial;
/// <summary>
/// 每个视野格子的mesh
/// </summary>
public Mesh mesh;
/// <summary>
/// pass
/// </summary>
private DrawFullScreenViewerPass _fullScreenViewerPass;
private BlitFullScreenViewerPass _blitFullScreenViewerPass;
public RenderPassEvent passEvent = RenderPassEvent.BeforeRenderingShadows;
public RenderPassEvent blitPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
/// <summary>
/// 临时rt
/// </summary>
private RenderTexture rt1 = null;
/// <summary>
/// 临时rt
/// </summary>
private RenderTexture rt2 = null;
public override void Create()
{
_fullScreenViewerPass = new DrawFullScreenViewerPass(material, mesh);
_blitFullScreenViewerPass = new BlitFullScreenViewerPass(blitMaterial);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
var width = renderingData.cameraData.camera.pixelWidth;
var heigh = renderingData.cameraData.camera.pixelHeight;
if (rt1 == null)
{
rt1 = RenderTexture.GetTemporary(width, heigh);
rt2 = RenderTexture.GetTemporary(width, heigh);
}
if (material != null && mesh != null)
{
_fullScreenViewerPass.SetRTs(rt1);
_blitFullScreenViewerPass.SetRTs(rt1, rt2);
_fullScreenViewerPass.renderPassEvent = passEvent;
_blitFullScreenViewerPass.renderPassEvent = blitPassEvent;
renderer.EnqueuePass(_fullScreenViewerPass);
renderer.EnqueuePass(_blitFullScreenViewerPass);
}
}
}
public class DrawFullScreenViewerPass : ScriptableRenderPass
{
private Material _material;
private Mesh _mesh;
private RenderTexture _rt;
public DrawFullScreenViewerPass(Material material, Mesh mesh)
{
_material = material;
_mesh = mesh;
}
public void SetRTs(RenderTexture rt)
{
_rt = rt;
FogDataMgr.Instance.Configure(_mesh, _material);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(&#34;DrawFullScreenViewer&#34;);
// 执行draw
FogDataMgr.Instance.DigView(cmd, _rt);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
cmd.SetRenderTarget(renderingData.cameraData.renderer.cameraColorTargetHandle);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void FrameCleanup(CommandBuffer cmd)
{
FogDataMgr.Instance.FrameCleanup(cmd);
}
}
public class BlitFullScreenViewerPass : ScriptableRenderPass
{
private readonly Material _material;
private RenderTexture _rt1;
private RenderTexture _rt2;
public BlitFullScreenViewerPass(Material mat)
{
_material = mat;
}
public void SetRTs(RenderTexture rt1, RenderTexture rt2)
{
_rt1 = rt1;
_rt2 = rt2;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(&#34;BlitFullScreenViewerPass&#34;);
FogDataMgr.Instance.Blit(cmd, _material, ref _rt1, ref _rt2, ref renderingData);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
FogDataMgr.cs
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class FogDataMgr
{
struct MeshProperties
{
public float4x4 mat;
public float status;
};
private static FogDataMgr _instance = null;
public static FogDataMgr Instance
{
get
{
if (_instance == null)
{
_instance = new FogDataMgr();
}
return _instance;
}
}
private Dictionary<ulong, int> ViewerGridsStatus = new Dictionary<ulong, int>();
private ComputeBuffer argsBuffer;
private ComputeBuffer meshPropertiesBuffer;
private Material _fogMaterial;
private Mesh _fogMesh;
private readonly string PropertyName = &#34;_Properties&#34;;
private uint _width;
private bool _canDraw = false;
private uint[] args;
public void Config(uint width, uint heigh)
{
_width = width;
ViewerGridsStatus.Clear();
_canDraw = false;
args = new uint { 0, 0, 0, 0, 0 };
if (argsBuffer!= null)
argsBuffer.Dispose();
argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
argsBuffer.SetData(args);
}
public void AddViewerPoint(Vector2Int point, int status)
{
ulong key = (ulong)point.x * _width + (ulong)point.y;
if (!ViewerGridsStatus.ContainsKey(key))
ViewerGridsStatus.Add(key, status);
}
public void Apply()
{
CreateBuffer();
_canDraw = true;
}
private void CreateBuffer()
{
args = (uint)ViewerGridsStatus.Count;
if (argsBuffer!= null)
argsBuffer.Dispose();
argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
argsBuffer.SetData(args);
MeshProperties[] properties = new MeshProperties;
int index = 0;
foreach (var (key, value) in ViewerGridsStatus)
{
Vector3 position = new Vector3(key/_width, 0, key%_width);
Quaternion rotation = Quaternion.Euler(Vector3.zero);
Vector3 scale = Vector3.one;
properties.mat = Matrix4x4.TRS(position, rotation, scale);
properties.status = value;
index++;
}
int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MeshProperties));
if (meshPropertiesBuffer!= null)
meshPropertiesBuffer.Dispose();
meshPropertiesBuffer = new ComputeBuffer(ViewerGridsStatus.Count, size);
meshPropertiesBuffer.SetData(properties);
_fogMaterial.SetBuffer(PropertyName, meshPropertiesBuffer);
}
public void DigView(CommandBuffer cmd, RenderTexture rt)
{
cmd.SetRenderTarget(rt);
cmd.ClearRenderTarget(true, true, Color.clear, 1);
if (_canDraw)
cmd.DrawMeshInstancedIndirect(_fogMesh, 0, _fogMaterial, -1, argsBuffer);
}
public void FrameCleanup(CommandBuffer cmd)
{
}
public void Blit(CommandBuffer cmd, Material _material, ref RenderTexture rt, ref RenderTexture rt2, ref RenderingData renderingData)
{
_material.SetTexture(&#34;DigRT&#34;, rt);
cmd.Blit(renderingData.cameraData.renderer.cameraColorTargetHandle, rt2);
cmd.Blit(rt2, renderingData.cameraData.renderer.cameraColorTargetHandle, _material, 0);
}
public void Configure(Mesh mesh, Material material)
{
_fogMaterial = material;
_fogMesh = mesh;
args = new uint { 0, 0, 0, 0, 0 };
args = _fogMesh.GetIndexCount(0);
args = _fogMesh.GetIndexStart(0);
args = _fogMesh.GetBaseVertex(0);
}
}
页:
[1]