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(); 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 lights = new List(); 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(); 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 (); // 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 } }