[unity] Application of RenderFeature (generate grid lines on the horizontal plane)

[unity] Application of RenderFeature (generate grid lines on the horizontal plane)

In URP, RenderFeature is used for post-processing effects, and can also achieve some special effects, such as generating grid lines. We can use CommandBuffer to create a ground grid, so that the density of the ground grid can be controlled by adjusting the parameters of the CommandBuffer.

achieve effect

create process

  1. Create a RenderFeature Template
  2. Write CommandBuffer to generate grid method
  3. Add to Render Pipeline Assets

Create a RenderFeature Template

  • In the Project panel Create→Rendering→URP Renderer Feature, the default name is CustomRenderPassFeature

Introduction

URP Renderer Feature template inherits ScriptableRendererFeature

ScriptableRendererFeature consists of two classes CustomRenderPassFeature and CustomRenderPass, CustomRenderPass inherits ScriptableRenderPass

ScriptableRendererFeature

Create : It is used to initialize the resource of this Feature

AddRenderPasses : Insert one or more ScriptableRenderPass in Renderer

ScriptableRenderPass

Configure : Renderer will call this method before executing the rendering process

Execute : It is the core method of this class, which defines our execution rules and implements rendering logic

FrameCleanup : Can be used to release allocated resources created by this process

Write CommandBuffer to generate grid method

Write the script in the created RenderFeature template as follows:

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);
    }
}

Add to RenderPipelineAsset (RenderPipelineAsset)

  • Find the URP Asset (location: Edit→ProjectSetting→Quality→Rendering→RenderPipelineAsset)
  • Find URP Universal Renderer (Location: URP Asset→Rendering→RendererList)
  • Add Renderer Feature, click Add Renderer Feature of URP Universal Renderer to add the previously created Renderer Feature template

Replenish

RenderFeature template custom parameter adjustment method

method one:

    CustomRenderPassFeature custom=renderData.rendererFeatures.OfType<CustomRenderPassFeature>().FirstOrDefault();
     custom.lineCount =200;
     custom.SetParam();

Method Two:

    [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();    
}

The built-in rendering pipeline uses the CommandBuffer to create the ground mesh

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
		}
	}
}

Guess you like

Origin blog.csdn.net/dxs1990/article/details/131514661