Creating a custom render pipeline

Creating a custom render pipeline

Unity provides two prebuilt render pipelines based on the Scriptable Render Pipeline (SRP): the High Definition Render Pipeline (HDRP), and the Universal Render Pipeline (URP). HDRP and URP offer extensive customization options; however, if you want even more control over your rendering
 pipeline, you can create your own custom render pipeline based on SRP.

Read this documentation if you want to create your own custom SRP, if you want to create a custom version of URP or HDRP, or if you want to understand how SRP works on a fundamental level.

///

Creating a custom render pipeline based on the Scriptable Render Pipeline

This page contains information on how to get started with creating your own custom render pipeline based on the Scriptable Render Pipeline (SRP).

Creating a new project and installing the packages needed for a custom render pipeline

These instructions show you how to create a custom render pipeline using the SRP Core package. SRP Core is a package made by Unity that contains a reusable code to help you make your own render pipeline, including boilerplate code for working with platform-specific graphics APIs, utility functions for common rendering
 operations, and the shader
 library that URP and HDRP use. For more information on SRP Core, see the SRP Core package documentation.

  1. Create a new Unity Project.
  2. Use Git to create a clone of the SRP source code repository. You can place the SRP source code in any location on your disk, as long as it is not in one of the reserved Project sub-folders.
  3. Use Git to update your copy of the SRP source code to a branch that is compatible with your version of the Unity Editor. Read Using the latest version in the SRP repository documentation for information on branches and versions.
  4. Open your Project in Unity, and install the following packages from the SRP source code folder on your disk, in the following order. For information on installing packages from disk, see Installing a package from a local folder.
    • com.unity.render-pipelines.core.
    • Optional: com.unity.render-pipelines.shadergraph. Install this package if you intend to use Shader Graph or modify the Shader Graph source code as part of your custom SRP.
    • Optional: com.unity.render-pipelines.visualeffectgraph. Install this package if you intend to use Visual Effect Graph or modify the Visual Effect Graph source code as part of your custom SRP.

You can now debug and modify the scripts
 in your copy of the SRP source code, and see the results of your changes in your Unity Project.

Creating a custom version of URP or HDRP

The Universal Render Pipeline (URP) and the High Definition Render Pipeline (HDRP) offer extensive customization options to help you achieve the graphics and performance you need. However, if you want even more control, you can create a custom version of one of these render pipelines, and modify the source code.

Follow steps 1–3 in the section above, Creating a new Project and installing the packages needed for a custom SRP. When you reach step 4, install the following packages in the following order:

URP:

  • com.unity.render-pipelines.core
  • com.unity.render-pipelines.shadergraph
  • com.unity.render-pipelines.universal

HDRP:

  • com.unity.render-pipelines.core
  • com.unity.render-pipelines.shadergraph
  • com.unity.render-pipelines.high-defintion

//

Creating a Render Pipeline Asset and Render Pipeline Instance in a custom render pipeline

If you are creating your own render pipeline based on the Scriptable Render Pipeline (SRP), your Project must contain:

  • A script that inherits from RenderPipelineAsset and overrides its CreatePipeline() method. This script defines your Render Pipeline Asset.
  • A script that inherits from RenderPipeline, and overrides its Render() method. This script defines your Render Pipeline Instance, and is where you write your custom rendering
     code.
  • A Render Pipeline Asset that you have created from your RenderPipelineAsset script. This asset acts as a factory class for your Render Pipeline Instance.

Because these elements are so closely related, you should create them at the same time.

Creating a basic Render Pipeline Asset and Render Pipeline Instance

