Unity渲染学习:简易SRP实现(可编程渲染管线)

Unity渲染学习:简易SRP实现

原文:https://zhuanlan.zhihu.com/p/36407658
Unity渲染学习:简易SRP实现(可编程渲染管线)_第1张图片
Unity渲染学习:简易SRP实现(可编程渲染管线)_第2张图片
Unity渲染学习:简易SRP实现(可编程渲染管线)_第3张图片
c#部分:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
#endif

namespace Kata03
{
    public class CustomRenderPipeline : RenderPipeline
    {
        CommandBuffer _cb;
        //保存平行光方向
        Vector3 _LightDir;
        //在管线销毁时调用
        public override void Dispose()
        {
            base.Dispose();
            if (_cb!=null)
            {
                _cb.Dispose();
                _cb = null;
            }
        }
        //在绘制管线时调用
        public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
        {
            base.Render(renderContext, cameras);
            if (_cb==null)
            {
                _cb = new CommandBuffer();
            }

            //准备好光源名称
            int _LightDir = Shader.PropertyToID("_LightDir");
            int _LightColor = Shader.PropertyToID("_LightColor");
            int _CameraPos = Shader.PropertyToID("_CameraPos");

            //对每个相机执行操作
            foreach (var camera in cameras)
            {
                //将上下文设置为当前相机上下文
                renderContext.SetupCameraProperties(camera);
                _cb.name = "Setup";
                _cb.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
                //设置渲染目标颜色为相机背景色
                _cb.ClearRenderTarget(true, true, camera.backgroundColor);
                //设置相机的着色器全局变量_CameraPos
                Vector4 CameraPosition = new Vector4(camera.transform.position.x, camera.transform.position.y, camera.transform.position.z, 1.0f);
                _cb.SetGlobalVector(_CameraPos,CameraPosition);
                renderContext.ExecuteCommandBuffer(_cb);
                _cb.Clear();

                //绘制skybox
                renderContext.DrawSkybox(camera);
                //执行裁剪
                CullResults culled = new CullResults();
                CullResults.Cull(camera, renderContext, out culled);

                //裁剪会给出三个参数:
                //可见的物体列表:visibleRenderers
                //可见的灯光:visibleLights
                //可见的反射探针(Cubemap):visibleReflectionProbes
                //所有东西都是未排序的

                //获取所有灯光
                List<VisibleLight> lights = culled.visibleLights;
                _cb.name = "RenderLights";
                foreach (var light in lights)
                {
                    //只处理平行光
                    if (light.lightType!=LightType.Directional)
                    {
                        continue;
                    }
                    //获取光源方向
                    Vector4 pos = light.localToWorld.GetColumn(2);
                    Vector4 LightDirection = new Vector4(-pos.x, -pos.y, -pos.z, 0);
                    //获取光源颜色
                    Color LightColor = light.finalColor;
                    //构建shader常量缓存
                    _cb.SetGlobalVector(_LightDir, LightDirection);
                    _cb.SetGlobalColor(_LightColor, LightColor);
                    renderContext.ExecuteCommandBuffer(_cb);
                    _cb.Clear();
                    FilterRenderersSettings rs = new FilterRenderersSettings(true);
                    //只渲染固体范围
                    rs.renderQueueRange = RenderQueueRange.opaque;
                    //包括所有层
                    rs.layerMask = ~0;
                    //使用Shader中指定光照模式为BaseLit的pass
                    DrawRendererSettings ds = new DrawRendererSettings(camera, new ShaderPassName("BaseLit"));
                    //绘制物体
                    renderContext.DrawRenderers(culled.visibleRenderers, ref ds, rs);
                    break;
                }
                //开始执行上下文
                renderContext.Submit();
            }
        }
    }

    //启用SRP
    public class CustomRenderPipelineAsset : RenderPipelineAsset
    {
#if UNITY_EDITOR
        //生成SRP文件
        [MenuItem("Assets/Create/Render Pipeline/Kata03/Pipeline Asset")]
        static void CreateKata03Pipeline()
        {
            ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<CreateKata03PipelineAsset>(), "Kata03 Pipeline.asset", null, null);
        }
        class CreateKata03PipelineAsset : EndNameEditAction
        {
            public override void Action(int instanceId, string pathName, string resourceFile)
            {
                var instance = CreateInstance<CustomRenderPipelineAsset>();
                AssetDatabase.CreateAsset(instance, pathName);
            }
        }
#endif
        protected override IRenderPipeline InternalCreatePipeline()
        {
            return new CustomRenderPipeline();
        }
    }
}

shader部分:

Shader "Custom/Kata03/BaseDirLit"
{
	Properties
	{
		_Color("Tint",Color) = (0.5,0.5,0.5,1.0)
		_DiffuseFactor("Diffuse Factor",Range(0,1)) = 1
		_SpecularFactor("Specular Factor", Range(0, 1)) = 1
		_SpecularPower("Specular Power", Range(1, 100)) = 100
	}

	SubShader
	{
		//根据FilterRenderersSettings.renderQueueRange选择
		Tags { "Queue" = "Geometry" }

		Pass
		{
			//根据DrawRendererSettings选择
			Tags{"LightMode" = "BaseLit"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			float4 _LightDir;
			float4 _LightColor;
			float4 _CameraPos;
			float4 _Color;
			float _DiffuseFactor;
			float _SpecularFactor;
			float _SpecularPower;


			struct a2v
			{
				float4 position : POSITION;
				float3 normal:NORMAL;
			};

			struct v2f
			{
				float4 position:SV_POSITION;
				float3 worldNormal:TEXCOORD1;
				float3 worldPos:TEXCOORD2;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (a2v v)
			{
				v2f o;
				o.position = UnityObjectToClipPos(v.position);
				o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.position).xyz;
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float4 diffuse = _DiffuseFactor * max(0.0,dot(_LightDir.xyz , normalize(i.worldNormal)))*_LightColor*_Color;
				float3 cameraDirection = normalize(_CameraPos.xyz - i.worldPos);
				float3 halfDir = normalize(_LightDir.xyz + cameraDirection);
				float4 specular = _SpecularFactor * pow(max(0.0, dot(normalize(i.worldNormal), halfDir)), _SpecularPower)*_LightColor;
				return diffuse + specular;
			}
			ENDCG
		}
	}
}

你可能感兴趣的:(Unity,Rendering)