URP學習之一--SRP


學習URP之前首先要知道SRP是什么。

SRP(Scriptable Render Pipeline)Unity向開發者提供的用來組織渲染數據和自定義提交渲染方案的接口,用戶可以靈活的根據需求選擇自己的渲染信息組織和提交方案。

URP就是Unity官方在SRP的基礎上實現好的一套方案。

我們先來創建一個屬於自己的渲染管線看看SRP究竟在起的什么作用:

創建兩個腳本:

腳本1

 

 1 using UnityEngine;
 2 
 3 using UnityEngine.Rendering;
 4 
 5  
 6 
 7 [CreateAssetMenu]
 8 
 9 public class SRenderPipelineAsset : RenderPipelineAsset
10 
11 {
12 
13     protected override RenderPipeline CreatePipeline()
14 
15     {
16 
17         return new SRenderPipeline();
18 
19     }
20 
21 }

 

 

腳本2

 

using UnityEngine;

using UnityEngine.Rendering;

 

public class SRenderPipeline : RenderPipeline

{

    protected override void Render(ScriptableRenderContext context, Camera[] cameras)

    {

        

    }

}

 

Asset Menu中創建自己的PipelineAsset文件:

 

然后將創建出來的Asset放入Graphics Setting

 

接下來你會看到無論是場景視圖還是Game視圖都是一片白色,此時就需要我們為渲染管線填充內容,我們主要在RenderPipelineRender函數提交渲染,Render函數的第一個參數context可以看作是做渲染提交的上下文,里面包含了很多接口;第二個參數是cameras,把所有的相機(包括場景相機和preview相機)都作為參數傳入進來。所以先試一下最簡單的:

 

protected override void Render(ScriptableRenderContext context, Camera[] cameras)
{
        for (int i = 0; i < cameras.Length; i++)
        {
            context.DrawSkybox(cameras[i]);
        }
        context.Submit();
}

 

Context中有很多draw方法,我們要確定在哪個相機上draw,所以需要逐相機調用,將相機傳入方法;context最后必須調用submit方法提交渲染,因為上面調用draw並不是真正提交到GPU了,而是填充了context的內容,只有將context提交上去才會將渲染數據送往GPU。

細心的小伙伴會發現雖然天空盒畫出來了,但是轉動相機為什么沒有任何反映呢?

原來粗心的我在畫天空盒之前少了一句這樣的代碼:

context.SetupCameraProperties(camera);

 

從代碼我們可以看出渲染一切物體之前首先必須設置相機數據到context,否則context無法根據相機矩陣信息算出應該看到的區域。

那么天空盒畫完了,該畫場景物體了,代碼如下:

protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        for (int i = 0; i < cameras.Length; i++)
        {
            Camera camera = cameras[i];
            context.SetupCameraProperties(camera);
            context.DrawSkybox(camera);
            
            //相機裁剪
            camera.TryGetCullingParameters(out var parameters);
            CullingResults results = context.Cull(ref parameters);

            DrawingSettings ds = new DrawingSettings();
            FilteringSettings fs = new FilteringSettings();
            
            context.DrawRenderers(results, ref ds, ref fs);
        }

        context.Submit();
    }

 

首先相機要進行視錐裁剪,決定哪些物體需要被渲染,裁剪參數從相機中獲取,裁剪結果存放在Cull方法的返回值中,然而並不能拿到里面每一個物體的數據,最后調用方法DrawRenderers。然而筆者我總感覺少了什么,回到Unity發現果然不對。如下圖:

 

這個cube一下子讓我想到了問題所在:材質!

於是經過不知多長時間的鼓搗,加上查百度(重點),才寫出以下代碼:

 

protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        for (int i = 0; i < cameras.Length; i++)
        {
            Camera camera = cameras[i];
            context.SetupCameraProperties(camera);
            context.DrawSkybox(camera);
            
            //相機裁剪
            camera.TryGetCullingParameters(out var parameters);
            CullingResults results = context.Cull(ref parameters);

            DrawingSettings ds = new DrawingSettings();
            //指定使用設定的LightMode的Pass
            ds.SetShaderPassName(0, new ShaderTagId("SForward"));
            //排序設置
            ds.sortingSettings = new SortingSettings(camera){criteria = SortingCriteria.CommonOpaque};
            //過濾設置
            FilteringSettings fs = new FilteringSettings(RenderQueueRange.opaque,-1);

            context.DrawRenderers(results, ref ds, ref fs);
        }

        context.Submit();
    }

這里需要注意的是DrawSettings里面的SetShaderPassName查找的不不不(重要的事情說三遍)是Shader的Pass中那個Name “xxx” 不是那個!!!找的是Tags中的LightMode!雖然不知道為什么,但是記住就對了。

還有就是DrawSettings中的sortingSettings,沒錯,就是這個排序規則,必須設置criteria字段,筆者我一直以為其他地方出問題了,結果查了半天就是因為這個,就是它,大家記住這個可惡的字段!

Shader代碼如下:

Shader "Custom/test"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque"}
        LOD 100

        Pass
        {
            Tags{ "LightMode" = "SForward"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

非常常規而又簡單的Unlit。

給個貼圖效果如下:

那如果我想要一個光照該怎么辦呢?

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Custom/diffuse"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque"}
        LOD 100

        Pass
        {
            Tags{ "LightMode" = "SForward"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal :NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldNormal:TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                float3 worldNormal = normalize(i.worldNormal);
                float3 lightDir = _WorldSpaceLightPos0.xyz;
                col = col * saturate(dot(worldNormal, lightDir));
                // apply fog
                return col;
            }
            ENDCG
        }
    }
}

按照正常的diffuse寫完全沒有任何問題,Specular也是一樣。

diffuse效果如下:

現在,我們基本上可以通過SRP正常的顯示一些簡單的效果,通過這個簡單的例子來引出我們對URP的學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM