testss
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal interface IRenderPass2D
|
||||
{
|
||||
Renderer2DData rendererData { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
// Only to be used when Pixel Perfect Camera is present and it has Crop Frame X or Y enabled.
|
||||
// This pass simply clears BuiltinRenderTextureType.CameraTarget to black, so that the letterbox or pillarbox is black instead of garbage.
|
||||
// In the future this can be extended to draw a custom background image instead of just clearing.
|
||||
internal class PixelPerfectBackgroundPass : ScriptableRenderPass
|
||||
{
|
||||
private static readonly ProfilingSampler m_ProfilingScope = new ProfilingSampler("Pixel Perfect Background Pass");
|
||||
|
||||
public PixelPerfectBackgroundPass(RenderPassEvent evt)
|
||||
{
|
||||
renderPassEvent = evt;
|
||||
}
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
var cmd = CommandBufferPool.Get();
|
||||
|
||||
using (new ProfilingScope(cmd, m_ProfilingScope))
|
||||
{
|
||||
CoreUtils.SetRenderTarget(
|
||||
cmd,
|
||||
BuiltinRenderTextureType.CameraTarget,
|
||||
RenderBufferLoadAction.DontCare,
|
||||
RenderBufferStoreAction.Store,
|
||||
ClearFlag.Color,
|
||||
Color.black);
|
||||
}
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,328 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal class Render2DLightingPass : ScriptableRenderPass, IRenderPass2D
|
||||
{
|
||||
private static readonly int k_HDREmulationScaleID = Shader.PropertyToID("_HDREmulationScale");
|
||||
private static readonly int k_InverseHDREmulationScaleID = Shader.PropertyToID("_InverseHDREmulationScale");
|
||||
private static readonly int k_UseSceneLightingID = Shader.PropertyToID("_UseSceneLighting");
|
||||
private static readonly int k_RendererColorID = Shader.PropertyToID("_RendererColor");
|
||||
private static readonly int k_CameraSortingLayerTextureID = Shader.PropertyToID("_CameraSortingLayerTexture");
|
||||
|
||||
private static readonly int[] k_ShapeLightTextureIDs =
|
||||
{
|
||||
Shader.PropertyToID("_ShapeLightTexture0"),
|
||||
Shader.PropertyToID("_ShapeLightTexture1"),
|
||||
Shader.PropertyToID("_ShapeLightTexture2"),
|
||||
Shader.PropertyToID("_ShapeLightTexture3")
|
||||
};
|
||||
|
||||
private static readonly ShaderTagId k_CombinedRenderingPassNameOld = new ShaderTagId("Lightweight2D");
|
||||
private static readonly ShaderTagId k_CombinedRenderingPassName = new ShaderTagId("Universal2D");
|
||||
private static readonly ShaderTagId k_NormalsRenderingPassName = new ShaderTagId("NormalsRendering");
|
||||
private static readonly ShaderTagId k_LegacyPassName = new ShaderTagId("SRPDefaultUnlit");
|
||||
private static readonly List<ShaderTagId> k_ShaderTags = new List<ShaderTagId>() { k_LegacyPassName, k_CombinedRenderingPassName, k_CombinedRenderingPassNameOld };
|
||||
|
||||
private static readonly ProfilingSampler m_ProfilingDrawLights = new ProfilingSampler("Draw 2D Lights");
|
||||
private static readonly ProfilingSampler m_ProfilingDrawLightTextures = new ProfilingSampler("Draw 2D Lights Textures");
|
||||
private static readonly ProfilingSampler m_ProfilingDrawRenderers = new ProfilingSampler("Draw All Renderers");
|
||||
private static readonly ProfilingSampler m_ProfilingDrawLayerBatch = new ProfilingSampler("Draw Layer Batch");
|
||||
private static readonly ProfilingSampler m_ProfilingSamplerUnlit = new ProfilingSampler("Render Unlit");
|
||||
|
||||
Material m_BlitMaterial;
|
||||
Material m_SamplingMaterial;
|
||||
|
||||
private readonly Renderer2DData m_Renderer2DData;
|
||||
|
||||
private bool m_HasValidDepth;
|
||||
|
||||
public Render2DLightingPass(Renderer2DData rendererData, Material blitMaterial, Material samplingMaterial)
|
||||
{
|
||||
m_Renderer2DData = rendererData;
|
||||
m_BlitMaterial = blitMaterial;
|
||||
m_SamplingMaterial = samplingMaterial;
|
||||
}
|
||||
|
||||
internal void Setup(bool hasValidDepth)
|
||||
{
|
||||
m_HasValidDepth = hasValidDepth;
|
||||
}
|
||||
|
||||
private void GetTransparencySortingMode(Camera camera, ref SortingSettings sortingSettings)
|
||||
{
|
||||
var mode = m_Renderer2DData.transparencySortMode;
|
||||
|
||||
if (mode == TransparencySortMode.Default)
|
||||
{
|
||||
mode = camera.orthographic ? TransparencySortMode.Orthographic : TransparencySortMode.Perspective;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case TransparencySortMode.Perspective:
|
||||
sortingSettings.distanceMetric = DistanceMetric.Perspective;
|
||||
break;
|
||||
case TransparencySortMode.Orthographic:
|
||||
sortingSettings.distanceMetric = DistanceMetric.Orthographic;
|
||||
break;
|
||||
default:
|
||||
sortingSettings.distanceMetric = DistanceMetric.CustomAxis;
|
||||
sortingSettings.customAxis = m_Renderer2DData.transparencySortAxis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyCameraSortingLayerRenderTexture(ScriptableRenderContext context, RenderingData renderingData)
|
||||
{
|
||||
var cmd = CommandBufferPool.Get();
|
||||
cmd.Clear();
|
||||
this.CreateCameraSortingLayerRenderTexture(renderingData, cmd, m_Renderer2DData.cameraSortingLayerDownsamplingMethod);
|
||||
|
||||
Material copyMaterial = m_Renderer2DData.cameraSortingLayerDownsamplingMethod == Downsampling._4xBox ? m_SamplingMaterial : m_BlitMaterial;
|
||||
RenderingUtils.Blit(cmd, colorAttachment, m_Renderer2DData.cameraSortingLayerRenderTarget.id, copyMaterial, 0, false, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
|
||||
cmd.SetRenderTarget(colorAttachment);
|
||||
cmd.SetGlobalTexture(k_CameraSortingLayerTextureID, m_Renderer2DData.cameraSortingLayerRenderTarget.id);
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
}
|
||||
|
||||
private short GetCameraSortingLayerBoundsIndex()
|
||||
{
|
||||
SortingLayer[] sortingLayers = Light2DManager.GetCachedSortingLayer();
|
||||
for (short i = 0; i < sortingLayers.Length; i++)
|
||||
{
|
||||
if (sortingLayers[i].id == m_Renderer2DData.cameraSortingLayerTextureBound)
|
||||
return (short)sortingLayers[i].value;
|
||||
}
|
||||
|
||||
return short.MinValue;
|
||||
}
|
||||
|
||||
private int DrawLayerBatches(
|
||||
LayerBatch[] layerBatches,
|
||||
int batchCount,
|
||||
int startIndex,
|
||||
CommandBuffer cmd,
|
||||
ScriptableRenderContext context,
|
||||
ref RenderingData renderingData,
|
||||
ref FilteringSettings filterSettings,
|
||||
ref DrawingSettings normalsDrawSettings,
|
||||
ref DrawingSettings drawSettings,
|
||||
ref RenderTextureDescriptor desc)
|
||||
{
|
||||
var batchesDrawn = 0;
|
||||
var rtCount = 0U;
|
||||
// Draw lights
|
||||
using (new ProfilingScope(cmd, m_ProfilingDrawLights))
|
||||
{
|
||||
for (var i = startIndex; i < batchCount; ++i)
|
||||
{
|
||||
ref var layerBatch = ref layerBatches[i];
|
||||
|
||||
var blendStyleMask = layerBatch.lightStats.blendStylesUsed;
|
||||
var blendStyleCount = 0U;
|
||||
while (blendStyleMask > 0)
|
||||
{
|
||||
blendStyleCount += blendStyleMask & 1;
|
||||
blendStyleMask >>= 1;
|
||||
}
|
||||
|
||||
rtCount += blendStyleCount;
|
||||
|
||||
if (rtCount > LayerUtility.maxTextureCount)
|
||||
break;
|
||||
|
||||
batchesDrawn++;
|
||||
|
||||
if (layerBatch.lightStats.totalNormalMapUsage > 0)
|
||||
{
|
||||
filterSettings.sortingLayerRange = layerBatch.layerRange;
|
||||
var depthTarget = m_HasValidDepth ? depthAttachment : BuiltinRenderTextureType.None;
|
||||
this.RenderNormals(context, renderingData, normalsDrawSettings, filterSettings, depthTarget, cmd, layerBatch.lightStats);
|
||||
}
|
||||
|
||||
using (new ProfilingScope(cmd, m_ProfilingDrawLightTextures))
|
||||
{
|
||||
this.RenderLights(renderingData, cmd, layerBatch.startLayerID, ref layerBatch, ref desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw renderers
|
||||
var blendStylesCount = m_Renderer2DData.lightBlendStyles.Length;
|
||||
using (new ProfilingScope(cmd, m_ProfilingDrawRenderers))
|
||||
{
|
||||
cmd.SetRenderTarget(colorAttachment, depthAttachment);
|
||||
|
||||
for (var i = startIndex; i < startIndex + batchesDrawn; i++)
|
||||
{
|
||||
using (new ProfilingScope(cmd, m_ProfilingDrawLayerBatch))
|
||||
{
|
||||
// This is a local copy of the array element (it's a struct). Remember to add a ref here if you need to modify the real thing.
|
||||
var layerBatch = layerBatches[i];
|
||||
|
||||
if (layerBatch.lightStats.totalLights > 0)
|
||||
{
|
||||
for (var blendStyleIndex = 0; blendStyleIndex < blendStylesCount; blendStyleIndex++)
|
||||
{
|
||||
var blendStyleMask = (uint)(1 << blendStyleIndex);
|
||||
var blendStyleUsed = (layerBatch.lightStats.blendStylesUsed & blendStyleMask) > 0;
|
||||
|
||||
if (blendStyleUsed)
|
||||
{
|
||||
var identifier = layerBatch.GetRTId(cmd, desc, blendStyleIndex);
|
||||
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], identifier);
|
||||
}
|
||||
|
||||
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleUsed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var blendStyleIndex = 0; blendStyleIndex < k_ShapeLightTextureIDs.Length; blendStyleIndex++)
|
||||
{
|
||||
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], Texture2D.blackTexture);
|
||||
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleIndex == 0);
|
||||
}
|
||||
}
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
cmd.Clear();
|
||||
|
||||
|
||||
short cameraSortingLayerBoundsIndex = GetCameraSortingLayerBoundsIndex();
|
||||
// If our camera sorting layer texture bound is inside our batch we need to break up the DrawRenderers into two batches
|
||||
if (cameraSortingLayerBoundsIndex >= layerBatch.layerRange.lowerBound && cameraSortingLayerBoundsIndex < layerBatch.layerRange.upperBound && m_Renderer2DData.useCameraSortingLayerTexture)
|
||||
{
|
||||
filterSettings.sortingLayerRange = new SortingLayerRange(layerBatch.layerRange.lowerBound, cameraSortingLayerBoundsIndex);
|
||||
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
|
||||
CopyCameraSortingLayerRenderTexture(context, renderingData);
|
||||
|
||||
filterSettings.sortingLayerRange = new SortingLayerRange((short)(cameraSortingLayerBoundsIndex + 1), layerBatch.layerRange.upperBound);
|
||||
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterSettings.sortingLayerRange = new SortingLayerRange(layerBatch.layerRange.lowerBound, layerBatch.layerRange.upperBound);
|
||||
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
|
||||
if (cameraSortingLayerBoundsIndex == layerBatch.layerRange.upperBound && m_Renderer2DData.useCameraSortingLayerTexture)
|
||||
CopyCameraSortingLayerRenderTexture(context, renderingData);
|
||||
}
|
||||
|
||||
// Draw light volumes
|
||||
if (layerBatch.lightStats.totalVolumetricUsage > 0)
|
||||
{
|
||||
var sampleName = "Render 2D Light Volumes";
|
||||
cmd.BeginSample(sampleName);
|
||||
|
||||
this.RenderLightVolumes(renderingData, cmd, layerBatch.startLayerID, layerBatch.endLayerValue, colorAttachment, depthAttachment, m_Renderer2DData.lightCullResult.visibleLights);
|
||||
|
||||
cmd.EndSample(sampleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = startIndex; i < startIndex + batchesDrawn; ++i)
|
||||
{
|
||||
ref var layerBatch = ref layerBatches[i];
|
||||
layerBatch.ReleaseRT(cmd);
|
||||
}
|
||||
|
||||
return batchesDrawn;
|
||||
}
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
var isLitView = true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (renderingData.cameraData.isSceneViewCamera)
|
||||
isLitView = UnityEditor.SceneView.currentDrawingSceneView.sceneLighting;
|
||||
|
||||
if (renderingData.cameraData.camera.cameraType == CameraType.Preview)
|
||||
isLitView = false;
|
||||
#endif
|
||||
var camera = renderingData.cameraData.camera;
|
||||
var filterSettings = new FilteringSettings();
|
||||
filterSettings.renderQueueRange = RenderQueueRange.all;
|
||||
filterSettings.layerMask = -1;
|
||||
filterSettings.renderingLayerMask = 0xFFFFFFFF;
|
||||
filterSettings.sortingLayerRange = SortingLayerRange.all;
|
||||
|
||||
LayerUtility.InitializeBudget(m_Renderer2DData.lightRenderTextureMemoryBudget);
|
||||
ShadowRendering.InitializeBudget(m_Renderer2DData.shadowRenderTextureMemoryBudget);
|
||||
|
||||
var isSceneLit = m_Renderer2DData.lightCullResult.IsSceneLit();
|
||||
if (isSceneLit)
|
||||
{
|
||||
var combinedDrawSettings = CreateDrawingSettings(k_ShaderTags, ref renderingData, SortingCriteria.CommonTransparent);
|
||||
var normalsDrawSettings = CreateDrawingSettings(k_NormalsRenderingPassName, ref renderingData, SortingCriteria.CommonTransparent);
|
||||
|
||||
var sortSettings = combinedDrawSettings.sortingSettings;
|
||||
GetTransparencySortingMode(camera, ref sortSettings);
|
||||
combinedDrawSettings.sortingSettings = sortSettings;
|
||||
normalsDrawSettings.sortingSettings = sortSettings;
|
||||
|
||||
var cmd = CommandBufferPool.Get();
|
||||
cmd.SetGlobalFloat(k_HDREmulationScaleID, m_Renderer2DData.hdrEmulationScale);
|
||||
cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / m_Renderer2DData.hdrEmulationScale);
|
||||
cmd.SetGlobalFloat(k_UseSceneLightingID, isLitView ? 1.0f : 0.0f);
|
||||
cmd.SetGlobalColor(k_RendererColorID, Color.white);
|
||||
this.SetShapeLightShaderGlobals(cmd);
|
||||
|
||||
var desc = this.GetBlendStyleRenderTextureDesc(renderingData);
|
||||
|
||||
var layerBatches = LayerUtility.CalculateBatches(m_Renderer2DData.lightCullResult, out var batchCount);
|
||||
var batchesDrawn = 0;
|
||||
|
||||
for (var i = 0; i < batchCount; i += batchesDrawn)
|
||||
batchesDrawn = DrawLayerBatches(layerBatches, batchCount, i, cmd, context, ref renderingData, ref filterSettings, ref normalsDrawSettings, ref combinedDrawSettings, ref desc);
|
||||
|
||||
this.ReleaseRenderTextures(cmd);
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
var unlitDrawSettings = CreateDrawingSettings(k_ShaderTags, ref renderingData, SortingCriteria.CommonTransparent);
|
||||
|
||||
var cmd = CommandBufferPool.Get();
|
||||
using (new ProfilingScope(cmd, m_ProfilingSamplerUnlit))
|
||||
{
|
||||
CoreUtils.SetRenderTarget(cmd, colorAttachment, depthAttachment, ClearFlag.None, Color.white);
|
||||
|
||||
cmd.SetGlobalFloat(k_UseSceneLightingID, isLitView ? 1.0f : 0.0f);
|
||||
cmd.SetGlobalColor(k_RendererColorID, Color.white);
|
||||
|
||||
for (var blendStyleIndex = 0; blendStyleIndex < k_ShapeLightTextureIDs.Length; blendStyleIndex++)
|
||||
{
|
||||
if (blendStyleIndex == 0)
|
||||
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], Texture2D.blackTexture);
|
||||
|
||||
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleIndex == 0);
|
||||
}
|
||||
}
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
|
||||
Profiler.BeginSample("Render Sprites Unlit");
|
||||
context.DrawRenderers(renderingData.cullResults, ref unlitDrawSettings, ref filterSettings);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
filterSettings.sortingLayerRange = SortingLayerRange.all;
|
||||
RenderingUtils.RenderObjectsWithError(context, ref renderingData.cullResults, camera, filterSettings, SortingCriteria.None);
|
||||
}
|
||||
|
||||
Renderer2DData IRenderPass2D.rendererData
|
||||
{
|
||||
get { return m_Renderer2DData; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,154 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal struct LayerBatch
|
||||
{
|
||||
public int startLayerID;
|
||||
public int endLayerValue;
|
||||
public SortingLayerRange layerRange;
|
||||
public LightStats lightStats;
|
||||
private unsafe fixed int renderTargetIds[4];
|
||||
private unsafe fixed bool renderTargetUsed[4];
|
||||
|
||||
public void InitRTIds(int index)
|
||||
{
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
renderTargetUsed[i] = false;
|
||||
renderTargetIds[i] = Shader.PropertyToID($"_LightTexture_{index}_{i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RenderTargetIdentifier GetRTId(CommandBuffer cmd, RenderTextureDescriptor desc, int index)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
if (!renderTargetUsed[index])
|
||||
{
|
||||
cmd.GetTemporaryRT(renderTargetIds[index], desc, FilterMode.Bilinear);
|
||||
renderTargetUsed[index] = true;
|
||||
}
|
||||
return new RenderTargetIdentifier(renderTargetIds[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseRT(CommandBuffer cmd)
|
||||
{
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
if (!renderTargetUsed[i])
|
||||
continue;
|
||||
|
||||
cmd.ReleaseTemporaryRT(renderTargetIds[i]);
|
||||
renderTargetUsed[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LayerUtility
|
||||
{
|
||||
private static LayerBatch[] s_LayerBatches;
|
||||
public static uint maxTextureCount { get; private set; }
|
||||
|
||||
public static void InitializeBudget(uint maxTextureCount)
|
||||
{
|
||||
LayerUtility.maxTextureCount = math.max(4, maxTextureCount);
|
||||
}
|
||||
|
||||
private static bool CanBatchLightsInLayer(int layerIndex1, int layerIndex2, SortingLayer[] sortingLayers, ILight2DCullResult lightCullResult)
|
||||
{
|
||||
var layerId1 = sortingLayers[layerIndex1].id;
|
||||
var layerId2 = sortingLayers[layerIndex2].id;
|
||||
foreach (var light in lightCullResult.visibleLights)
|
||||
{
|
||||
// If the lit layers are different, or if they are lit but this is a shadow casting light then don't batch.
|
||||
if ((light.IsLitLayer(layerId1) != light.IsLitLayer(layerId2)) || (light.IsLitLayer(layerId1) && light.shadowsEnabled))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int FindUpperBoundInBatch(int startLayerIndex, SortingLayer[] sortingLayers, ILight2DCullResult lightCullResult)
|
||||
{
|
||||
// start checking at the next layer
|
||||
for (var i = startLayerIndex + 1; i < sortingLayers.Length; i++)
|
||||
{
|
||||
if (!CanBatchLightsInLayer(startLayerIndex, i, sortingLayers, lightCullResult))
|
||||
return i - 1;
|
||||
}
|
||||
return sortingLayers.Length - 1;
|
||||
}
|
||||
|
||||
private static void InitializeBatchInfos(SortingLayer[] cachedSortingLayers)
|
||||
{
|
||||
var count = cachedSortingLayers.Length;
|
||||
var needInit = s_LayerBatches == null;
|
||||
if (s_LayerBatches is null)
|
||||
{
|
||||
s_LayerBatches = new LayerBatch[count];
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// we should fix. Make a non allocating version of this
|
||||
if (!Application.isPlaying && s_LayerBatches.Length != count)
|
||||
{
|
||||
s_LayerBatches = new LayerBatch[count];
|
||||
needInit = true;
|
||||
}
|
||||
#endif
|
||||
if (needInit)
|
||||
{
|
||||
for (var i = 0; i < s_LayerBatches.Length; i++)
|
||||
{
|
||||
ref var layerBatch = ref s_LayerBatches[i];
|
||||
layerBatch.InitRTIds(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static LayerBatch[] CalculateBatches(ILight2DCullResult lightCullResult, out int batchCount)
|
||||
{
|
||||
var cachedSortingLayers = Light2DManager.GetCachedSortingLayer();
|
||||
InitializeBatchInfos(cachedSortingLayers);
|
||||
|
||||
batchCount = 0;
|
||||
for (var i = 0; i < cachedSortingLayers.Length;)
|
||||
{
|
||||
var layerToRender = cachedSortingLayers[i].id;
|
||||
var lightStats = lightCullResult.GetLightStatsByLayer(layerToRender);
|
||||
ref var layerBatch = ref s_LayerBatches[batchCount++];
|
||||
|
||||
// Find the highest layer that share the same set of lights as this layer.
|
||||
var upperLayerInBatch = FindUpperBoundInBatch(i, cachedSortingLayers, lightCullResult);
|
||||
|
||||
// Some renderers override their sorting layer value with short.MinValue or short.MaxValue.
|
||||
// When drawing the first sorting layer, we should include the range from short.MinValue to layerValue.
|
||||
// Similarly, when drawing the last sorting layer, include the range from layerValue to short.MaxValue.
|
||||
var startLayerValue = (short)cachedSortingLayers[i].value;
|
||||
var lowerBound = (i == 0) ? short.MinValue : startLayerValue;
|
||||
var endLayerValue = (short)cachedSortingLayers[upperLayerInBatch].value;
|
||||
var upperBound = (upperLayerInBatch == cachedSortingLayers.Length - 1) ? short.MaxValue : endLayerValue;
|
||||
|
||||
// Renderer within this range share the same set of lights so they should be rendered together.
|
||||
var sortingLayerRange = new SortingLayerRange(lowerBound, upperBound);
|
||||
|
||||
layerBatch.startLayerID = layerToRender;
|
||||
layerBatch.endLayerValue = endLayerValue;
|
||||
layerBatch.layerRange = sortingLayerRange;
|
||||
layerBatch.lightStats = lightStats;
|
||||
|
||||
i = upperLayerInBatch + 1;
|
||||
}
|
||||
|
||||
return s_LayerBatches;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal static class Light2DLookupTexture
|
||||
{
|
||||
private static Texture2D s_PointLightLookupTexture;
|
||||
private static Texture2D s_FalloffLookupTexture;
|
||||
|
||||
public static Texture GetLightLookupTexture()
|
||||
{
|
||||
if (s_PointLightLookupTexture == null)
|
||||
s_PointLightLookupTexture = CreatePointLightLookupTexture();
|
||||
return s_PointLightLookupTexture;
|
||||
}
|
||||
|
||||
private static Texture2D CreatePointLightLookupTexture()
|
||||
{
|
||||
const int WIDTH = 256;
|
||||
const int HEIGHT = 256;
|
||||
|
||||
var textureFormat = GraphicsFormat.R8G8B8A8_UNorm;
|
||||
if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.SetPixels))
|
||||
textureFormat = GraphicsFormat.R16G16B16A16_SFloat;
|
||||
else if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R32G32B32A32_SFloat, FormatUsage.SetPixels))
|
||||
textureFormat = GraphicsFormat.R32G32B32A32_SFloat;
|
||||
|
||||
var texture = new Texture2D(WIDTH, HEIGHT, textureFormat, TextureCreationFlags.None);
|
||||
texture.filterMode = FilterMode.Bilinear;
|
||||
texture.wrapMode = TextureWrapMode.Clamp;
|
||||
var center = new Vector2(WIDTH / 2.0f, HEIGHT / 2.0f);
|
||||
|
||||
for (var y = 0; y < HEIGHT; y++)
|
||||
{
|
||||
for (var x = 0; x < WIDTH; x++)
|
||||
{
|
||||
var pos = new Vector2(x, y);
|
||||
var distance = Vector2.Distance(pos, center);
|
||||
var relPos = pos - center;
|
||||
var direction = center - pos;
|
||||
direction.Normalize();
|
||||
|
||||
// red = 1-0 distance
|
||||
// green = 1-0 angle
|
||||
// blue = direction.x
|
||||
// alpha = direction.y
|
||||
|
||||
float red;
|
||||
if (x == WIDTH - 1 || y == HEIGHT - 1)
|
||||
red = 0;
|
||||
else
|
||||
red = Mathf.Clamp(1 - (2.0f * distance / WIDTH), 0.0f, 1.0f);
|
||||
|
||||
var cosAngle = Vector2.Dot(Vector2.down, relPos.normalized);
|
||||
var angle = Mathf.Acos(cosAngle) / Mathf.PI; // 0-1
|
||||
|
||||
var green = Mathf.Clamp(1 - angle, 0.0f, 1.0f);
|
||||
var blue = direction.x;
|
||||
var alpha = direction.y;
|
||||
|
||||
var color = new Color(red, green, blue, alpha);
|
||||
|
||||
texture.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
texture.Apply();
|
||||
return texture;
|
||||
}
|
||||
|
||||
//#if UNITY_EDITOR
|
||||
// [MenuItem("Light2D Debugging/Write Light Texture")]
|
||||
// static public void WriteLightTexture()
|
||||
// {
|
||||
// var path = EditorUtility.SaveFilePanel("Save texture as PNG", "", "LightLookupTexture.exr", "png");
|
||||
|
||||
// CreatePointLightLookupTexture();
|
||||
|
||||
// byte[] imgData = s_PointLightLookupTexture.EncodeToEXR(Texture2D.EXRFlags.CompressRLE);
|
||||
// if (imgData != null)
|
||||
// File.WriteAllBytes(path, imgData);
|
||||
// }
|
||||
|
||||
// [MenuItem("Light2D Debugging/Write Falloff Texture")]
|
||||
// static public void WriteCurveTexture()
|
||||
// {
|
||||
// var path = EditorUtility.SaveFilePanel("Save texture as PNG", "", "FalloffLookupTexture.png", "png");
|
||||
|
||||
// CreateFalloffLookupTexture();
|
||||
|
||||
// byte[] imgData = s_FalloffLookupTexture.EncodeToPNG();
|
||||
// if (imgData != null)
|
||||
// File.WriteAllBytes(path, imgData);
|
||||
// }
|
||||
//#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,615 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal static class RendererLighting
|
||||
{
|
||||
private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler("Draw Normals");
|
||||
private static readonly ShaderTagId k_NormalsRenderingPassName = new ShaderTagId("NormalsRendering");
|
||||
private static readonly Color k_NormalClearColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
private static readonly string k_SpriteLightKeyword = "SPRITE_LIGHT";
|
||||
private static readonly string k_UsePointLightCookiesKeyword = "USE_POINT_LIGHT_COOKIES";
|
||||
private static readonly string k_LightQualityFastKeyword = "LIGHT_QUALITY_FAST";
|
||||
private static readonly string k_UseNormalMap = "USE_NORMAL_MAP";
|
||||
private static readonly string k_UseAdditiveBlendingKeyword = "USE_ADDITIVE_BLENDING";
|
||||
|
||||
private static readonly string[] k_UseBlendStyleKeywords =
|
||||
{
|
||||
"USE_SHAPE_LIGHT_TYPE_0", "USE_SHAPE_LIGHT_TYPE_1", "USE_SHAPE_LIGHT_TYPE_2", "USE_SHAPE_LIGHT_TYPE_3"
|
||||
};
|
||||
|
||||
private static readonly int[] k_BlendFactorsPropIDs =
|
||||
{
|
||||
Shader.PropertyToID("_ShapeLightBlendFactors0"),
|
||||
Shader.PropertyToID("_ShapeLightBlendFactors1"),
|
||||
Shader.PropertyToID("_ShapeLightBlendFactors2"),
|
||||
Shader.PropertyToID("_ShapeLightBlendFactors3")
|
||||
};
|
||||
|
||||
private static readonly int[] k_MaskFilterPropIDs =
|
||||
{
|
||||
Shader.PropertyToID("_ShapeLightMaskFilter0"),
|
||||
Shader.PropertyToID("_ShapeLightMaskFilter1"),
|
||||
Shader.PropertyToID("_ShapeLightMaskFilter2"),
|
||||
Shader.PropertyToID("_ShapeLightMaskFilter3")
|
||||
};
|
||||
|
||||
private static readonly int[] k_InvertedFilterPropIDs =
|
||||
{
|
||||
Shader.PropertyToID("_ShapeLightInvertedFilter0"),
|
||||
Shader.PropertyToID("_ShapeLightInvertedFilter1"),
|
||||
Shader.PropertyToID("_ShapeLightInvertedFilter2"),
|
||||
Shader.PropertyToID("_ShapeLightInvertedFilter3")
|
||||
};
|
||||
|
||||
private static GraphicsFormat s_RenderTextureFormatToUse = GraphicsFormat.R8G8B8A8_UNorm;
|
||||
private static bool s_HasSetupRenderTextureFormatToUse;
|
||||
|
||||
private static readonly int k_SrcBlendID = Shader.PropertyToID("_SrcBlend");
|
||||
private static readonly int k_DstBlendID = Shader.PropertyToID("_DstBlend");
|
||||
private static readonly int k_FalloffIntensityID = Shader.PropertyToID("_FalloffIntensity");
|
||||
private static readonly int k_FalloffDistanceID = Shader.PropertyToID("_FalloffDistance");
|
||||
private static readonly int k_LightColorID = Shader.PropertyToID("_LightColor");
|
||||
private static readonly int k_VolumeOpacityID = Shader.PropertyToID("_VolumeOpacity");
|
||||
private static readonly int k_CookieTexID = Shader.PropertyToID("_CookieTex");
|
||||
private static readonly int k_FalloffLookupID = Shader.PropertyToID("_FalloffLookup");
|
||||
private static readonly int k_LightPositionID = Shader.PropertyToID("_LightPosition");
|
||||
private static readonly int k_LightInvMatrixID = Shader.PropertyToID("_LightInvMatrix");
|
||||
private static readonly int k_InnerRadiusMultID = Shader.PropertyToID("_InnerRadiusMult");
|
||||
private static readonly int k_OuterAngleID = Shader.PropertyToID("_OuterAngle");
|
||||
private static readonly int k_InnerAngleMultID = Shader.PropertyToID("_InnerAngleMult");
|
||||
private static readonly int k_LightLookupID = Shader.PropertyToID("_LightLookup");
|
||||
private static readonly int k_IsFullSpotlightID = Shader.PropertyToID("_IsFullSpotlight");
|
||||
private static readonly int k_LightZDistanceID = Shader.PropertyToID("_LightZDistance");
|
||||
private static readonly int k_PointLightCookieTexID = Shader.PropertyToID("_PointLightCookieTex");
|
||||
|
||||
private static GraphicsFormat GetRenderTextureFormat()
|
||||
{
|
||||
if (!s_HasSetupRenderTextureFormatToUse)
|
||||
{
|
||||
if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render))
|
||||
s_RenderTextureFormatToUse = GraphicsFormat.B10G11R11_UFloatPack32;
|
||||
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.Linear | FormatUsage.Render))
|
||||
s_RenderTextureFormatToUse = GraphicsFormat.R16G16B16A16_SFloat;
|
||||
|
||||
s_HasSetupRenderTextureFormatToUse = true;
|
||||
}
|
||||
|
||||
return s_RenderTextureFormatToUse;
|
||||
}
|
||||
|
||||
public static void CreateNormalMapRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, float renderScale)
|
||||
{
|
||||
if (renderScale != pass.rendererData.normalsRenderTargetScale)
|
||||
{
|
||||
if (pass.rendererData.isNormalsRenderTargetValid)
|
||||
{
|
||||
cmd.ReleaseTemporaryRT(pass.rendererData.normalsRenderTarget.id);
|
||||
}
|
||||
|
||||
pass.rendererData.isNormalsRenderTargetValid = true;
|
||||
pass.rendererData.normalsRenderTargetScale = renderScale;
|
||||
|
||||
var descriptor = new RenderTextureDescriptor(
|
||||
(int)(renderingData.cameraData.cameraTargetDescriptor.width * renderScale),
|
||||
(int)(renderingData.cameraData.cameraTargetDescriptor.height * renderScale));
|
||||
|
||||
descriptor.graphicsFormat = GetRenderTextureFormat();
|
||||
descriptor.useMipMap = false;
|
||||
descriptor.autoGenerateMips = false;
|
||||
descriptor.depthBufferBits = 0;
|
||||
descriptor.msaaSamples = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
|
||||
cmd.GetTemporaryRT(pass.rendererData.normalsRenderTarget.id, descriptor, FilterMode.Bilinear);
|
||||
}
|
||||
}
|
||||
|
||||
public static RenderTextureDescriptor GetBlendStyleRenderTextureDesc(this IRenderPass2D pass, RenderingData renderingData)
|
||||
{
|
||||
var renderTextureScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
|
||||
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
|
||||
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
|
||||
|
||||
var descriptor = new RenderTextureDescriptor(width, height);
|
||||
descriptor.graphicsFormat = GetRenderTextureFormat();
|
||||
descriptor.useMipMap = false;
|
||||
descriptor.autoGenerateMips = false;
|
||||
descriptor.depthBufferBits = 0;
|
||||
descriptor.msaaSamples = 1;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public static void CreateCameraSortingLayerRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, Downsampling downsamplingMethod)
|
||||
{
|
||||
var renderTextureScale = 1.0f;
|
||||
if (downsamplingMethod == Downsampling._2xBilinear)
|
||||
renderTextureScale = 0.5f;
|
||||
else if (downsamplingMethod == Downsampling._4xBox || downsamplingMethod == Downsampling._4xBilinear)
|
||||
renderTextureScale = 0.25f;
|
||||
|
||||
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
|
||||
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
|
||||
|
||||
var descriptor = new RenderTextureDescriptor(width, height);
|
||||
descriptor.graphicsFormat = renderingData.cameraData.cameraTargetDescriptor.graphicsFormat;
|
||||
descriptor.useMipMap = false;
|
||||
descriptor.autoGenerateMips = false;
|
||||
descriptor.depthBufferBits = 0;
|
||||
descriptor.msaaSamples = 1;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
|
||||
cmd.GetTemporaryRT(pass.rendererData.cameraSortingLayerRenderTarget.id, descriptor, FilterMode.Bilinear);
|
||||
}
|
||||
|
||||
public static void EnableBlendStyle(CommandBuffer cmd, int blendStyleIndex, bool enabled)
|
||||
{
|
||||
var keyword = k_UseBlendStyleKeywords[blendStyleIndex];
|
||||
|
||||
if (enabled)
|
||||
cmd.EnableShaderKeyword(keyword);
|
||||
else
|
||||
cmd.DisableShaderKeyword(keyword);
|
||||
}
|
||||
|
||||
public static void ReleaseRenderTextures(this IRenderPass2D pass, CommandBuffer cmd)
|
||||
{
|
||||
pass.rendererData.isNormalsRenderTargetValid = false;
|
||||
pass.rendererData.normalsRenderTargetScale = 0.0f;
|
||||
cmd.ReleaseTemporaryRT(pass.rendererData.normalsRenderTarget.id);
|
||||
cmd.ReleaseTemporaryRT(pass.rendererData.shadowsRenderTarget.id);
|
||||
cmd.ReleaseTemporaryRT(pass.rendererData.cameraSortingLayerRenderTarget.id);
|
||||
}
|
||||
|
||||
public static void DrawPointLight(CommandBuffer cmd, Light2D light, Mesh lightMesh, Material material)
|
||||
{
|
||||
var scale = new Vector3(light.pointLightOuterRadius, light.pointLightOuterRadius, light.pointLightOuterRadius);
|
||||
var matrix = Matrix4x4.TRS(light.transform.position, light.transform.rotation, scale);
|
||||
cmd.DrawMesh(lightMesh, matrix, material);
|
||||
}
|
||||
|
||||
private static void RenderLightSet(IRenderPass2D pass, RenderingData renderingData, int blendStyleIndex, CommandBuffer cmd, int layerToRender, RenderTargetIdentifier renderTexture, List<Light2D> lights)
|
||||
{
|
||||
var maxShadowTextureCount = ShadowRendering.maxTextureCount;
|
||||
var requiresRTInit = true;
|
||||
|
||||
// This case should never happen, but if it does it may cause an infinite loop later.
|
||||
if (maxShadowTextureCount < 1)
|
||||
{
|
||||
Debug.LogError("maxShadowTextureCount cannot be less than 1");
|
||||
return;
|
||||
}
|
||||
|
||||
// Break up light rendering into batches for the purpose of shadow casting
|
||||
var lightIndex = 0;
|
||||
while (lightIndex < lights.Count)
|
||||
{
|
||||
var remainingLights = (uint)lights.Count - lightIndex;
|
||||
var batchedLights = 0;
|
||||
|
||||
// Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
|
||||
var shadowLightCount = 0;
|
||||
while (batchedLights < remainingLights && shadowLightCount < maxShadowTextureCount)
|
||||
{
|
||||
var light = lights[lightIndex + batchedLights];
|
||||
if (light.shadowsEnabled && light.shadowIntensity > 0)
|
||||
{
|
||||
ShadowRendering.CreateShadowRenderTexture(pass, renderingData, cmd, shadowLightCount);
|
||||
ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowIntensity);
|
||||
shadowLightCount++;
|
||||
}
|
||||
batchedLights++;
|
||||
}
|
||||
|
||||
// Set the current RT to the light RT
|
||||
if (shadowLightCount > 0 || requiresRTInit)
|
||||
{
|
||||
cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
|
||||
requiresRTInit = false;
|
||||
}
|
||||
|
||||
// Render all the lights.
|
||||
shadowLightCount = 0;
|
||||
for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
|
||||
{
|
||||
var light = lights[(int)(lightIndex + lightIndexOffset)];
|
||||
|
||||
if (light != null &&
|
||||
light.lightType != Light2D.LightType.Global &&
|
||||
light.blendStyleIndex == blendStyleIndex &&
|
||||
light.IsLitLayer(layerToRender))
|
||||
{
|
||||
// Render light
|
||||
var lightMaterial = pass.rendererData.GetLightMaterial(light, false);
|
||||
if (lightMaterial == null)
|
||||
continue;
|
||||
|
||||
var lightMesh = light.lightMesh;
|
||||
if (lightMesh == null)
|
||||
continue;
|
||||
|
||||
// Set the shadow texture to read from
|
||||
if (light.shadowsEnabled && light.shadowIntensity > 0)
|
||||
ShadowRendering.SetGlobalShadowTexture(cmd, light, shadowLightCount++);
|
||||
else
|
||||
ShadowRendering.DisableGlobalShadowTexture(cmd);
|
||||
|
||||
|
||||
if (light.lightType == Light2D.LightType.Sprite && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
|
||||
cmd.SetGlobalTexture(k_CookieTexID, light.lightCookieSprite.texture);
|
||||
|
||||
SetGeneralLightShaderGlobals(pass, cmd, light);
|
||||
|
||||
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
|
||||
SetPointLightShaderGlobals(pass, cmd, light);
|
||||
|
||||
// Light code could be combined...
|
||||
if (light.lightType == (Light2D.LightType)Light2D.DeprecatedLightType.Parametric || light.lightType == Light2D.LightType.Freeform || light.lightType == Light2D.LightType.Sprite)
|
||||
{
|
||||
cmd.DrawMesh(lightMesh, light.transform.localToWorldMatrix, lightMaterial);
|
||||
}
|
||||
else if (light.lightType == Light2D.LightType.Point)
|
||||
{
|
||||
DrawPointLight(cmd, light, lightMesh, lightMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release all of the temporary shadow textures
|
||||
for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
|
||||
ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
|
||||
|
||||
lightIndex += batchedLights;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RenderLightVolumes(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, int layerToRender, int endLayerValue, RenderTargetIdentifier renderTexture, RenderTargetIdentifier depthTexture, List<Light2D> lights)
|
||||
{
|
||||
var maxShadowTextureCount = ShadowRendering.maxTextureCount;
|
||||
var requiresRTInit = true;
|
||||
|
||||
// This case should never happen, but if it does it may cause an infinite loop later.
|
||||
if (maxShadowTextureCount < 1)
|
||||
{
|
||||
Debug.LogError("maxShadowTextureCount cannot be less than 1");
|
||||
return;
|
||||
}
|
||||
|
||||
// Break up light rendering into batches for the purpose of shadow casting
|
||||
var lightIndex = 0;
|
||||
while (lightIndex < lights.Count)
|
||||
{
|
||||
var remainingLights = (uint)lights.Count - lightIndex;
|
||||
var batchedLights = 0;
|
||||
|
||||
// Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
|
||||
var shadowLightCount = 0;
|
||||
while (batchedLights < remainingLights && shadowLightCount < maxShadowTextureCount)
|
||||
{
|
||||
var light = lights[lightIndex + batchedLights];
|
||||
if (light.volumetricShadowsEnabled && light.shadowVolumeIntensity > 0)
|
||||
{
|
||||
ShadowRendering.CreateShadowRenderTexture(pass, renderingData, cmd, shadowLightCount);
|
||||
ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowVolumeIntensity);
|
||||
shadowLightCount++;
|
||||
}
|
||||
batchedLights++;
|
||||
}
|
||||
|
||||
// Set the current RT to the light RT
|
||||
if (shadowLightCount > 0 || requiresRTInit)
|
||||
{
|
||||
cmd.SetRenderTarget(renderTexture, depthTexture);
|
||||
requiresRTInit = false;
|
||||
}
|
||||
|
||||
// Render all the lights.
|
||||
shadowLightCount = 0;
|
||||
for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
|
||||
{
|
||||
var light = lights[(int)(lightIndex + lightIndexOffset)];
|
||||
|
||||
if (light.lightType == Light2D.LightType.Global)
|
||||
continue;
|
||||
|
||||
if (light.volumeIntensity <= 0.0f || !light.volumeIntensityEnabled)
|
||||
continue;
|
||||
|
||||
var topMostLayerValue = light.GetTopMostLitLayer();
|
||||
if (endLayerValue == topMostLayerValue) // this implies the layer is correct
|
||||
{
|
||||
var lightVolumeMaterial = pass.rendererData.GetLightMaterial(light, true);
|
||||
var lightMesh = light.lightMesh;
|
||||
|
||||
// Set the shadow texture to read from
|
||||
if (light.volumetricShadowsEnabled && light.shadowVolumeIntensity > 0)
|
||||
ShadowRendering.SetGlobalShadowTexture(cmd, light, shadowLightCount++);
|
||||
else
|
||||
ShadowRendering.DisableGlobalShadowTexture(cmd);
|
||||
|
||||
if (light.lightType == Light2D.LightType.Sprite && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
|
||||
cmd.SetGlobalTexture(k_CookieTexID, light.lightCookieSprite.texture);
|
||||
|
||||
SetGeneralLightShaderGlobals(pass, cmd, light);
|
||||
|
||||
// Is this needed
|
||||
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
|
||||
SetPointLightShaderGlobals(pass, cmd, light);
|
||||
|
||||
// Could be combined...
|
||||
if (light.lightType == Light2D.LightType.Parametric || light.lightType == Light2D.LightType.Freeform || light.lightType == Light2D.LightType.Sprite)
|
||||
{
|
||||
cmd.DrawMesh(lightMesh, light.transform.localToWorldMatrix, lightVolumeMaterial);
|
||||
}
|
||||
else if (light.lightType == Light2D.LightType.Point)
|
||||
{
|
||||
DrawPointLight(cmd, light, lightMesh, lightVolumeMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Release all of the temporary shadow textures
|
||||
for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
|
||||
ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
|
||||
|
||||
lightIndex += batchedLights;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetShapeLightShaderGlobals(this IRenderPass2D pass, CommandBuffer cmd)
|
||||
{
|
||||
for (var i = 0; i < pass.rendererData.lightBlendStyles.Length; i++)
|
||||
{
|
||||
var blendStyle = pass.rendererData.lightBlendStyles[i];
|
||||
if (i >= k_BlendFactorsPropIDs.Length)
|
||||
break;
|
||||
|
||||
cmd.SetGlobalVector(k_BlendFactorsPropIDs[i], blendStyle.blendFactors);
|
||||
cmd.SetGlobalVector(k_MaskFilterPropIDs[i], blendStyle.maskTextureChannelFilter.mask);
|
||||
cmd.SetGlobalVector(k_InvertedFilterPropIDs[i], blendStyle.maskTextureChannelFilter.inverted);
|
||||
}
|
||||
|
||||
cmd.SetGlobalTexture(k_FalloffLookupID, pass.rendererData.fallOffLookup);
|
||||
}
|
||||
|
||||
private static float GetNormalizedInnerRadius(Light2D light)
|
||||
{
|
||||
return light.pointLightInnerRadius / light.pointLightOuterRadius;
|
||||
}
|
||||
|
||||
private static float GetNormalizedAngle(float angle)
|
||||
{
|
||||
return (angle / 360.0f);
|
||||
}
|
||||
|
||||
private static void GetScaledLightInvMatrix(Light2D light, out Matrix4x4 retMatrix)
|
||||
{
|
||||
var outerRadius = light.pointLightOuterRadius;
|
||||
var lightScale = Vector3.one;
|
||||
var outerRadiusScale = new Vector3(lightScale.x * outerRadius, lightScale.y * outerRadius, lightScale.z * outerRadius);
|
||||
|
||||
var transform = light.transform;
|
||||
|
||||
var scaledLightMat = Matrix4x4.TRS(transform.position, transform.rotation, outerRadiusScale);
|
||||
retMatrix = Matrix4x4.Inverse(scaledLightMat);
|
||||
}
|
||||
|
||||
private static void SetGeneralLightShaderGlobals(IRenderPass2D pass, CommandBuffer cmd, Light2D light)
|
||||
{
|
||||
float intensity = light.intensity * light.color.a;
|
||||
Color color = intensity * light.color;
|
||||
color.a = 1.0f;
|
||||
|
||||
float volumeIntensity = light.volumeIntensity;
|
||||
|
||||
cmd.SetGlobalFloat(k_FalloffIntensityID, light.falloffIntensity);
|
||||
cmd.SetGlobalFloat(k_FalloffDistanceID, light.shapeLightFalloffSize);
|
||||
cmd.SetGlobalColor(k_LightColorID, color);
|
||||
cmd.SetGlobalFloat(k_VolumeOpacityID, volumeIntensity);
|
||||
}
|
||||
|
||||
private static void SetPointLightShaderGlobals(IRenderPass2D pass, CommandBuffer cmd, Light2D light)
|
||||
{
|
||||
// This is used for the lookup texture
|
||||
GetScaledLightInvMatrix(light, out var lightInverseMatrix);
|
||||
|
||||
var innerRadius = GetNormalizedInnerRadius(light);
|
||||
var innerAngle = GetNormalizedAngle(light.pointLightInnerAngle);
|
||||
var outerAngle = GetNormalizedAngle(light.pointLightOuterAngle);
|
||||
var innerRadiusMult = 1 / (1 - innerRadius);
|
||||
|
||||
cmd.SetGlobalVector(k_LightPositionID, light.transform.position);
|
||||
cmd.SetGlobalMatrix(k_LightInvMatrixID, lightInverseMatrix);
|
||||
cmd.SetGlobalFloat(k_InnerRadiusMultID, innerRadiusMult);
|
||||
cmd.SetGlobalFloat(k_OuterAngleID, outerAngle);
|
||||
cmd.SetGlobalFloat(k_InnerAngleMultID, 1 / (outerAngle - innerAngle));
|
||||
cmd.SetGlobalTexture(k_LightLookupID, Light2DLookupTexture.GetLightLookupTexture());
|
||||
cmd.SetGlobalTexture(k_FalloffLookupID, pass.rendererData.fallOffLookup);
|
||||
cmd.SetGlobalFloat(k_FalloffIntensityID, light.falloffIntensity);
|
||||
cmd.SetGlobalFloat(k_IsFullSpotlightID, innerAngle == 1 ? 1.0f : 0.0f);
|
||||
|
||||
cmd.SetGlobalFloat(k_LightZDistanceID, light.normalMapDistance);
|
||||
|
||||
if (light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
|
||||
cmd.SetGlobalTexture(k_PointLightCookieTexID, light.lightCookieSprite.texture);
|
||||
}
|
||||
|
||||
public static void ClearDirtyLighting(this IRenderPass2D pass, CommandBuffer cmd, uint blendStylesUsed)
|
||||
{
|
||||
for (var i = 0; i < pass.rendererData.lightBlendStyles.Length; ++i)
|
||||
{
|
||||
if ((blendStylesUsed & (uint)(1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
if (!pass.rendererData.lightBlendStyles[i].isDirty)
|
||||
continue;
|
||||
|
||||
cmd.SetRenderTarget(pass.rendererData.lightBlendStyles[i].renderTargetHandle.Identifier());
|
||||
cmd.ClearRenderTarget(false, true, Color.black);
|
||||
pass.rendererData.lightBlendStyles[i].isDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RenderNormals(this IRenderPass2D pass, ScriptableRenderContext context, RenderingData renderingData, DrawingSettings drawSettings, FilteringSettings filterSettings, RenderTargetIdentifier depthTarget, CommandBuffer cmd, LightStats lightStats)
|
||||
{
|
||||
using (new ProfilingScope(cmd, m_ProfilingSampler))
|
||||
{
|
||||
// figure out the scale
|
||||
var normalRTScale = 0.0f;
|
||||
|
||||
if (depthTarget != BuiltinRenderTextureType.None)
|
||||
normalRTScale = 1.0f;
|
||||
else
|
||||
normalRTScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
|
||||
|
||||
pass.CreateNormalMapRenderTexture(renderingData, cmd, normalRTScale);
|
||||
|
||||
if (depthTarget != BuiltinRenderTextureType.None)
|
||||
{
|
||||
cmd.SetRenderTarget(
|
||||
pass.rendererData.normalsRenderTarget.Identifier(),
|
||||
RenderBufferLoadAction.DontCare,
|
||||
RenderBufferStoreAction.Store,
|
||||
depthTarget,
|
||||
RenderBufferLoadAction.Load,
|
||||
RenderBufferStoreAction.DontCare);
|
||||
}
|
||||
else
|
||||
cmd.SetRenderTarget(pass.rendererData.normalsRenderTarget.Identifier(), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
|
||||
|
||||
cmd.ClearRenderTarget(true, true, k_NormalClearColor);
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
cmd.Clear();
|
||||
|
||||
drawSettings.SetShaderPassName(0, k_NormalsRenderingPassName);
|
||||
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RenderLights(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, int layerToRender, ref LayerBatch layerBatch, ref RenderTextureDescriptor rtDesc)
|
||||
{
|
||||
var blendStyles = pass.rendererData.lightBlendStyles;
|
||||
|
||||
for (var i = 0; i < blendStyles.Length; ++i)
|
||||
{
|
||||
if ((layerBatch.lightStats.blendStylesUsed & (uint)(1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
var sampleName = blendStyles[i].name;
|
||||
cmd.BeginSample(sampleName);
|
||||
|
||||
if (!Light2DManager.GetGlobalColor(layerToRender, i, out var clearColor))
|
||||
clearColor = Color.black;
|
||||
|
||||
var anyLights = (layerBatch.lightStats.blendStylesWithLights & (uint)(1 << i)) != 0;
|
||||
|
||||
var desc = rtDesc;
|
||||
if (!anyLights) // No lights -- create tiny texture
|
||||
desc.width = desc.height = 4;
|
||||
var identifier = layerBatch.GetRTId(cmd, desc, i);
|
||||
|
||||
cmd.SetRenderTarget(identifier,
|
||||
RenderBufferLoadAction.DontCare,
|
||||
RenderBufferStoreAction.Store,
|
||||
RenderBufferLoadAction.DontCare,
|
||||
RenderBufferStoreAction.DontCare);
|
||||
cmd.ClearRenderTarget(false, true, clearColor);
|
||||
|
||||
if (anyLights)
|
||||
{
|
||||
RenderLightSet(
|
||||
pass, renderingData,
|
||||
i,
|
||||
cmd,
|
||||
layerToRender,
|
||||
identifier,
|
||||
pass.rendererData.lightCullResult.visibleLights
|
||||
);
|
||||
}
|
||||
|
||||
cmd.EndSample(sampleName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetBlendModes(Material material, BlendMode src, BlendMode dst)
|
||||
{
|
||||
material.SetFloat(k_SrcBlendID, (float)src);
|
||||
material.SetFloat(k_DstBlendID, (float)dst);
|
||||
}
|
||||
|
||||
private static uint GetLightMaterialIndex(Light2D light, bool isVolume)
|
||||
{
|
||||
var isPoint = light.isPointLight;
|
||||
var bitIndex = 0;
|
||||
var volumeBit = isVolume ? 1u << bitIndex : 0u;
|
||||
bitIndex++;
|
||||
var shapeBit = !isPoint ? 1u << bitIndex : 0u;
|
||||
bitIndex++;
|
||||
var additiveBit = light.overlapOperation == Light2D.OverlapOperation.AlphaBlend ? 0u : 1u << bitIndex;
|
||||
bitIndex++;
|
||||
var spriteBit = light.lightType == Light2D.LightType.Sprite ? 1u << bitIndex : 0u;
|
||||
bitIndex++;
|
||||
var pointCookieBit = (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null) ? 1u << bitIndex : 0u;
|
||||
bitIndex++;
|
||||
var pointFastQualityBit = (isPoint && light.normalMapQuality == Light2D.NormalMapQuality.Fast) ? 1u << bitIndex : 0u;
|
||||
bitIndex++;
|
||||
var useNormalMap = light.normalMapQuality != Light2D.NormalMapQuality.Disabled ? 1u << bitIndex : 0u;
|
||||
|
||||
return pointFastQualityBit | pointCookieBit | spriteBit | additiveBit | shapeBit | volumeBit | useNormalMap;
|
||||
}
|
||||
|
||||
private static Material CreateLightMaterial(Renderer2DData rendererData, Light2D light, bool isVolume)
|
||||
{
|
||||
var isPoint = light.isPointLight;
|
||||
Material material;
|
||||
|
||||
if (isVolume)
|
||||
material = CoreUtils.CreateEngineMaterial(isPoint ? rendererData.pointLightVolumeShader : rendererData.shapeLightVolumeShader);
|
||||
else
|
||||
{
|
||||
material = CoreUtils.CreateEngineMaterial(isPoint ? rendererData.pointLightShader : rendererData.shapeLightShader);
|
||||
|
||||
if (light.overlapOperation == Light2D.OverlapOperation.Additive)
|
||||
{
|
||||
SetBlendModes(material, BlendMode.One, BlendMode.One);
|
||||
material.EnableKeyword(k_UseAdditiveBlendingKeyword);
|
||||
}
|
||||
else
|
||||
SetBlendModes(material, BlendMode.SrcAlpha, BlendMode.OneMinusSrcAlpha);
|
||||
}
|
||||
|
||||
if (light.lightType == Light2D.LightType.Sprite)
|
||||
material.EnableKeyword(k_SpriteLightKeyword);
|
||||
|
||||
if (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
|
||||
material.EnableKeyword(k_UsePointLightCookiesKeyword);
|
||||
|
||||
if (isPoint && light.normalMapQuality == Light2D.NormalMapQuality.Fast)
|
||||
material.EnableKeyword(k_LightQualityFastKeyword);
|
||||
|
||||
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled)
|
||||
material.EnableKeyword(k_UseNormalMap);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
private static Material GetLightMaterial(this Renderer2DData rendererData, Light2D light, bool isVolume)
|
||||
{
|
||||
var materialIndex = GetLightMaterialIndex(light, isVolume);
|
||||
|
||||
if (!rendererData.lightMaterials.TryGetValue(materialIndex, out var material))
|
||||
{
|
||||
material = CreateLightMaterial(rendererData, light, isVolume);
|
||||
rendererData.lightMaterials[materialIndex] = material;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user