The following example shows how to create a script for a basic custom Render Pipeline Asset that instantiates the Render Pipeline Instance, a script that defines the Render Pipeline Instance, and the Render Pipeline Asset itself.

  1. Create a C# script called ExampleRenderPipelineAsset.cs.

  2. Copy and paste the following code into the new script:

    using UnityEngine;
    using UnityEngine.Rendering;
        
    // The CreateAssetMenu attribute lets you create instances of this class in the Unity Editor.
    [CreateAssetMenu(menuName = "Rendering/ExampleRenderPipelineAsset")]
    public class ExampleRenderPipelineAsset : RenderPipelineAsset
    {
        // Unity calls this method before rendering the first frame.
        // If a setting on the Render Pipeline Asset changes, Unity destroys the current Render Pipeline Instance and calls this method again before rendering the next frame.
        protected override RenderPipeline CreatePipeline() {
            // Instantiate the Render Pipeline that this custom SRP uses for rendering.
            return new ExampleRenderPipelineInstance();
        }
    }
    
  3. Create a C# script called ExampleRenderPipelineInstance.cs.

  4. Copy and paste the following code into the new script:

    using UnityEngine;
    using UnityEngine.Rendering;
        
    public class ExampleRenderPipelineInstance : RenderPipeline
    {
        public ExampleRenderPipelineInstance() {
        }
        
        protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
            // This is where you can write custom rendering code. Customize this method to customize your SRP.
        }
    }
    
  5. In the Project view, either click the add (+) button, or open the context menu and navigate to Create, and then choose Rendering > Example Render Pipeline Asset. Unity creates a new Render Pipeline Asset in the Project view.

Creating a configurable Render Pipeline Asset and Render Pipeline Instance

By default, a Render Pipeline Asset stores
 information about which Render Pipeline Instance to use for rendering, and the default Materials and Shaders
 to use in the Editor. In your RenderPipelineAsset script, you can extend your Render Pipeline Asset so that it stores additional data, and you can have multiple different Render Pipeline Assets with different configurations in your Project. For example, you might use a Render Pipeline Asset to hold configuration data for each different tier of hardware. The High Definition Render Pipeline (HDRP) and the Universal Render Pipeline (URP) include examples of this.

The following example shows how to create a RenderPipelineAsset script that defines a Render Pipeline Asset with public data that you can set for each instance using the Inspector
, and a Render Pipeline Instance that receives a Render Pipeline Asset in its constructor and uses data from that Render Pipeline Asset.

  1. Create a C# script called ExampleRenderPipelineAsset.cs.

  2. Copy and paste the following code into the new script:

    using UnityEngine;
    using UnityEngine.Rendering;
        
    // The CreateAssetMenu attribute lets you create instances of this class in the Unity Editor.
    [CreateAssetMenu(menuName = "Rendering/ExampleRenderPipelineAsset")]
    public class ExampleRenderPipelineAsset : RenderPipelineAsset
    {
        // This data can be defined in the Inspector for each Render Pipeline Asset
        public Color exampleColor;
        public string exampleString;
        
            // Unity calls this method before rendering the first frame.
           // If a setting on the Render Pipeline Asset changes, Unity destroys the current Render Pipeline Instance and calls this method again before rendering the next frame.
        protected override RenderPipeline CreatePipeline() {
            // Instantiate the Render Pipeline that this custom SRP uses for rendering, and pass a reference to this Render Pipeline Asset.
            // The Render Pipeline Instance can then access the configuration data defined above.
            return new ExampleRenderPipelineInstance(this);
        }
    }
    
  3. Create a C# script called ExampleRenderPipelineInstance.cs.

  4. Copy and paste the following code into the new script:

    using UnityEngine;
    using UnityEngine.Rendering;
        
    public class ExampleRenderPipelineInstance : RenderPipeline
    {
        // Use this variable to a reference to the Render Pipeline Asset that was passed to the constructor
        private ExampleRenderPipelineAsset renderPipelineAsset;
        
        // The constructor has an instance of the ExampleRenderPipelineAsset class as its parameter.
        public ExampleRenderPipelineInstance(ExampleRenderPipelineAsset asset) {
            renderPipelineAsset = asset;
        }
        
        protected override void Render(ScriptableRenderContext context, Camera[] cameras) {
            // This is an example of using the data from the Render Pipeline Asset.
            Debug.Log(renderPipelineAsset.exampleString);
                
            // This is where you can write custom rendering code. Customize this method to customize your SRP.
        }
    }
    
    
  5. In the Project view, either click the add (+) button, or open the context menu and navigate to Create, and then choose Rendering > Example Render Pipeline Asset. Unity creates a new Render Pipeline Asset in the Project view.

