【unity】RenderFeature的应用(生成水平面的网格线)
在URP里RenderFeature是用于后处理效果上的,也还可以实现一些特殊的效果,比如生成网格线。我们可以使用 CommandBuffer来创建地面网格,这样的话可以通过调整 CommandBuffer的参数来控制地面网格的密度。
实现效果
创建流程
- 创建RenderFeature模板
- 编写CommandBuffer生成网格方法
- 增加到 渲染管线资产
创建RenderFeature模板
- 在Project面板Create→Rendering→URP Renderer Feature,默认命名为CustomRenderPassFeature
简介
URP Renderer Feature模板继承ScriptableRendererFeature
ScriptableRendererFeature由两个类 CustomRenderPassFeature 与 CustomRenderPass 组成,CustomRenderPass继承ScriptableRenderPass
ScriptableRendererFeature
Create:是用来初始化这个 Feature 的资源
AddRenderPasses:在 Renderer 中插入一个或多个 ScriptableRenderPass
ScriptableRenderPass
Configure :在执行渲染过程之前,Renderer 将调用此方法
Execute:是这个类的核心方法,定义我们的执行规则 ,实现渲染逻辑
FrameCleanup:可用于释放通过此过程创建的分配资源
编写CommandBuffer生成网格方法
在创建的RenderFeature模板中编写脚本如下:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class CustomRenderPassFeature : ScriptableRendererFeature
{
public float lineCount;
class CustomRenderPass : ScriptableRenderPass
{
public float lineCount;
public bool isRender = false;
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if ( !Application.isPlaying) return;
ProfilingSampler mProfilingSampler = new ProfilingSampler("Test1");
CommandBuffer cmd = CommandBufferPool.Get("Test1 Cmd");
Material cmdMat1 = new Material(Shader.Find("Models/LineShader"));
using (new ProfilingScope(cmd, mProfilingSampler))
{
Mesh meshRenderer = CreateGridMesh(Color.green, lineCount);
cmd.DrawMesh(meshRenderer, Matrix4x4.identity, cmdMat1);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
/// <summary>
/// 创建网格
/// </summary>
/// <param name="color"></param>
/// <param name="spacing"></param>
/// <param name="linesCount"></param>
/// <returns></returns>
public Mesh CreateGridMesh(Color color, float spacing, int linesCount = 150)
{
int count = linesCount / 2;
Mesh mesh = new Mesh();
mesh.name = "Grid " + spacing;
int index = 0;
int[] indices = new int[count * 8];
Vector3[] vertices = new Vector3[count * 8];
Color[] colors = new Color[count * 8];
for (int i = -count; i < count; ++i)
{
vertices[index] = new Vector3(i * spacing, 0, -count * spacing);
vertices[index + 1] = new Vector3(i * spacing, 0, count * spacing);
vertices[index + 2] = new Vector3(-count * spacing, 0, i * spacing);
vertices[index + 3] = new Vector3(count * spacing, 0, i * spacing);
indices[index] = index;
indices[index + 1] = index + 1;
indices[index + 2] = index + 2;
indices[index + 3] = index + 3;
colors[index] = colors[index + 1] = colors[index + 2] = colors[index + 3] = color;
index += 4;
}
Debug.Log(vertices.Length);
mesh.vertices = vertices;
mesh.SetIndices(indices, MeshTopology.Lines, 0);
return mesh;
}
}
CustomRenderPass m_ScriptablePass;
/// <inheritdoc/>
public override void Create()
{
m_ScriptablePass = new CustomRenderPass();
m_ScriptablePass.lineCount = lineCount;
m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
}
/// <summary>
/// 用于修改参数
/// </summary>
public void SetParam()
{
m_ScriptablePass.lineCount = lineCount;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(m_ScriptablePass);
}
}
增加到渲染管线资产(RenderPipelineAsset)
- 找到URP Asset(位置: Edit→ProjectSetting→Quality→Rendering→RenderPipelineAsset)
- 找到URP Universal Renderer(位置:URP Asset→Rendering→RendererList)
- 增加Renderer Feature,点击URP Universal Renderer的Add Renderer Feature添加之前创建的Renderer Feature模板
补充
RenderFeature模板自定义参数调整方法
方法一:
CustomRenderPassFeature custom=renderData.rendererFeatures.OfType<CustomRenderPassFeature>().FirstOrDefault();
custom.lineCount =200;
custom.SetParam();
方法二:
[SerializeField]
UniversalRendererData renderData;
List<ScriptableRendererFeature> rendererFeatures;
Dictionary<string, ScriptableRendererFeature> innerFeatures = new Dictionary<string, ScriptableRendererFeature>();
CustomRenderPassFeature custom;
void Start()
{
rendererFeatures = renderData.rendererFeatures;
for (int i = 0; i < rendererFeatures.Count; i++)
{
var feature = rendererFeatures[i];
innerFeatures[feature.name] = feature;
}
ScriptableRendererFeature rendererFeature;
innerFeatures.TryGetValue("CustomRenderPassFeature", out rendererFeature);
custom = rendererFeature as CustomRenderPassFeature;
}
void SetParam()
{
custom.lineCount = 200;
custom.SetParam();
}
内置渲染管线使用 CommandBuffer来创建地面网格
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class CommandBufferTest : MonoBehaviour
{
CommandBuffer cmdBuffer;
public Material cmdMat1;
public Camera mainCamera;
public float m_alpha = 1.0f;
bool m_zTest = false;
Mesh m_grid0Mesh;
private void Start()
{
cmdBuffer = new CommandBuffer() { name = "CameraCmdBuffer" };
mainCamera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, cmdBuffer);
m_zTest = true;
DrawMesh();
}
//关机调用
void OnDestroy()
{
Cleanup();
}
//卸载调用
void OnDisable()
{
Cleanup();
}
//载入调用
void OnEnable()
{
if (m_zTest)
DrawMesh();
}
public void DrawMesh()
{
cmdBuffer.Clear();
m_grid0Mesh = CreateGridMesh(Color.green, 10);
cmdBuffer.DrawMesh(m_grid0Mesh, Matrix4x4.identity, cmdMat1);
}
public Mesh CreateGridMesh(Color color, float spacing, int linesCount = 150)
{
int count = linesCount / 2;
Mesh mesh = new Mesh();
mesh.name = "Grid " + spacing;
int index = 0;
int[] indices = new int[count * 8];
Vector3[] vertices = new Vector3[count * 8];
Color[] colors = new Color[count * 8];
for (int i = -count; i < count; ++i)
{
vertices[index] = new Vector3(i * spacing, 0, -count * spacing);
vertices[index + 1] = new Vector3(i * spacing, 0, count * spacing);
vertices[index + 2] = new Vector3(-count * spacing, 0, i * spacing);
vertices[index + 3] = new Vector3(count * spacing, 0, i * spacing);
indices[index] = index;
indices[index + 1] = index + 1;
indices[index + 2] = index + 2;
indices[index + 3] = index + 3;
colors[index] = colors[index + 1] = colors[index + 2] = colors[index + 3] = color;
index += 4;
}
mesh.vertices = vertices;
mesh.SetIndices(indices, MeshTopology.Lines, 0);
return mesh;
}
private void Cleanup()
{
if (m_grid0Mesh != null)
{
Destroy(m_grid0Mesh);
}
}
}
LineShader
Shader "Models/LineShader"
{
Properties
{
_Color("Color", Color) = (1, 1, 1, 1)
[Enum(Off,0,On,1)]_ZWrite("ZWrite", Float) = 1.0
}
SubShader
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
LOD 100
Pass
{
ZWrite[_ZWrite]
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
fixed4 _Color;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return _Color;
}
ENDCG
}
}
}