原文:https://zhuanlan.zhihu.com/p/36407658
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
}
}
}