您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
789 行
35 KiB
789 行
35 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";
|
|
|
|
// Debugging
|
|
public enum MaterialDebugMode
|
|
{
|
|
None = 0,
|
|
|
|
Depth = 1,
|
|
TexCoord0 = 2,
|
|
VertexNormalWS = 3,
|
|
VertexTangentWS = 4,
|
|
VertexBitangentWS = 5,
|
|
|
|
BakeDiffuseLighting = 100,
|
|
EmissiveColor = 101,
|
|
EmissiveIntensity = 102,
|
|
Velocity = 103,
|
|
Distortion = 104,
|
|
DistortionBlur = 105,
|
|
|
|
BaseColor = 1001,
|
|
SpecularOcclusion = 1002,
|
|
NormalWS = 1003,
|
|
PerceptualSmoothness = 1004,
|
|
MaterialId = 1005,
|
|
AmbientOcclusion = 1006,
|
|
TangentWS = 1007,
|
|
Anisotropy = 1008,
|
|
Metalic = 1009,
|
|
Specular = 1010,
|
|
SubSurfaceRadius = 1011,
|
|
Thickness = 1012,
|
|
SubSurfaceProfile = 1013,
|
|
CoatNormalWS = 1014,
|
|
CoatPerceptualSmoothness = 1015,
|
|
SpecularColor = 1016,
|
|
}
|
|
|
|
public enum GBufferDebugMode
|
|
{
|
|
None = 0,
|
|
DiffuseColor = 1,
|
|
Normal = 2,
|
|
Depth = 3,
|
|
BakedDiffuse = 4,
|
|
SpecularColor = 5,
|
|
SpecularOcclustion = 6,
|
|
Smoothness = 7,
|
|
MaterialId = 8,
|
|
}
|
|
|
|
public class DebugParameters
|
|
{
|
|
// Material Debugging
|
|
public MaterialDebugMode materialDebugMode = MaterialDebugMode.None;
|
|
public GBufferDebugMode gBufferDebugMode = GBufferDebugMode.None;
|
|
|
|
// 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;
|
|
|
|
//[SerializeField]
|
|
//ShadowSettings m_ShadowSettings = ShadowSettings.Default;
|
|
//ShadowRenderPass m_ShadowPass;
|
|
|
|
Material m_DeferredMaterial;
|
|
Material m_FinalPassMaterial;
|
|
|
|
// Debug
|
|
Material m_GBufferDebugMaterial;
|
|
|
|
GBufferManager gbufferManager = new GBufferManager();
|
|
|
|
static private int s_CameraColorBuffer;
|
|
static private int s_CameraDepthBuffer;
|
|
|
|
static private ComputeBuffer s_punctualLightList;
|
|
|
|
void OnEnable()
|
|
{
|
|
Rebuild ();
|
|
}
|
|
|
|
void OnValidate()
|
|
{
|
|
Rebuild ();
|
|
}
|
|
|
|
void ClearComputeBuffers()
|
|
{
|
|
if (s_punctualLightList != null)
|
|
s_punctualLightList.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)));
|
|
|
|
m_DeferredMaterial = CreateEngineMaterial("Hidden/Unity/LightingDeferred");
|
|
m_FinalPassMaterial = CreateEngineMaterial("Hidden/Unity/FinalPass");
|
|
|
|
// Debug
|
|
m_GBufferDebugMaterial = CreateEngineMaterial("Hidden/Unity/GBufferDebug");
|
|
|
|
// m_ShadowPass = new ShadowRenderPass (m_ShadowSettings);
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
s_punctualLightList.Release();
|
|
|
|
if (m_DeferredMaterial) DestroyImmediate(m_DeferredMaterial);
|
|
if (m_FinalPassMaterial) DestroyImmediate(m_FinalPassMaterial);
|
|
}
|
|
|
|
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 RenderMaterialDebug(CullResults cull, Camera camera, RenderLoop renderLoop)
|
|
{
|
|
// setup GBuffer for rendering
|
|
var cmd = new CommandBuffer();
|
|
cmd.name = "Material Debug Pass";
|
|
cmd.GetTemporaryRT(s_CameraColorBuffer, camera.pixelWidth, camera.pixelHeight, 0, FilterMode.Point, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
|
|
cmd.GetTemporaryRT(s_CameraDepthBuffer, camera.pixelWidth, camera.pixelHeight, 24, FilterMode.Point, RenderTextureFormat.Depth);
|
|
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("_MaterialDebugMode", (int)debugParameters.materialDebugMode);
|
|
|
|
RenderOpaqueRenderList(cull, camera, renderLoop, "Debug");
|
|
RenderTransparentRenderList(cull, camera, renderLoop, "Debug");
|
|
|
|
cmd = new CommandBuffer();
|
|
cmd.name = "Blit Material Debug";
|
|
cmd.Blit(s_CameraColorBuffer, BuiltinRenderTextureType.CameraTarget);
|
|
renderLoop.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
|
|
void RenderGBufferDebug(Camera camera, RenderLoop renderLoop)
|
|
{
|
|
Matrix4x4 invViewProj = GetViewProjectionMatrix(camera).inverse;
|
|
m_GBufferDebugMaterial.SetMatrix("_InvViewProjMatrix", invViewProj);
|
|
|
|
Vector4 screenSize = ComputeScreenSize(camera);
|
|
m_GBufferDebugMaterial.SetVector("_ScreenSize", screenSize);
|
|
m_GBufferDebugMaterial.SetFloat("_DebugMode", (float)debugParameters.gBufferDebugMode);
|
|
|
|
// gbufferManager.BindBuffers(m_DeferredMaterial);
|
|
// TODO: Bind depth textures
|
|
var cmd = new CommandBuffer();
|
|
cmd.name = "GBuffer Debug Pass";
|
|
cmd.Blit(null, BuiltinRenderTextureType.CameraTarget, m_GBufferDebugMaterial, 0);
|
|
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);
|
|
|
|
// 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)
|
|
{
|
|
// setup GBuffer for rendering
|
|
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 UpdatePunctualLights(ActiveLight[] activeLights)
|
|
{
|
|
int punctualLightCount = 0;
|
|
List<PunctualLightData> lights = new List<PunctualLightData>();
|
|
|
|
for (int lightIndex = 0; lightIndex < Math.Min(activeLights.Length, MaxLights); lightIndex++)
|
|
{
|
|
ActiveLight light = activeLights[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("g_punctualLightList", s_punctualLightList);
|
|
Shader.SetGlobalInt("g_punctualLightCount", punctualLightCount);
|
|
}
|
|
|
|
void UpdateLightConstants(ActiveLight[] activeLights /*, ref ShadowOutput shadow */)
|
|
{
|
|
/*
|
|
int nNumLightsIncludingTooMany = 0;
|
|
|
|
int g_nNumLights = 0;
|
|
|
|
Vector4[] g_vLightColor = new Vector4[ MAX_LIGHTS ];
|
|
Vector4[] g_vLightPosition_flInvRadius = new Vector4[ MAX_LIGHTS ];
|
|
Vector4[] g_vLightDirection = new Vector4[ MAX_LIGHTS ];
|
|
Vector4[] g_vLightShadowIndex_vLightParams = new Vector4[ MAX_LIGHTS ];
|
|
Vector4[] g_vLightFalloffParams = new Vector4[ MAX_LIGHTS ];
|
|
Vector4[] g_vSpotLightInnersuterConeCosines = new Vector4[ MAX_LIGHTS ];
|
|
Matrix4x4[] g_matWorldToShadow = new Matrix4x4[ MAX_LIGHTS * MAX_SHADOWMAP_PER_LIGHTS ];
|
|
Vector4[] g_vDirShadowSplitSpheres = new Vector4[ MAX_DIRECTIONAL_SPLIT ];
|
|
|
|
for ( int nLight = 0; nLight < activeLights.Length; nLight++ )
|
|
{
|
|
|
|
nNumLightsIncludingTooMany++;
|
|
if ( nNumLightsIncludingTooMany > MAX_LIGHTS )
|
|
continue;
|
|
|
|
ActiveLight light = activeLights [nLight];
|
|
LightType lightType = light.lightType;
|
|
Vector3 position = light.light.transform.position;
|
|
Vector3 lightDir = light.light.transform.forward.normalized;
|
|
AdditionalLightData additionalLightData = light.light.GetComponent<AdditionalLightData> ();
|
|
|
|
// Setup shadow data arrays
|
|
bool hasShadows = shadow.GetShadowSliceCountLightIndex (nLight) != 0;
|
|
|
|
if ( lightType == LightType.Directional )
|
|
{
|
|
g_vLightColor[ g_nNumLights ] = light.finalColor;
|
|
g_vLightPosition_flInvRadius[ g_nNumLights ] = new Vector4(
|
|
position.x - ( lightDir.x * DIRECTIONAL_LIGHT_PULLBACK_DISTANCE ),
|
|
position.y - ( lightDir.y * DIRECTIONAL_LIGHT_PULLBACK_DISTANCE ),
|
|
position.z - ( lightDir.z * DIRECTIONAL_LIGHT_PULLBACK_DISTANCE ),
|
|
-1.0f );
|
|
g_vLightDirection[ g_nNumLights ] = new Vector4( lightDir.x, lightDir.y, lightDir.z );
|
|
g_vLightShadowIndex_vLightParams[ g_nNumLights ] = new Vector4( 0, 0, 1, 1 );
|
|
g_vLightFalloffParams[ g_nNumLights ] = new Vector4( 0.0f, 0.0f, float.MaxValue, (float)lightType );
|
|
g_vSpotLightInnerOuterConeCosines[ g_nNumLights ] = new Vector4( 0.0f, -1.0f, 1.0f );
|
|
|
|
if (hasShadows)
|
|
{
|
|
for (int s = 0; s < MAX_DIRECTIONAL_SPLIT; ++s)
|
|
{
|
|
g_vDirShadowSplitSpheres[s] = shadow.directionalShadowSplitSphereSqr[s];
|
|
}
|
|
}
|
|
}
|
|
else if ( lightType == LightType.Point )
|
|
{
|
|
g_vLightColor[ g_nNumLights ] = light.finalColor;
|
|
|
|
g_vLightPosition_flInvRadius[ g_nNumLights ] = new Vector4( position.x, position.y, position.z, 1.0f / light.range );
|
|
g_vLightDirection[ g_nNumLights ] = new Vector4( 0.0f, 0.0f, 0.0f );
|
|
g_vLightShadowIndex_vLightParams[ g_nNumLights ] = new Vector4( 0, 0, 1, 1 );
|
|
g_vLightFalloffParams[ g_nNumLights ] = new Vector4( 1.0f, 0.0f, light.range * light.range, (float)lightType );
|
|
g_vSpotLightInnerOuterConeCosines[ g_nNumLights ] = new Vector4( 0.0f, -1.0f, 1.0f );
|
|
}
|
|
else if ( lightType == LightType.Spot )
|
|
{
|
|
g_vLightColor[ g_nNumLights ] = light.finalColor;
|
|
g_vLightPosition_flInvRadius[ g_nNumLights ] = new Vector4( position.x, position.y, position.z, 1.0f / light.range );
|
|
g_vLightDirection[ g_nNumLights ] = new Vector4( lightDir.x, lightDir.y, lightDir.z );
|
|
g_vLightShadowIndex_vLightParams[ g_nNumLights ] = new Vector4( 0, 0, 1, 1 );
|
|
g_vLightFalloffParams[ g_nNumLights ] = new Vector4( 1.0f, 0.0f, light.range * light.range, (float)lightType );
|
|
|
|
float flInnerConePercent = AdditionalLightData.GetInnerSpotPercent01(additionalLightData);
|
|
float spotAngle = light.light.spotAngle;
|
|
float flPhiDot = Mathf.Clamp( Mathf.Cos( spotAngle * 0.5f * Mathf.Deg2Rad ), 0.0f, 1.0f ); // outer cone
|
|
float flThetaDot = Mathf.Clamp( Mathf.Cos( spotAngle * 0.5f * flInnerConePercent * Mathf.Deg2Rad ), 0.0f, 1.0f ); // inner cone
|
|
g_vSpotLightInnerOuterConeCosines[ g_nNumLights ] = new Vector4( flThetaDot, flPhiDot, 1.0f / Mathf.Max( 0.01f, flThetaDot - flPhiDot ) );
|
|
|
|
}
|
|
|
|
if ( hasShadows )
|
|
{
|
|
// Enable shadows
|
|
g_vLightShadowIndex_vLightParams[ g_nNumLights ].x = 1;
|
|
for(int s=0; s < shadow.GetShadowSliceCountLightIndex (nLight); ++s)
|
|
{
|
|
int shadowSliceIndex = shadow.GetShadowSliceIndex (nLight, s);
|
|
g_matWorldToShadow [g_nNumLights * MAX_SHADOWMAP_PER_LIGHTS + s] = shadow.shadowSlices[shadowSliceIndex].shadowTransform.transpose;
|
|
}
|
|
}
|
|
|
|
g_nNumLights++;
|
|
}
|
|
|
|
// Warn if too many lights found
|
|
if ( nNumLightsIncludingTooMany > MAX_LIGHTS )
|
|
{
|
|
if ( nNumLightsIncludingTooMany > m_nWarnedTooManyLights )
|
|
{
|
|
Debug.LogError( "ERROR! Found " + nNumLightsIncludingTooMany + " runtime lights! Valve renderer supports up to " + MAX_LIGHTS +
|
|
" active runtime lights at a time!\nDisabling " + ( nNumLightsIncludingTooMany - MAX_LIGHTS ) + " runtime light" +
|
|
( ( nNumLightsIncludingTooMany - MAX_LIGHTS ) > 1 ? "s" : "" ) + "!\n" );
|
|
}
|
|
m_nWarnedTooManyLights = nNumLightsIncludingTooMany;
|
|
}
|
|
else
|
|
{
|
|
if ( m_nWarnedTooManyLights > 0 )
|
|
{
|
|
m_nWarnedTooManyLights = 0;
|
|
Debug.Log( "SUCCESS! Found " + nNumLightsIncludingTooMany + " runtime lights which is within the supported number of lights, " + MAX_LIGHTS + ".\n\n" );
|
|
}
|
|
}
|
|
|
|
// Send constants to shaders
|
|
Shader.SetGlobalInt( "g_nNumLights", g_nNumLights );
|
|
|
|
// New method for Unity 5.4 to set arrays of constants
|
|
Shader.SetGlobalVectorArray( "g_vLightPosition_flInvRadius", g_vLightPosition_flInvRadius );
|
|
Shader.SetGlobalVectorArray( "g_vLightColor", g_vLightColor );
|
|
Shader.SetGlobalVectorArray( "g_vLightDirection", g_vLightDirection );
|
|
Shader.SetGlobalVectorArray( "g_vLightShadowIndex_vLightParams", g_vLightShadowIndex_vLightParams );
|
|
Shader.SetGlobalVectorArray( "g_vLightFalloffParams", g_vLightFalloffParams );
|
|
Shader.SetGlobalVectorArray( "g_vSpotLightInnerOuterConeCosines", g_vSpotLightInnerOuterConeCosines );
|
|
Shader.SetGlobalMatrixArray( "g_matWorldToShadow", g_matWorldToShadow );
|
|
Shader.SetGlobalVectorArray( "g_vDirShadowSplitSpheres", g_vDirShadowSplitSpheres );
|
|
|
|
// Time
|
|
#if ( UNITY_EDITOR )
|
|
{
|
|
Shader.SetGlobalFloat( "g_flTime", Time.realtimeSinceStartup );
|
|
//Debug.Log( "Time " + Time.realtimeSinceStartup );
|
|
}
|
|
#else
|
|
{
|
|
Shader.SetGlobalFloat( "g_flTime", Time.timeSinceLevelLoad );
|
|
//Debug.Log( "Time " + Time.timeSinceLevelLoad );
|
|
}
|
|
#endif
|
|
|
|
// PCF 3x3 Shadows
|
|
float flTexelEpsilonX = 1.0f / m_ShadowSettings.shadowAtlasWidth;
|
|
float flTexelEpsilonY = 1.0f / m_ShadowSettings.shadowAtlasHeight;
|
|
Vector4 g_vShadow3x3PCFTerms0 = new Vector4( 20.0f / 267.0f, 33.0f / 267.0f, 55.0f / 267.0f, 0.0f );
|
|
Vector4 g_vShadow3x3PCFTerms1 = new Vector4( flTexelEpsilonX, flTexelEpsilonY, -flTexelEpsilonX, -flTexelEpsilonY );
|
|
Vector4 g_vShadow3x3PCFTerms2 = new Vector4( flTexelEpsilonX, flTexelEpsilonY, 0.0f, 0.0f );
|
|
Vector4 g_vShadow3x3PCFTerms3 = new Vector4( -flTexelEpsilonX, -flTexelEpsilonY, 0.0f, 0.0f );
|
|
|
|
Shader.SetGlobalVector( "g_vShadow3x3PCFTerms0", g_vShadow3x3PCFTerms0 );
|
|
Shader.SetGlobalVector( "g_vShadow3x3PCFTerms1", g_vShadow3x3PCFTerms1 );
|
|
Shader.SetGlobalVector( "g_vShadow3x3PCFTerms2", g_vShadow3x3PCFTerms2 );
|
|
Shader.SetGlobalVector( "g_vShadow3x3PCFTerms3", g_vShadow3x3PCFTerms3 );
|
|
*/
|
|
}
|
|
|
|
/*
|
|
void RenderDeferredLighting(Camera camera, CullingInputs inputs, RenderLoop loop)
|
|
{
|
|
var props = new MaterialPropertyBlock();
|
|
|
|
var cmd = new CommandBuffer();
|
|
cmd.SetRenderTarget(new RenderTargetIdentifier(kGBufferEmission), new RenderTargetIdentifier(kGBufferZ));
|
|
foreach (var cl in inputs.culledLights)
|
|
{
|
|
bool renderAsQuad = (cl.flags & VisibleLightFlags.IntersectsNearPlane) != 0 || (cl.flags & VisibleLightFlags.IntersectsFarPlane) != 0 || (cl.lightType == LightType.Directional);
|
|
|
|
Vector3 lightPos = cl.localToWorld.GetColumn(3);
|
|
float range = cl.range;
|
|
cmd.DisableShaderKeyword("POINT");
|
|
cmd.DisableShaderKeyword("POINT_COOKIE");
|
|
cmd.DisableShaderKeyword("SPOT");
|
|
cmd.DisableShaderKeyword("DIRECTIONAL");
|
|
cmd.DisableShaderKeyword("DIRECTIONAL_COOKIE");
|
|
//cmd.EnableShaderKeyword ("UNITY_HDR_ON");
|
|
switch (cl.lightType)
|
|
{
|
|
case LightType.Point:
|
|
cmd.EnableShaderKeyword("POINT");
|
|
break;
|
|
case LightType.Spot:
|
|
cmd.EnableShaderKeyword("SPOT");
|
|
break;
|
|
case LightType.Directional:
|
|
cmd.EnableShaderKeyword("DIRECTIONAL");
|
|
break;
|
|
}
|
|
props.SetFloat("_LightAsQuad", renderAsQuad ? 1 : 0);
|
|
props.SetVector("_LightPos", new Vector4(lightPos.x, lightPos.y, lightPos.z, 1.0f / (range * range)));
|
|
props.SetVector("_LightColor", cl.finalColor);
|
|
Debug.Log("Light color : " + cl.finalColor.ToString());
|
|
props.SetMatrix("_WorldToLight", cl.worldToLocal);
|
|
|
|
///@TODO: cleanup, remove this from Internal-PrePassLighting shader
|
|
//DeferredPrivate::s_LightMaterial->SetTexture (ShaderLab::Property ("_LightTextureB0"), builtintex::GetAttenuationTexture ());
|
|
|
|
if (renderAsQuad)
|
|
{
|
|
cmd.DrawMesh(m_QuadMesh, Matrix4x4.identity, m_DeferredMaterial, 0, 0, props);
|
|
}
|
|
else
|
|
{
|
|
var matrix = Matrix4x4.TRS(lightPos, Quaternion.identity, new Vector3(range, range, range));
|
|
cmd.DrawMesh(m_PointLightMesh, matrix, m_DeferredMaterial, 0, 0, props);
|
|
}
|
|
}
|
|
loop.ExecuteCommandBuffer(cmd);
|
|
cmd.Dispose();
|
|
}
|
|
*/
|
|
|
|
public override void Render(Camera[] cameras, RenderLoop renderLoop)
|
|
{
|
|
// 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.culledLights /*, ref shadows */);
|
|
|
|
|
|
bool needDebugRendering = debugParameters.materialDebugMode != MaterialDebugMode.None || debugParameters.gBufferDebugMode != GBufferDebugMode.None;
|
|
|
|
if (!needDebugRendering)
|
|
{
|
|
UpdatePunctualLights(cullResults.culledLights);
|
|
|
|
InitAndClearBuffer(camera, renderLoop);
|
|
|
|
RenderGBuffer(cullResults, camera, renderLoop);
|
|
|
|
RenderDeferredLighting(camera, renderLoop);
|
|
|
|
RenderForward(cullResults, camera, renderLoop);
|
|
|
|
FinalPass(renderLoop);
|
|
}
|
|
else
|
|
{
|
|
if(debugParameters.materialDebugMode != MaterialDebugMode.None)
|
|
{
|
|
RenderMaterialDebug(cullResults, camera, renderLoop);
|
|
}
|
|
else if (debugParameters.gBufferDebugMode != GBufferDebugMode.None)
|
|
{
|
|
InitAndClearBuffer(camera, renderLoop);
|
|
RenderGBuffer(cullResults, camera, renderLoop);
|
|
RenderGBufferDebug(camera, 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
|
|
}
|
|
}
|