zoukankan      html  css  js  c++  java
  • 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的学习。

  • 相关阅读:
    升级Xcode之后VVDocumenter-Xcode不能用的解决办法
    iOS国际化
    display:table 表格布局
    display: run-in
    连续字符换行 溢出点点点 多行省略
    Number 类型
    Boolean 相关
    Browsing contexts 浏览器上下文
    return flase 作用
    JS外链
  • 原文地址:https://www.cnblogs.com/shenyibo/p/12485235.html
Copyright © 2011-2022 走看看