123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.Mathematics;
- using Unity.Collections.LowLevel.Unsafe;
-
- using UnityEngine.Experimental.Rendering;
- using UnityEngine.Rendering.RenderGraphModule;
-
- namespace UnityEngine.Rendering.Universal.Internal
- {
- /// <summary>
- /// Computes and submits lighting data to the GPU.
- /// </summary>
- public class ForwardLights
- {
- static class LightConstantBuffer
- {
- public static int _MainLightPosition; // DeferredLights.LightConstantBuffer also refers to the same ShaderPropertyID - TODO: move this definition to a common location shared by other UniversalRP classes
- public static int _MainLightColor; // DeferredLights.LightConstantBuffer also refers to the same ShaderPropertyID - TODO: move this definition to a common location shared by other UniversalRP classes
- public static int _MainLightOcclusionProbesChannel; // Deferred?
- public static int _MainLightLayerMask;
-
- public static int _AdditionalLightsCount;
- public static int _AdditionalLightsPosition;
- public static int _AdditionalLightsColor;
- public static int _AdditionalLightsAttenuation;
- public static int _AdditionalLightsSpotDir;
- public static int _AdditionalLightOcclusionProbeChannel;
- public static int _AdditionalLightsLayerMasks;
- }
-
- int m_AdditionalLightsBufferId;
- int m_AdditionalLightsIndicesId;
-
- const string k_SetupLightConstants = "Setup Light Constants";
- private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler(k_SetupLightConstants);
- private static readonly ProfilingSampler m_ProfilingSamplerFPSetup = new ProfilingSampler("Forward+ Setup");
- private static readonly ProfilingSampler m_ProfilingSamplerFPComplete = new ProfilingSampler("Forward+ Complete");
- private static readonly ProfilingSampler m_ProfilingSamplerFPUpload = new ProfilingSampler("Forward+ Upload");
- MixedLightingSetup m_MixedLightingSetup;
-
- Vector4[] m_AdditionalLightPositions;
- Vector4[] m_AdditionalLightColors;
- Vector4[] m_AdditionalLightAttenuations;
- Vector4[] m_AdditionalLightSpotDirections;
- Vector4[] m_AdditionalLightOcclusionProbeChannels;
- float[] m_AdditionalLightsLayerMasks; // Unity has no support for binding uint arrays. We will use asuint() in the shader instead.
-
- bool m_UseStructuredBuffer;
-
- bool m_UseForwardPlus;
- int m_DirectionalLightCount;
- int m_ActualTileWidth;
- int2 m_TileResolution;
-
- JobHandle m_CullingHandle;
- NativeArray<uint> m_ZBins;
- GraphicsBuffer m_ZBinsBuffer;
- NativeArray<uint> m_TileMasks;
- GraphicsBuffer m_TileMasksBuffer;
-
- LightCookieManager m_LightCookieManager;
- ReflectionProbeManager m_ReflectionProbeManager;
- int m_WordsPerTile;
- float m_ZBinScale;
- float m_ZBinOffset;
- int m_LightCount;
- int m_BinCount;
-
- internal struct InitParams
- {
- public LightCookieManager lightCookieManager;
- public bool forwardPlus;
-
- static internal InitParams Create()
- {
- InitParams p;
- {
- var settings = LightCookieManager.Settings.Create();
- var asset = UniversalRenderPipeline.asset;
- if (asset)
- {
- settings.atlas.format = asset.additionalLightsCookieFormat;
- settings.atlas.resolution = asset.additionalLightsCookieResolution;
- }
-
- p.lightCookieManager = new LightCookieManager(ref settings);
- p.forwardPlus = false;
- }
- return p;
- }
- }
-
- /// <summary>
- /// Creates a new <c>ForwardLights</c> instance.
- /// </summary>
- public ForwardLights() : this(InitParams.Create()) { }
-
- internal ForwardLights(InitParams initParams)
- {
- m_UseStructuredBuffer = RenderingUtils.useStructuredBuffer;
- m_UseForwardPlus = initParams.forwardPlus;
-
- LightConstantBuffer._MainLightPosition = Shader.PropertyToID("_MainLightPosition");
- LightConstantBuffer._MainLightColor = Shader.PropertyToID("_MainLightColor");
- LightConstantBuffer._MainLightOcclusionProbesChannel = Shader.PropertyToID("_MainLightOcclusionProbes");
- LightConstantBuffer._MainLightLayerMask = Shader.PropertyToID("_MainLightLayerMask");
- LightConstantBuffer._AdditionalLightsCount = Shader.PropertyToID("_AdditionalLightsCount");
-
- if (m_UseStructuredBuffer)
- {
- m_AdditionalLightsBufferId = Shader.PropertyToID("_AdditionalLightsBuffer");
- m_AdditionalLightsIndicesId = Shader.PropertyToID("_AdditionalLightsIndices");
- }
- else
- {
- LightConstantBuffer._AdditionalLightsPosition = Shader.PropertyToID("_AdditionalLightsPosition");
- LightConstantBuffer._AdditionalLightsColor = Shader.PropertyToID("_AdditionalLightsColor");
- LightConstantBuffer._AdditionalLightsAttenuation = Shader.PropertyToID("_AdditionalLightsAttenuation");
- LightConstantBuffer._AdditionalLightsSpotDir = Shader.PropertyToID("_AdditionalLightsSpotDir");
- LightConstantBuffer._AdditionalLightOcclusionProbeChannel = Shader.PropertyToID("_AdditionalLightsOcclusionProbes");
- LightConstantBuffer._AdditionalLightsLayerMasks = Shader.PropertyToID("_AdditionalLightsLayerMasks");
-
- int maxLights = UniversalRenderPipeline.maxVisibleAdditionalLights;
- m_AdditionalLightPositions = new Vector4[maxLights];
- m_AdditionalLightColors = new Vector4[maxLights];
- m_AdditionalLightAttenuations = new Vector4[maxLights];
- m_AdditionalLightSpotDirections = new Vector4[maxLights];
- m_AdditionalLightOcclusionProbeChannels = new Vector4[maxLights];
- m_AdditionalLightsLayerMasks = new float[maxLights];
- }
-
- if (m_UseForwardPlus)
- {
- CreateForwardPlusBuffers();
- m_ReflectionProbeManager = ReflectionProbeManager.Create();
- }
-
- m_LightCookieManager = initParams.lightCookieManager;
- }
-
- void CreateForwardPlusBuffers()
- {
- m_ZBins = new NativeArray<uint>(UniversalRenderPipeline.maxZBinWords, Allocator.Persistent);
- m_ZBinsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Constant, UniversalRenderPipeline.maxZBinWords / 4, UnsafeUtility.SizeOf<float4>());
- m_ZBinsBuffer.name = "URP Z-Bin Buffer";
- m_TileMasks = new NativeArray<uint>(UniversalRenderPipeline.maxTileWords, Allocator.Persistent);
- m_TileMasksBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Constant, UniversalRenderPipeline.maxTileWords / 4, UnsafeUtility.SizeOf<float4>());
- m_TileMasksBuffer.name = "URP Tile Buffer";
- }
-
- internal ReflectionProbeManager reflectionProbeManager => m_ReflectionProbeManager;
-
- static int AlignByteCount(int count, int align) => align * ((count + align - 1) / align);
-
- // Calculate view planes and viewToViewportScaleBias. This handles projection center in case the projection is off-centered
- void GetViewParams(Camera camera, float4x4 viewToClip, out float viewPlaneBot, out float viewPlaneTop, out float4 viewToViewportScaleBias)
- {
- // We want to calculate `fovHalfHeight = tan(fov / 2)`
- // `projection[1][1]` contains `1 / tan(fov / 2)`
- var viewPlaneHalfSizeInv = math.float2(viewToClip[0][0], viewToClip[1][1]);
- var viewPlaneHalfSize = math.rcp(viewPlaneHalfSizeInv);
- var centerClipSpace = camera.orthographic ? -math.float2(viewToClip[3][0], viewToClip[3][1]): math.float2(viewToClip[2][0], viewToClip[2][1]);
-
- viewPlaneBot = centerClipSpace.y * viewPlaneHalfSize.y - viewPlaneHalfSize.y;
- viewPlaneTop = centerClipSpace.y * viewPlaneHalfSize.y + viewPlaneHalfSize.y;
- viewToViewportScaleBias = math.float4(
- viewPlaneHalfSizeInv * 0.5f,
- -centerClipSpace * 0.5f + 0.5f
- );
- }
-
- internal void PreSetup(UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData)
- {
- if (m_UseForwardPlus)
- {
- using var _ = new ProfilingScope(m_ProfilingSamplerFPSetup);
-
- if (!m_CullingHandle.IsCompleted)
- {
- throw new InvalidOperationException("Forward+ jobs have not completed yet.");
- }
-
- if (m_TileMasks.Length != UniversalRenderPipeline.maxTileWords)
- {
- m_ZBins.Dispose();
- m_ZBinsBuffer.Dispose();
- m_TileMasks.Dispose();
- m_TileMasksBuffer.Dispose();
- CreateForwardPlusBuffers();
- }
- else
- {
- unsafe
- {
- UnsafeUtility.MemClear(m_ZBins.GetUnsafePtr(), m_ZBins.Length * sizeof(uint));
- UnsafeUtility.MemClear(m_TileMasks.GetUnsafePtr(), m_TileMasks.Length * sizeof(uint));
- }
- }
-
- var camera = cameraData.camera;
-
- var screenResolution = math.int2(cameraData.pixelWidth, cameraData.pixelHeight);
- #if ENABLE_VR && ENABLE_XR_MODULE
- var viewCount = cameraData.xr.enabled && cameraData.xr.singlePassEnabled ? 2 : 1;
- #else
- var viewCount = 1;
- #endif
-
- m_LightCount = lightData.visibleLights.Length;
- var lightOffset = 0;
- while (lightOffset < m_LightCount && lightData.visibleLights[lightOffset].lightType == LightType.Directional)
- {
- lightOffset++;
- }
- m_LightCount -= lightOffset;
-
- m_DirectionalLightCount = lightOffset;
- if (lightData.mainLightIndex != -1 && m_DirectionalLightCount != 0) m_DirectionalLightCount -= 1;
-
- var visibleLights = lightData.visibleLights.GetSubArray(lightOffset, m_LightCount);
- var reflectionProbes = renderingData.cullResults.visibleReflectionProbes;
- var reflectionProbeCount = math.min(reflectionProbes.Length, UniversalRenderPipeline.maxVisibleReflectionProbes);
- var itemsPerTile = visibleLights.Length + reflectionProbeCount;
- m_WordsPerTile = (itemsPerTile + 31) / 32;
-
- m_ActualTileWidth = 8 >> 1;
- do
- {
- m_ActualTileWidth <<= 1;
- m_TileResolution = (screenResolution + m_ActualTileWidth - 1) / m_ActualTileWidth;
- }
- while ((m_TileResolution.x * m_TileResolution.y * m_WordsPerTile * viewCount) > UniversalRenderPipeline.maxTileWords);
-
- if (!camera.orthographic)
- {
- // Use to calculate binIndex = log2(z) * zBinScale + zBinOffset
- m_ZBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((math.log2(camera.farClipPlane) - math.log2(camera.nearClipPlane)) * (2 + m_WordsPerTile));
- m_ZBinOffset = -math.log2(camera.nearClipPlane) * m_ZBinScale;
- m_BinCount = (int)(math.log2(camera.farClipPlane) * m_ZBinScale + m_ZBinOffset);
- }
- else
- {
- // Use to calculate binIndex = z * zBinScale + zBinOffset
- m_ZBinScale = (UniversalRenderPipeline.maxZBinWords / viewCount) / ((camera.farClipPlane - camera.nearClipPlane) * (2 + m_WordsPerTile));
- m_ZBinOffset = -camera.nearClipPlane * m_ZBinScale;
- m_BinCount = (int)(camera.farClipPlane * m_ZBinScale + m_ZBinOffset);
- }
-
- var worldToViews = new Fixed2<float4x4>(cameraData.GetViewMatrix(0), cameraData.GetViewMatrix(math.min(1, viewCount - 1)));
- var viewToClips = new Fixed2<float4x4>(cameraData.GetProjectionMatrix(0), cameraData.GetProjectionMatrix(math.min(1, viewCount - 1)));
-
- // Should probe come after otherProbe?
- static bool IsProbeGreater(VisibleReflectionProbe probe, VisibleReflectionProbe otherProbe)
- {
- return probe.importance < otherProbe.importance ||
- (probe.importance == otherProbe.importance && probe.bounds.extents.sqrMagnitude > otherProbe.bounds.extents.sqrMagnitude);
- }
-
- for (var i = 1; i < reflectionProbeCount; i++)
- {
- var probe = reflectionProbes[i];
- var j = i - 1;
- while (j >= 0 && IsProbeGreater(reflectionProbes[j], probe))
- {
- reflectionProbes[j + 1] = reflectionProbes[j];
- j--;
- }
-
- reflectionProbes[j + 1] = probe;
- }
-
- var minMaxZs = new NativeArray<float2>(itemsPerTile * viewCount, Allocator.TempJob);
-
- var lightMinMaxZJob = new LightMinMaxZJob
- {
- worldToViews = worldToViews,
- lights = visibleLights,
- minMaxZs = minMaxZs.GetSubArray(0, m_LightCount * viewCount)
- };
- // Innerloop batch count of 32 is not special, just a handwavy amount to not have too much scheduling overhead nor too little parallelism.
- var lightMinMaxZHandle = lightMinMaxZJob.ScheduleParallel(m_LightCount * viewCount, 32, new JobHandle());
-
- var reflectionProbeMinMaxZJob = new ReflectionProbeMinMaxZJob
- {
- worldToViews = worldToViews,
- reflectionProbes = reflectionProbes,
- minMaxZs = minMaxZs.GetSubArray(m_LightCount * viewCount, reflectionProbeCount * viewCount)
- };
- var reflectionProbeMinMaxZHandle = reflectionProbeMinMaxZJob.ScheduleParallel(reflectionProbeCount * viewCount, 32, lightMinMaxZHandle);
-
- var zBinningBatchCount = (m_BinCount + ZBinningJob.batchSize - 1) / ZBinningJob.batchSize;
- var zBinningJob = new ZBinningJob
- {
- bins = m_ZBins,
- minMaxZs = minMaxZs,
- zBinScale = m_ZBinScale,
- zBinOffset = m_ZBinOffset,
- binCount = m_BinCount,
- wordsPerTile = m_WordsPerTile,
- lightCount = m_LightCount,
- reflectionProbeCount = reflectionProbeCount,
- batchCount = zBinningBatchCount,
- viewCount = viewCount,
- isOrthographic = camera.orthographic
- };
- var zBinningHandle = zBinningJob.ScheduleParallel(zBinningBatchCount * viewCount, 1, reflectionProbeMinMaxZHandle);
-
- reflectionProbeMinMaxZHandle.Complete();
-
- GetViewParams(camera, viewToClips[0], out float viewPlaneBottom0, out float viewPlaneTop0, out float4 viewToViewportScaleBias0);
- GetViewParams(camera, viewToClips[1], out float viewPlaneBottom1, out float viewPlaneTop1, out float4 viewToViewportScaleBias1);
-
- // Each light needs 1 range for Y, and a range per row. Align to 128-bytes to avoid false sharing.
- var rangesPerItem = AlignByteCount((1 + m_TileResolution.y) * UnsafeUtility.SizeOf<InclusiveRange>(), 128) / UnsafeUtility.SizeOf<InclusiveRange>();
- var tileRanges = new NativeArray<InclusiveRange>(rangesPerItem * itemsPerTile * viewCount, Allocator.TempJob);
- var tilingJob = new TilingJob
- {
- lights = visibleLights,
- reflectionProbes = reflectionProbes,
- tileRanges = tileRanges,
- itemsPerTile = itemsPerTile,
- rangesPerItem = rangesPerItem,
- worldToViews = worldToViews,
- tileScale = (float2)screenResolution / m_ActualTileWidth,
- tileScaleInv = m_ActualTileWidth / (float2)screenResolution,
- viewPlaneBottoms = new Fixed2<float>(viewPlaneBottom0, viewPlaneBottom1),
- viewPlaneTops = new Fixed2<float>(viewPlaneTop0, viewPlaneTop1),
- viewToViewportScaleBiases = new Fixed2<float4>(viewToViewportScaleBias0, viewToViewportScaleBias1),
- tileCount = m_TileResolution,
- near = camera.nearClipPlane,
- isOrthographic = camera.orthographic
- };
-
- var tileRangeHandle = tilingJob.ScheduleParallel(itemsPerTile * viewCount, 1, reflectionProbeMinMaxZHandle);
-
- var expansionJob = new TileRangeExpansionJob
- {
- tileRanges = tileRanges,
- tileMasks = m_TileMasks,
- rangesPerItem = rangesPerItem,
- itemsPerTile = itemsPerTile,
- wordsPerTile = m_WordsPerTile,
- tileResolution = m_TileResolution,
- };
-
- var tilingHandle = expansionJob.ScheduleParallel(m_TileResolution.y * viewCount, 1, tileRangeHandle);
- m_CullingHandle = JobHandle.CombineDependencies(
- minMaxZs.Dispose(zBinningHandle),
- tileRanges.Dispose(tilingHandle));
-
- JobHandle.ScheduleBatchedJobs();
- }
- }
-
- /// <summary>
- /// Sets up the keywords and data for forward lighting.
- /// </summary>
- /// <param name="context"></param>
- /// <param name="renderingData"></param>
- public void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
- {
- ContextContainer frameData = renderingData.frameData;
- UniversalRenderingData universalRenderingData = frameData.Get<UniversalRenderingData>();
- UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
- UniversalLightData lightData = frameData.Get<UniversalLightData>();
-
- SetupLights(CommandBufferHelpers.GetUnsafeCommandBuffer(renderingData.commandBuffer), universalRenderingData, cameraData, lightData);
- }
-
- static ProfilingSampler s_SetupForwardLights = new ProfilingSampler("Setup Forward Lights");
- private class SetupLightPassData
- {
- internal UniversalRenderingData renderingData;
- internal UniversalCameraData cameraData;
- internal UniversalLightData lightData;
- internal ForwardLights forwardLights;
- };
- /// <summary>
- /// Sets up the ForwardLight data for RenderGraph execution
- /// </summary>
- internal void SetupRenderGraphLights(RenderGraph renderGraph, UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData)
- {
- using (var builder = renderGraph.AddUnsafePass<SetupLightPassData>(s_SetupForwardLights.name, out var passData,
- s_SetupForwardLights))
- {
- passData.renderingData = renderingData;
- passData.cameraData = cameraData;
- passData.lightData = lightData;
- passData.forwardLights = this;
-
- builder.AllowPassCulling(false);
-
- builder.SetRenderFunc((SetupLightPassData data, UnsafeGraphContext rgContext) =>
- {
- data.forwardLights.SetupLights(rgContext.cmd, data.renderingData, data.cameraData, data.lightData);
- });
- }
- }
-
- internal void SetupLights(UnsafeCommandBuffer cmd, UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData)
- {
- int additionalLightsCount = lightData.additionalLightsCount;
- bool additionalLightsPerVertex = lightData.shadeAdditionalLightsPerVertex;
- using (new ProfilingScope(m_ProfilingSampler))
- {
- if (m_UseForwardPlus)
- {
- m_ReflectionProbeManager.UpdateGpuData(CommandBufferHelpers.GetNativeCommandBuffer(cmd), ref renderingData.cullResults);
-
- using (new ProfilingScope(m_ProfilingSamplerFPComplete))
- {
- m_CullingHandle.Complete();
- }
-
- using (new ProfilingScope(m_ProfilingSamplerFPUpload))
- {
- m_ZBinsBuffer.SetData(m_ZBins.Reinterpret<float4>(UnsafeUtility.SizeOf<uint>()));
- m_TileMasksBuffer.SetData(m_TileMasks.Reinterpret<float4>(UnsafeUtility.SizeOf<uint>()));
- cmd.SetGlobalConstantBuffer(m_ZBinsBuffer, "urp_ZBinBuffer", 0, UniversalRenderPipeline.maxZBinWords * 4);
- cmd.SetGlobalConstantBuffer(m_TileMasksBuffer, "urp_TileBuffer", 0, UniversalRenderPipeline.maxTileWords * 4);
- }
-
- cmd.SetGlobalVector("_FPParams0", math.float4(m_ZBinScale, m_ZBinOffset, m_LightCount, m_DirectionalLightCount));
- cmd.SetGlobalVector("_FPParams1", math.float4(cameraData.pixelRect.size / m_ActualTileWidth, m_TileResolution.x, m_WordsPerTile));
- cmd.SetGlobalVector("_FPParams2", math.float4(m_BinCount, m_TileResolution.x * m_TileResolution.y, 0, 0));
- }
-
- SetupShaderLightConstants(cmd, ref renderingData.cullResults, lightData);
-
- bool lightCountCheck = (cameraData.renderer.stripAdditionalLightOffVariants && lightData.supportsAdditionalLights) || additionalLightsCount > 0;
- cmd.SetKeyword(ShaderGlobalKeywords.AdditionalLightsVertex, lightCountCheck && additionalLightsPerVertex && !m_UseForwardPlus);
- cmd.SetKeyword(ShaderGlobalKeywords.AdditionalLightsPixel, lightCountCheck && !additionalLightsPerVertex && !m_UseForwardPlus);
- cmd.SetKeyword(ShaderGlobalKeywords.ForwardPlus, m_UseForwardPlus);
-
- bool isShadowMask = lightData.supportsMixedLighting && m_MixedLightingSetup == MixedLightingSetup.ShadowMask;
- bool isShadowMaskAlways = isShadowMask && QualitySettings.shadowmaskMode == ShadowmaskMode.Shadowmask;
- bool isSubtractive = lightData.supportsMixedLighting && m_MixedLightingSetup == MixedLightingSetup.Subtractive;
- cmd.SetKeyword(ShaderGlobalKeywords.LightmapShadowMixing, isSubtractive || isShadowMaskAlways);
- cmd.SetKeyword(ShaderGlobalKeywords.ShadowsShadowMask, isShadowMask);
- cmd.SetKeyword(ShaderGlobalKeywords.MixedLightingSubtractive, isSubtractive); // Backward compatibility
-
- cmd.SetKeyword(ShaderGlobalKeywords.ReflectionProbeBlending, lightData.reflectionProbeBlending);
- cmd.SetKeyword(ShaderGlobalKeywords.ReflectionProbeBoxProjection, lightData.reflectionProbeBoxProjection);
-
- var asset = UniversalRenderPipeline.asset;
- bool apvIsEnabled = asset != null && asset.lightProbeSystem == LightProbeSystem.ProbeVolumes;
- ProbeVolumeSHBands probeVolumeSHBands = asset.probeVolumeSHBands;
-
- cmd.SetKeyword(ShaderGlobalKeywords.ProbeVolumeL1, apvIsEnabled && probeVolumeSHBands == ProbeVolumeSHBands.SphericalHarmonicsL1);
- cmd.SetKeyword(ShaderGlobalKeywords.ProbeVolumeL2, apvIsEnabled && probeVolumeSHBands == ProbeVolumeSHBands.SphericalHarmonicsL2);
-
- // TODO: If we can robustly detect LIGHTMAP_ON, we can skip SH logic.
- var shMode = PlatformAutoDetect.ShAutoDetect(asset.shEvalMode);
- cmd.SetKeyword(ShaderGlobalKeywords.EVALUATE_SH_MIXED, shMode == ShEvalMode.Mixed);
- cmd.SetKeyword(ShaderGlobalKeywords.EVALUATE_SH_VERTEX, shMode == ShEvalMode.PerVertex);
-
- var stack = VolumeManager.instance.stack;
- bool enableProbeVolumes = ProbeReferenceVolume.instance.UpdateShaderVariablesProbeVolumes(
- CommandBufferHelpers.GetNativeCommandBuffer(cmd),
- stack.GetComponent<ProbeVolumesOptions>(),
- cameraData.IsTemporalAAEnabled() ? Time.frameCount : 0,
- lightData.supportsLightLayers);
-
- cmd.SetGlobalInt("_EnableProbeVolumes", enableProbeVolumes ? 1 : 0);
- cmd.SetKeyword(ShaderGlobalKeywords.LightLayers, lightData.supportsLightLayers && !CoreUtils.IsSceneLightingDisabled(cameraData.camera));
-
- if (m_LightCookieManager != null)
- {
- m_LightCookieManager.Setup(CommandBufferHelpers.GetNativeCommandBuffer(cmd), lightData);
- }
- else
- {
- cmd.SetKeyword(ShaderGlobalKeywords.LightCookies, false);
- }
- }
- }
-
- internal void Cleanup()
- {
- if (m_UseForwardPlus)
- {
- m_CullingHandle.Complete();
- m_ZBins.Dispose();
- m_TileMasks.Dispose();
- m_ZBinsBuffer.Dispose();
- m_ZBinsBuffer = null;
- m_TileMasksBuffer.Dispose();
- m_TileMasksBuffer = null;
- m_ReflectionProbeManager.Dispose();
- }
- }
-
- void InitializeLightConstants(NativeArray<VisibleLight> lights, int lightIndex, bool supportsLightLayers, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightAttenuation, out Vector4 lightSpotDir, out Vector4 lightOcclusionProbeChannel, out uint lightLayerMask, out bool isSubtractive)
- {
- UniversalRenderPipeline.InitializeLightConstants_Common(lights, lightIndex, out lightPos, out lightColor, out lightAttenuation, out lightSpotDir, out lightOcclusionProbeChannel);
- lightLayerMask = 0;
- isSubtractive = false;
-
- // When no lights are visible, main light will be set to -1.
- // In this case we initialize it to default values and return
- if (lightIndex < 0)
- return;
-
- ref VisibleLight lightData = ref lights.UnsafeElementAtMutable(lightIndex);
- Light light = lightData.light;
- var lightBakingOutput = light.bakingOutput;
- isSubtractive = lightBakingOutput.isBaked && lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Subtractive;
-
- if (light == null)
- return;
-
- if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed &&
- lightData.light.shadows != LightShadows.None &&
- m_MixedLightingSetup == MixedLightingSetup.None)
- {
- switch (lightBakingOutput.mixedLightingMode)
- {
- case MixedLightingMode.Subtractive:
- m_MixedLightingSetup = MixedLightingSetup.Subtractive;
- break;
- case MixedLightingMode.Shadowmask:
- m_MixedLightingSetup = MixedLightingSetup.ShadowMask;
- break;
- }
- }
-
- if (supportsLightLayers)
- {
- var additionalLightData = light.GetUniversalAdditionalLightData();
- lightLayerMask = RenderingLayerUtils.ToValidRenderingLayers(additionalLightData.renderingLayers);
- }
- }
-
- void SetupShaderLightConstants(UnsafeCommandBuffer cmd, ref CullingResults cullResults, UniversalLightData lightData)
- {
- m_MixedLightingSetup = MixedLightingSetup.None;
-
- // Main light has an optimized shader path for main light. This will benefit games that only care about a single light.
- // Universal pipeline also supports only a single shadow light, if available it will be the main light.
- SetupMainLightConstants(cmd, lightData);
- SetupAdditionalLightConstants(cmd, ref cullResults, lightData);
- }
-
- void SetupMainLightConstants(UnsafeCommandBuffer cmd, UniversalLightData lightData)
- {
- Vector4 lightPos, lightColor, lightAttenuation, lightSpotDir, lightOcclusionChannel;
- bool supportsLightLayers = lightData.supportsLightLayers;
- uint lightLayerMask;
- bool isSubtractive;
- InitializeLightConstants(lightData.visibleLights, lightData.mainLightIndex, supportsLightLayers, out lightPos, out lightColor, out lightAttenuation, out lightSpotDir, out lightOcclusionChannel, out lightLayerMask, out isSubtractive);
- lightColor.w = isSubtractive ? 0f : 1f;
-
- cmd.SetGlobalVector(LightConstantBuffer._MainLightPosition, lightPos);
- cmd.SetGlobalVector(LightConstantBuffer._MainLightColor, lightColor);
- cmd.SetGlobalVector(LightConstantBuffer._MainLightOcclusionProbesChannel, lightOcclusionChannel);
-
- if (supportsLightLayers)
- cmd.SetGlobalInt(LightConstantBuffer._MainLightLayerMask, (int)lightLayerMask);
- }
-
- void SetupAdditionalLightConstants(UnsafeCommandBuffer cmd, ref CullingResults cullResults, UniversalLightData lightData)
- {
- bool supportsLightLayers = lightData.supportsLightLayers;
- var lights = lightData.visibleLights;
- int maxAdditionalLightsCount = UniversalRenderPipeline.maxVisibleAdditionalLights;
- int additionalLightsCount = SetupPerObjectLightIndices(cullResults, lightData);
- if (additionalLightsCount > 0)
- {
- if (m_UseStructuredBuffer)
- {
- NativeArray<ShaderInput.LightData> additionalLightsData = new NativeArray<ShaderInput.LightData>(additionalLightsCount, Allocator.Temp);
- for (int i = 0, lightIter = 0; i < lights.Length && lightIter < maxAdditionalLightsCount; ++i)
- {
- if (lightData.mainLightIndex != i)
- {
- ShaderInput.LightData data;
- InitializeLightConstants(lights, i, supportsLightLayers,
- out data.position, out data.color, out data.attenuation,
- out data.spotDirection, out data.occlusionProbeChannels,
- out data.layerMask, out _);
- additionalLightsData[lightIter] = data;
- lightIter++;
- }
- }
-
- var lightDataBuffer = ShaderData.instance.GetLightDataBuffer(additionalLightsCount);
- lightDataBuffer.SetData(additionalLightsData);
-
- int lightIndices = cullResults.lightAndReflectionProbeIndexCount;
- var lightIndicesBuffer = ShaderData.instance.GetLightIndicesBuffer(lightIndices);
-
- cmd.SetGlobalBuffer(m_AdditionalLightsBufferId, lightDataBuffer);
- cmd.SetGlobalBuffer(m_AdditionalLightsIndicesId, lightIndicesBuffer);
-
- additionalLightsData.Dispose();
- }
- else
- {
- for (int i = 0, lightIter = 0; i < lights.Length && lightIter < maxAdditionalLightsCount; ++i)
- {
- if (lightData.mainLightIndex != i)
- {
- InitializeLightConstants(
- lights,
- i,
- supportsLightLayers,
- out m_AdditionalLightPositions[lightIter],
- out m_AdditionalLightColors[lightIter],
- out m_AdditionalLightAttenuations[lightIter],
- out m_AdditionalLightSpotDirections[lightIter],
- out m_AdditionalLightOcclusionProbeChannels[lightIter],
- out uint lightLayerMask,
- out var isSubtractive);
-
- if (supportsLightLayers)
- m_AdditionalLightsLayerMasks[lightIter] = math.asfloat(lightLayerMask);
-
- m_AdditionalLightColors[lightIter].w = isSubtractive ? 1f : 0f;
- lightIter++;
- }
- }
-
- cmd.SetGlobalVectorArray(LightConstantBuffer._AdditionalLightsPosition, m_AdditionalLightPositions);
- cmd.SetGlobalVectorArray(LightConstantBuffer._AdditionalLightsColor, m_AdditionalLightColors);
- cmd.SetGlobalVectorArray(LightConstantBuffer._AdditionalLightsAttenuation, m_AdditionalLightAttenuations);
- cmd.SetGlobalVectorArray(LightConstantBuffer._AdditionalLightsSpotDir, m_AdditionalLightSpotDirections);
- cmd.SetGlobalVectorArray(LightConstantBuffer._AdditionalLightOcclusionProbeChannel, m_AdditionalLightOcclusionProbeChannels);
-
- if (supportsLightLayers)
- cmd.SetGlobalFloatArray(LightConstantBuffer._AdditionalLightsLayerMasks, m_AdditionalLightsLayerMasks);
- }
-
- cmd.SetGlobalVector(LightConstantBuffer._AdditionalLightsCount, new Vector4(lightData.maxPerObjectAdditionalLightsCount, 0.0f, 0.0f, 0.0f));
- }
- else
- {
- cmd.SetGlobalVector(LightConstantBuffer._AdditionalLightsCount, Vector4.zero);
- }
- }
-
- int SetupPerObjectLightIndices(CullingResults cullResults, UniversalLightData lightData)
- {
- if (lightData.additionalLightsCount == 0 || m_UseForwardPlus)
- return lightData.additionalLightsCount;
-
- var perObjectLightIndexMap = cullResults.GetLightIndexMap(Allocator.Temp);
- int globalDirectionalLightsCount = 0;
- int additionalLightsCount = 0;
-
- // Disable all directional lights from the perobject light indices
- // Pipeline handles main light globally and there's no support for additional directional lights atm.
- int maxVisibleAdditionalLightsCount = UniversalRenderPipeline.maxVisibleAdditionalLights;
- int len = lightData.visibleLights.Length;
- for (int i = 0; i < len; ++i)
- {
- if (additionalLightsCount >= maxVisibleAdditionalLightsCount)
- break;
-
- if (i == lightData.mainLightIndex)
- {
- perObjectLightIndexMap[i] = -1;
- ++globalDirectionalLightsCount;
- }
- else
- {
- if (lightData.visibleLights[i].lightType == LightType.Directional ||
- lightData.visibleLights[i].lightType == LightType.Spot ||
- lightData.visibleLights[i].lightType == LightType.Point)
- {
- // Light type is supported
- perObjectLightIndexMap[i] -= globalDirectionalLightsCount;
- }
- else
- {
- // Light type is not supported. Skip the light.
- perObjectLightIndexMap[i] = -1;
- }
-
- ++additionalLightsCount;
- }
- }
-
- // Disable all remaining lights we cannot fit into the global light buffer.
- for (int i = globalDirectionalLightsCount + additionalLightsCount; i < perObjectLightIndexMap.Length; ++i)
- perObjectLightIndexMap[i] = -1;
-
- cullResults.SetLightIndexMap(perObjectLightIndexMap);
-
- if (m_UseStructuredBuffer && additionalLightsCount > 0)
- {
- int lightAndReflectionProbeIndices = cullResults.lightAndReflectionProbeIndexCount;
- Assertions.Assert.IsTrue(lightAndReflectionProbeIndices > 0, "Pipelines configures additional lights but per-object light and probe indices count is zero.");
- cullResults.FillLightAndReflectionProbeIndices(ShaderData.instance.GetLightIndicesBuffer(lightAndReflectionProbeIndices));
- }
-
- perObjectLightIndexMap.Dispose();
- return additionalLightsCount;
- }
- }
- }
|