///

Creating a simple render loop in a custom render pipeline

A render loop is the term for all of the rendering
 operations that take place in a single frame. This page contains information on creating a simple render loop in a custom render pipeline that is based on Unity’s Scriptable Render Pipeline.

The code examples on this page demonstrate the basic principles of using the Scriptable Render Pipeline. You can use this information to build your own custom Scriptable Render Pipeline, or to understand how Unity’s prebuilt Scriptable Render Pipelines work.

Preparing your project

Before you begin writing the code for your render loop, you must prepare your project.

The steps are as follows:

  1. Create an SRP-compatible shader.
  2. Create one or more GameObjects to render.
  3. Create the basic structure of your custom SRP.
  4. Optional: If you plan to extend your simple custom SRP to add more complex functionality, install the SRP Core package. The SRP Core package includes the SRP Core shader
     library (which you can use to make your shaders SRP Batcher compatible), and utility functions for common operations. For more information, see the SRP Core package documentation.

Creating an SRP-compatible shader

In the Scriptable Render Pipeline, you use the LightMode Pass tag to determine how to draw geometry. For more information on Pass tags, see ShaderLab: assigning tags to a Pass.

This task shows you how to create a very simple unlit Shader object with a LightMode Pass tag value of ExampleLightModeTag.

  1. Create a new shader asset in your project. For instructions on creating a shader asset, see Shader assets.
  2. In your Project view, double click the shader asset to open the shader source code in a text editor.
  3. Replace the existing code with the following:
// This defines a simple unlit Shader object that is compatible with a custom Scriptable Render Pipeline.
// It applies a hardcoded color, and demonstrates the use of the LightMode Pass tag.
// It is not compatible with SRP Batcher.

Shader "Examples/SimpleUnlitColor"
{
    SubShader
    {
        Pass
        {
            // The value of the LightMode Pass tag must match the ShaderTagId in ScriptableRenderContext.DrawRenderers
            Tags { "LightMode" = "ExampleLightModeTag"}

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

    float4x4 unity_MatrixVP;
            float4x4 unity_ObjectToWorld;

            struct Attributes
            {
                float4 positionOS   : POSITION;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
            };

            Varyings vert (Attributes IN)
            {
                Varyings OUT;
                float4 worldPos = mul(unity_ObjectToWorld, IN.positionOS);
                OUT.positionCS = mul(unity_MatrixVP, worldPos);
                return OUT;
            }

            float4 frag (Varyings IN) : SV_TARGET
            {
                return float4(0.5,1,0.5,1);
            }
            ENDHLSL
        }
    }
}

Creating a GameObject to render

To test that your render loop works, you must create something to render. This task shows you how to put GameObjects
 in your scene
 that use the SRP-compatible shader that you created in the previous task.

  1. Create a new material asset in your Unity project. For instructions see Materials
    .
  2. Assign the shader asset to the material asset. For instructions, see Materials.
  3. Create a cube in your scene. For instructions, see Primitive objects.
  4. Assign the material to it. For instructions, see Materials.

Creating the basic structure of your custom SRP

The final stage of preparation is to create the basic source files needed for your custom SRP, and tell Unity to begin rendering using the custom SRP.

  1. Create a class that inherits from RenderPipeline and a compatible Render Pipeline Asset, following the instructions in Creating a Render Pipeline Instance and Render Pipeline Asset
  2. Set the active Render Pipeline Asset, following the instructions in Setting the active Render Pipeline Asset. Unity will begin rendering using the custom SRP immediately, which means that your Scene view
     and Game view will be blank until you add code to your custom SRP.

Creating the render loop

In a simple render loop, the basic operations are:

  • Clearing the render target, which means removing the geometry that was drawn during the last frame.
  • Culling, which means filtering out geometry that is not visible to a Camera
    .
  • Drawing, which means telling the GPU what geometry to draw, and how to draw it.

