您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

606 行
24 KiB

using UnityEngine;
using System.Collections;
using UnityEngine.Rendering;
using System.Collections.Generic;
using System;
using UnityEditor;
namespace UnityEngine.ScriptableRenderLoop
{
[ExecuteInEditMode]
// This HDRenderLoop assume linear lighting. Don't work with gamma.
public class HDRenderLoop : ScriptableRenderLoop
{
private static string m_HDRenderLoopPath = "Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.asset";
// Must be in sync with DebugViewMaterial.hlsl
public enum DebugViewVaryingMode
{
Depth = 1,
TexCoord0 = 2,
VertexNormalWS = 3,
VertexTangentWS = 4,
VertexBitangentWS = 5,
VertexColor = 6,
}
// Must be in sync with DebugViewMaterial.hlsl
public enum DebugViewGbufferMode
{
Depth = 7,
BakeDiffuseLighting = 8,
}
public class DebugParameters
{
// Material Debugging
public int debugViewMaterial = 0;
// Rendering debugging
public bool displayOpaqueObjects = true;
public bool displayTransparentObjects = true;
public bool enableTonemap = true;
public float exposure = 0;
}
private DebugParameters m_DebugParameters = new DebugParameters();
public DebugParameters debugParameters
{
get { return m_DebugParameters; }
}
#if UNITY_EDITOR
[MenuItem("Renderloop/CreateHDRenderLoop")]
static void CreateHDRenderLoop()
{
var instance = ScriptableObject.CreateInstance<HDRenderLoop>();
UnityEditor.AssetDatabase.CreateAsset(instance, m_HDRenderLoopPath);
}
#endif
public class GBufferManager
{
public const int MaxGbuffer = 8;
public void SetBufferDescription(int index, string stringID, RenderTextureFormat inFormat, RenderTextureReadWrite inSRGBWrite)
{
IDs[index] = Shader.PropertyToID(stringID);
RTIDs[index] = new RenderTargetIdentifier(IDs[index]);
formats[index] = inFormat;
sRGBWrites[index] = inSRGBWrite;
}
public void InitGBuffers(int width, int height, CommandBuffer cmd)
{
for (int index = 0; index < gbufferCount; index++)
{
/* RTs[index] = */ cmd.GetTemporaryRT(IDs[index], width, height, 0, FilterMode.Point, formats[index], sRGBWrites[index]);
}
}
public RenderTargetIdentifier[] GetGBuffers(CommandBuffer cmd)
{
var colorMRTs = new RenderTargetIdentifier[gbufferCount];
for (int index = 0; index < gbufferCount; index++)
{
colorMRTs[index] = RTIDs[index];
}
return colorMRTs;
}
/*
public void BindBuffers(Material mat)
{
for (int index = 0; index < gbufferCount; index++)
{
mat.SetTexture(IDs[index], RTs[index]);
}
}
*/
public int gbufferCount { get; set; }
int[] IDs = new int[MaxGbuffer];
RenderTargetIdentifier[] RTIDs = new RenderTargetIdentifier[MaxGbuffer];
RenderTextureFormat[] formats = new RenderTextureFormat[MaxGbuffer];
RenderTextureReadWrite[] sRGBWrites = new RenderTextureReadWrite[MaxGbuffer];
}
public const int MaxLights = 32;
public const int MaxProbes = 32;
//[SerializeField]
//ShadowSettings m_ShadowSettings = ShadowSettings.Default;
//ShadowRenderPass m_ShadowPass;
[SerializeField]
TextureSettings m_TextureSettings = TextureSettings.Default;
Material m_DeferredMaterial;
Material m_FinalPassMaterial;
// Debug
Material m_DebugViewMaterialGBuffer;
GBufferManager gbufferManager = new GBufferManager();
static private int s_CameraColorBuffer;
static private int s_CameraDepthBuffer;
static private ComputeBuffer s_punctualLightList;
static private ComputeBuffer s_envLightList;
private TextureCacheCubemap m_cubeReflTexArray;
void OnEnable()
{
Rebuild();
}
void OnValidate()
{
Rebuild();
}
void ClearComputeBuffers()
{
if (s_punctualLightList != null)
s_punctualLightList.Release();
if (s_envLightList != null)
s_envLightList.Release();
}
Material CreateEngineMaterial(string shaderPath)
{
Material mat = new Material(Shader.Find(shaderPath) as Shader);
mat.hideFlags = HideFlags.HideAndDontSave;
return mat;
}
public override void Rebuild()
{
ClearComputeBuffers();
// See Lit.hlsl for details
gbufferManager.gbufferCount = 4;
gbufferManager.SetBufferDescription(0, "_CameraGBufferTexture0", RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
gbufferManager.SetBufferDescription(1, "_CameraGBufferTexture1", RenderTextureFormat.ARGB2101010, RenderTextureReadWrite.Linear);
gbufferManager.SetBufferDescription(2, "_CameraGBufferTexture2", RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
gbufferManager.SetBufferDescription(3, "_CameraGBufferTexture3", RenderTextureFormat.RGB111110Float, RenderTextureReadWrite.Linear);
s_CameraColorBuffer = Shader.PropertyToID("_CameraColorTexture");
s_CameraDepthBuffer = Shader.PropertyToID("_CameraDepthTexture");
s_punctualLightList = new ComputeBuffer(MaxLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(PunctualLightData)));
s_envLightList = new ComputeBuffer(MaxLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(EnvLightData)));
m_DeferredMaterial = CreateEngineMaterial("Hidden/Unity/LightingDeferred");
m_FinalPassMaterial = CreateEngineMaterial("Hidden/Unity/FinalPass");
// Debug
m_DebugViewMaterialGBuffer = CreateEngineMaterial("Hidden/Unity/DebugViewMaterialGBuffer");
// m_ShadowPass = new ShadowRenderPass (m_ShadowSettings);
m_cubeReflTexArray = new TextureCacheCubemap();
m_cubeReflTexArray.AllocTextureArray(32, (int)m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
}
void OnDisable()
{
s_punctualLightList.Release();
s_envLightList.Release();
if (m_DeferredMaterial) DestroyImmediate(m_DeferredMaterial);
if (m_FinalPassMaterial) DestroyImmediate(m_FinalPassMaterial);
m_cubeReflTexArray.Release();
}
void InitAndClearBuffer(Camera camera, RenderLoop renderLoop)
{
// We clear only the depth buffer, no need to clear the various color buffer as we overwrite them.
// Clear depth/stencil and init buffers
{
var cmd = new CommandBuffer();
cmd.name = "InitGBuffers and clear Depth/Stencil";
// Init buffer
// With scriptable render loop we must allocate ourself depth and color buffer (We must be independent of backbuffer for now, hope to fix that later).
// Also we manage ourself the HDR format, here allocating fp16 directly.
// With scriptable render loop we can allocate temporary RT in a command buffer, they will not be release with ExecuteCommandBuffer
// These temporary surface are release automatically at the end of the scriptable renderloop if not release explicitly
int w = camera.pixelWidth;
int h = camera.pixelHeight;
cmd.GetTemporaryRT(s_CameraColorBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Default);
cmd.GetTemporaryRT(s_CameraDepthBuffer, w, h, 24, FilterMode.Point, RenderTextureFormat.Depth);
gbufferManager.InitGBuffers(w, h, cmd);
cmd.SetRenderTarget(new RenderTargetIdentifier(s_CameraColorBuffer), new RenderTargetIdentifier(s_CameraDepthBuffer));
cmd.ClearRenderTarget(true, false, new Color(0, 0, 0, 0));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
// TEMP: As we are in development and have not all the setup pass we still clear the color in emissive buffer and gbuffer, but this will be removed later.
// Clear HDR target
{
var cmd = new CommandBuffer();
cmd.name = "Clear HDR target";
cmd.SetRenderTarget(new RenderTargetIdentifier(s_CameraColorBuffer), new RenderTargetIdentifier(s_CameraDepthBuffer));
cmd.ClearRenderTarget(false, true, new Color(0, 0, 0, 0));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
// Clear GBuffers
{
var cmd = new CommandBuffer();
cmd.name = "Clear GBuffer";
// Write into the Camera Depth buffer
cmd.SetRenderTarget(gbufferManager.GetGBuffers(cmd), new RenderTargetIdentifier(s_CameraDepthBuffer));
// Clear everything
// TODO: Clear is not required for color as we rewrite everything, will save performance.
cmd.ClearRenderTarget(false, true, new Color(0, 0, 0, 0));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
// END TEMP
}
void RenderOpaqueRenderList(CullResults cull, Camera camera, RenderLoop renderLoop, string passName)
{
if (!debugParameters.displayOpaqueObjects)
return;
DrawRendererSettings settings = new DrawRendererSettings(cull, camera, new ShaderPassName(passName));
settings.sorting.sortOptions = SortOptions.SortByMaterialThenMesh;
settings.inputCullingOptions.SetQueuesOpaque();
renderLoop.DrawRenderers(ref settings);
}
void RenderTransparentRenderList(CullResults cull, Camera camera, RenderLoop renderLoop, string passName)
{
if (!debugParameters.displayTransparentObjects)
return;
DrawRendererSettings settings = new DrawRendererSettings(cull, camera, new ShaderPassName(passName));
settings.rendererConfiguration = RendererConfiguration.ConfigureOneLightProbePerRenderer | RendererConfiguration.ConfigureReflectionProbesProbePerRenderer;
settings.sorting.sortOptions = SortOptions.SortByMaterialThenMesh;
settings.inputCullingOptions.SetQueuesTransparent();
renderLoop.DrawRenderers(ref settings);
}
void RenderGBuffer(CullResults cull, Camera camera, RenderLoop renderLoop)
{
// setup GBuffer for rendering
var cmd = new CommandBuffer();
cmd.name = "GBuffer Pass";
cmd.SetRenderTarget(gbufferManager.GetGBuffers(cmd), new RenderTargetIdentifier(s_CameraDepthBuffer));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
// render opaque objects into GBuffer
RenderOpaqueRenderList(cull, camera, renderLoop, "GBuffer");
}
void RenderDebugViewMaterial(CullResults cull, Camera camera, RenderLoop renderLoop)
{
// Render Opaque forward
{
var cmd = new CommandBuffer();
cmd.name = "DebugView Material Mode Pass";
cmd.SetRenderTarget(new RenderTargetIdentifier(s_CameraColorBuffer), new RenderTargetIdentifier(s_CameraDepthBuffer));
cmd.ClearRenderTarget(true, true, new Color(0, 0, 0, 0));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
Shader.SetGlobalInt("_DebugViewMaterial", (int)debugParameters.debugViewMaterial);
RenderOpaqueRenderList(cull, camera, renderLoop, "DebugView");
}
// Render GBUffer opaque
{
Vector4 screenSize = ComputeScreenSize(camera);
m_DebugViewMaterialGBuffer.SetVector("_ScreenSize", screenSize);
m_DebugViewMaterialGBuffer.SetFloat("_DebugViewMaterial", (float)debugParameters.debugViewMaterial);
// gbufferManager.BindBuffers(m_DeferredMaterial);
// TODO: Bind depth textures
var cmd = new CommandBuffer();
cmd.name = "GBuffer Debug Pass";
cmd.Blit(null, new RenderTargetIdentifier(s_CameraColorBuffer), m_DebugViewMaterialGBuffer, 0);
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
// Render forward transparent
{
RenderTransparentRenderList(cull, camera, renderLoop, "DebugView");
}
// Last blit
{
var cmd = new CommandBuffer();
cmd.name = "Blit DebugView Material Debug";
cmd.Blit(s_CameraColorBuffer, BuiltinRenderTextureType.CameraTarget);
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
}
Matrix4x4 GetViewProjectionMatrix(Camera camera)
{
// The actual projection matrix used in shaders is actually massaged a bit to work across all platforms
// (different Z value ranges etc.)
Matrix4x4 gpuProj = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
Matrix4x4 gpuVP = gpuProj * camera.worldToCameraMatrix;
return gpuVP;
}
Vector4 ComputeScreenSize(Camera camera)
{
Vector4 screenSize = new Vector4();
screenSize.x = camera.pixelWidth;
screenSize.y = camera.pixelHeight;
screenSize.z = 1.0f / camera.pixelWidth;
screenSize.w = 1.0f / camera.pixelHeight;
return screenSize;
}
void RenderDeferredLighting(Camera camera, RenderLoop renderLoop)
{
Matrix4x4 invViewProj = GetViewProjectionMatrix(camera).inverse;
m_DeferredMaterial.SetMatrix("_InvViewProjMatrix", invViewProj);
Vector4 screenSize = ComputeScreenSize(camera);
m_DeferredMaterial.SetVector("_ScreenSize", screenSize);
m_DeferredMaterial.SetTexture("_reflCubeTextures", m_cubeReflTexArray.GetTexCache());
// gbufferManager.BindBuffers(m_DeferredMaterial);
// TODO: Bind depth textures
var cmd = new CommandBuffer();
cmd.name = "Deferred Ligthing Pass";
cmd.Blit(null, new RenderTargetIdentifier(s_CameraColorBuffer), m_DeferredMaterial, 0);
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
void RenderForward(CullResults cullResults, Camera camera, RenderLoop renderLoop)
{
var cmd = new CommandBuffer();
cmd.name = "Forward Pass";
cmd.SetRenderTarget(new RenderTargetIdentifier(s_CameraColorBuffer), new RenderTargetIdentifier(s_CameraDepthBuffer));
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
RenderTransparentRenderList(cullResults, camera, renderLoop, "Forward");
}
void FinalPass(RenderLoop renderLoop)
{
// Those could be tweakable for the neutral tonemapper, but in the case of the LookDev we don't need that
const float BlackIn = 0.02f;
const float WhiteIn = 10.0f;
const float BlackOut = 0.0f;
const float WhiteOut = 10.0f;
const float WhiteLevel = 5.3f;
const float WhiteClip = 10.0f;
const float DialUnits = 20.0f;
const float HalfDialUnits = DialUnits * 0.5f;
// converting from artist dial units to easy shader-lerps (0-1)
Vector4 tonemapCoeff1 = new Vector4((BlackIn * DialUnits) + 1.0f, (BlackOut * HalfDialUnits) + 1.0f, (WhiteIn / DialUnits), (1.0f - (WhiteOut / DialUnits)));
Vector4 tonemapCoeff2 = new Vector4(0.0f, 0.0f, WhiteLevel, WhiteClip / HalfDialUnits);
m_FinalPassMaterial.SetVector("_ToneMapCoeffs1", tonemapCoeff1);
m_FinalPassMaterial.SetVector("_ToneMapCoeffs2", tonemapCoeff2);
m_FinalPassMaterial.SetFloat("_EnableToneMap", debugParameters.enableTonemap ? 1.0f : 0.0f);
m_FinalPassMaterial.SetFloat("_Exposure", debugParameters.exposure);
CommandBuffer cmd = new CommandBuffer();
cmd.name = "FinalPass";
// Resolve our HDR texture to CameraTarget.
cmd.Blit(s_CameraColorBuffer, BuiltinRenderTextureType.CameraTarget, m_FinalPassMaterial, 0);
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
void NewFrame()
{
// update texture caches
m_cubeReflTexArray.NewFrame();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------
void UpdatePunctualLights(VisibleLight[] visibleLights)
{
int punctualLightCount = 0;
List<PunctualLightData> lights = new List<PunctualLightData>();
for (int lightIndex = 0; lightIndex < Math.Min(visibleLights.Length, MaxLights); lightIndex++)
{
VisibleLight light = visibleLights[lightIndex];
if (light.lightType == LightType.Spot || light.lightType == LightType.Point || light.lightType == LightType.Directional)
{
PunctualLightData l = new PunctualLightData();
if (light.lightType == LightType.Directional)
{
l.useDistanceAttenuation = 0.0f;
// positionWS store Light direction for directional and is opposite to the forward direction
l.positionWS = -light.light.transform.forward;
l.invSqrAttenuationRadius = 0.0f;
}
else
{
l.useDistanceAttenuation = 1.0f;
l.positionWS = light.light.transform.position;
l.invSqrAttenuationRadius = 1.0f / (light.range * light.range);
}
// Correct intensity calculation (Different from Unity)
float lightColorR = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.r);
float lightColorG = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.g);
float lightColorB = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.b);
l.color.Set(lightColorR, lightColorG, lightColorB);
// Light direction is opposite to the forward direction
l.forward = -light.light.transform.forward;
// CAUTION: For IES as we inverse forward maybe this will need rotation.
l.up = light.light.transform.up;
l.right = light.light.transform.right;
l.diffuseScale = 1.0f;
l.specularScale = 1.0f;
l.shadowDimmer = 1.0f;
if (light.lightType == LightType.Spot)
{
float spotAngle = light.light.spotAngle;
AdditionalLightData additionalLightData = light.light.GetComponent<AdditionalLightData>();
float innerConePercent = AdditionalLightData.GetInnerSpotPercent01(additionalLightData);
float cosSpotOuterHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * Mathf.Deg2Rad), 0.0f, 1.0f);
float cosSpotInnerHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * innerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone
float val = Mathf.Max(0.001f, (cosSpotInnerHalfAngle - cosSpotOuterHalfAngle));
l.angleScale = 1.0f / val;
l.angleOffset = -cosSpotOuterHalfAngle * l.angleScale;
}
else
{
// 1.0f, 2.0f are neutral value allowing GetAngleAnttenuation in shader code to return 1.0
l.angleScale = 1.0f;
l.angleOffset = 2.0f;
}
lights.Add(l);
punctualLightCount++;
}
}
s_punctualLightList.SetData(lights.ToArray());
Shader.SetGlobalBuffer("_PunctualLightList", s_punctualLightList);
Shader.SetGlobalInt("_PunctualLightCount", punctualLightCount);
}
void UpdateReflectionProbes(VisibleReflectionProbe[] activeReflectionProbes)
{
int envLightCount = 0;
List<EnvLightData> lights = new List<EnvLightData>();
for (int lightIndex = 0; lightIndex < Math.Min(activeReflectionProbes.Length, MaxProbes); lightIndex++)
{
VisibleReflectionProbe probe = activeReflectionProbes[lightIndex];
EnvLightData l = new EnvLightData();
/*
Vector3 boxOffset = rl.center; // reflection volume offset relative to cube map capture point
float blendDistance = rl.blendDistance;
Matrix4x4 mat = rl.localToWorld;
//Matrix4x4 mat = rl.transform.localToWorldMatrix;
Vector3 cubeCapturePos = mat.GetColumn(3); // cube map capture position in world space
Vector3 combinedExtent = e + new Vector3(blendDistance, blendDistance, blendDistance);
lightData[i].uLightType = (uint)LightDefinitions.BOX_LIGHT;
m_cubeReflTexArray.FetchSlice(cubemap);
if (boxProj) lightData[i].flags |= LightDefinitions.IS_BOX_PROJECTED;
*/
lights.Add(l);
envLightCount++;
}
s_envLightList.SetData(lights.ToArray());
Shader.SetGlobalBuffer("_EnvLightList", s_envLightList);
Shader.SetGlobalInt("_EnvLightCount", envLightCount);
}
public override void Render(Camera[] cameras, RenderLoop renderLoop)
{
// Do anything we need to do upon a new frame.
NewFrame();
// Set Frame constant buffer
// TODO...
foreach (var camera in cameras)
{
// Set camera constant buffer
// TODO...
CullResults cullResults;
CullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
//m_ShadowPass.UpdateCullingParameters (ref cullingParams);
cullResults = CullResults.Cull(ref cullingParams, renderLoop);
//ShadowOutput shadows;
//m_ShadowPass.Render (renderLoop, cullResults, out shadows);
renderLoop.SetupCameraProperties(camera);
//UpdateLightConstants(cullResults.visibleLights /*, ref shadows */);
UpdatePunctualLights(cullResults.visibleLights);
UpdateReflectionProbes(cullResults.visibleReflectionProbes);
InitAndClearBuffer(camera, renderLoop);
RenderGBuffer(cullResults, camera, renderLoop);
if (debugParameters.debugViewMaterial != 0)
{
RenderDebugViewMaterial(cullResults, camera, renderLoop);
}
else
{
RenderDeferredLighting(camera, renderLoop);
RenderForward(cullResults, camera, renderLoop);
FinalPass(renderLoop);
}
renderLoop.Submit();
}
// Post effects
}
#if UNITY_EDITOR
public override UnityEditor.SupportedRenderingFeatures GetSupportedRenderingFeatures()
{
var features = new UnityEditor.SupportedRenderingFeatures();
features.reflectionProbe = UnityEditor.SupportedRenderingFeatures.ReflectionProbe.Rotation;
return features;
}
#endif
}
}