Clearing the render target

Clearing means removing the things that were drawn during the last frame. The render target is usually the screen; however, you can also render to textures to create a “picture in picture” effect. These examples demonstrate how to render to the screen, which is Unity’s default behavior.

To clear the render target in the Scriptable Render Pipeline, you do the following:

  1. Configure a CommandBuffer with a Clear command.
  2. Add the CommandBuffer to the queue of commands on the ScriptableRenderContext; to do this, call ScriptableRenderContext.ExecuteCommandBuffer.
  3. Instruct the graphics API to perform the queue of commands on the ScriptableRenderContext; to do this, call ScriptableRenderContext.Submit.

As with all Scriptable Render Pipeline operations, you use the RenderPipeline.Render method as the entry point for this code. This example code demonstrates how to do this:

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Instruct the graphics API to perform all scheduled commands
        context.Submit();
    }
}

Culling

Culling is the process of filtering out geometry that is not visible to a Camera.

To cull in the Scriptable Render Pipeline, you do the following:

  1. Populate a ScriptableCullingParameters struct with data about a Camera; to do this, call Camera.TryGetCullingParameters.
  2. Optional: Manually update the values of the ScriptableCullingParameters struct.
  3. Call ScriptableRenderContext.Cull, and store the results in a CullingResults struct.

This example code extends the example above, and demonstrates how to clear the render target and then perform a culling operation:

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Iterate over all Cameras
        foreach (Camera camera in cameras)
        {
            // Get the culling parameters from the current Camera
            camera.TryGetCullingParameters(out var cullingParameters);

            // Use the culling parameters to perform a cull operation, and store the results
            var cullingResults = context.Cull(ref cullingParameters);
        }

        // Instruct the graphics API to perform all scheduled commands
        context.Submit();
    }
}

Drawing

Drawing is the process of instructing the graphics API to draw a given set of geometry with given settings.

To draw in SRP, you do the following:

  1. Perform a culling operation, as described above, and store the results in a CullingResults struct.
  2. Create and configure FilteringSettings struct, which describes how to filter the culling results.
  3. Create and configure a DrawingSettings struct, which describes which geometry to draw and how to draw it.
  4. Optional: By default, Unity sets the render state based on the Shader object. If you want to override the render state for some or all of the geometry that you are about to draw, you can use a RenderStateBlock struct to do this.
  5. Call ScriptableRenderContext.DrawRenderers, and pass the structs that you created as parameters. Unity draws the filtered set of geometry, according to the settings.

This example code builds on the examples above, and demonstrates how to clear the render target, perform a culling operation, and draw the resulting geometry:

/* 
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // Create and schedule a command to clear the current render target
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // Iterate over all Cameras
        foreach (Camera camera in cameras)
        {
            // Get the culling parameters from the current Camera
            camera.TryGetCullingParameters(out var cullingParameters);

            // Use the culling parameters to perform a cull operation, and store the results
            var cullingResults = context.Cull(ref cullingParameters);

            // Update the value of built-in shader variables, based on the current Camera
            context.SetupCameraProperties(camera);

            // Tell Unity which geometry to draw, based on its LightMode Pass tag value
            ShaderTagId shaderTagId = new ShaderTagId("ExampleLightModeTag");

            // Tell Unity how to sort the geometry, based on the current Camera
            var sortingSettings = new SortingSettings(camera);

            // Create a DrawingSettings struct that describes which geometry to draw and how to draw it
            DrawingSettings drawingSettings = new DrawingSettings(shaderTagId, sortingSettings);

            // Tell Unity how to filter the culling results, to further specify which geometry to draw
            // Use FilteringSettings.defaultValue to specify no filtering
            FilteringSettings filteringSettings = FilteringSettings.defaultValue;
        
            // Schedule a command to draw the geometry, based on the settings you have defined
            context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);

            // Schedule a command to draw the Skybox if required
            if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
            {
                context.DrawSkybox(camera);
            }

            // Instruct the graphics API to perform all scheduled commands
            context.Submit();
        }
    }
}

///

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值