public static void RenderLightVolumes(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, int layerToRender, int endLayerValue, RenderTargetIdentifier renderTexture, RenderTargetIdentifier depthTexture, RenderBufferStoreAction intermediateStoreAction, RenderBufferStoreAction finalStoreAction, bool requiresRTInit, List <Light2D> lights) { var maxShadowLightCount = ShadowRendering.maxTextureCount * 4; // Now encodes shadows into RGBA as well as seperate textures NativeArray <bool> doesLightAtIndexHaveShadows = new NativeArray <bool>(lights.Count, Allocator.Temp); // This case should never happen, but if it does it may cause an infinite loop later. if (maxShadowLightCount < 1) { Debug.LogError("maxShadowLightCount cannot be less than 1"); return; } // Determine last light with volumetric shadows to be rendered if we want to use a different store action after using rendering its volumetric shadows int useFinalStoreActionAfter = lights.Count; if (intermediateStoreAction != finalStoreAction) { for (int i = lights.Count - 1; i >= 0; i--) { if (lights[i].renderVolumetricShadows) { useFinalStoreActionAfter = i; break; } } } // 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 < maxShadowLightCount) { int curLightIndex = lightIndex + batchedLights; var light = lights[curLightIndex]; if (CanCastVolumetricShadows(light, endLayerValue)) { doesLightAtIndexHaveShadows[curLightIndex] = false; if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowVolumeIntensity)) { doesLightAtIndexHaveShadows[curLightIndex] = true; shadowLightCount++; } } batchedLights++; } // Set the current RT to the light RT if (shadowLightCount > 0 || requiresRTInit) { var storeAction = lightIndex + batchedLights >= useFinalStoreActionAfter ? finalStoreAction : intermediateStoreAction; cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, storeAction, depthTexture, RenderBufferLoadAction.Load, storeAction); 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 (doesLightAtIndexHaveShadows[lightIndex + lightIndexOffset]) { 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; } doesLightAtIndexHaveShadows.Dispose(); }
private static void RenderLightSet(IRenderPass2D pass, RenderingData renderingData, int blendStyleIndex, CommandBuffer cmd, int layerToRender, RenderTargetIdentifier renderTexture, List <Light2D> lights) { var maxShadowLightCount = ShadowRendering.maxTextureCount * 4; var requiresRTInit = true; // This case should never happen, but if it does it may cause an infinite loop later. if (maxShadowLightCount < 1) { Debug.LogError("maxShadowTextureCount cannot be less than 1"); return; } NativeArray <bool> doesLightAtIndexHaveShadows = new NativeArray <bool>(lights.Count, Allocator.Temp); // 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 int shadowLightCount = 0; while (batchedLights < remainingLights && shadowLightCount < maxShadowLightCount) { int curLightIndex = lightIndex + batchedLights; var light = lights[curLightIndex]; if (CanCastShadows(light, layerToRender)) { doesLightAtIndexHaveShadows[curLightIndex] = false; if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowIntensity)) { doesLightAtIndexHaveShadows[curLightIndex] = true; 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 (doesLightAtIndexHaveShadows[lightIndex + lightIndexOffset]) { 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; } doesLightAtIndexHaveShadows.Dispose(); }
public static void CreateShadowRenderTexture(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int shadowIndex) { CreateShadowRenderTexture(pass, m_RenderTargets[shadowIndex], renderingData, cmdBuffer); }
public static void RenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, float shadowIntensity, RenderTargetIdentifier renderTexture, int colorBit) { using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadows)) { bool hasShadow = false; var shadowCasterGroups = ShadowCasterGroup2DManager.shadowCasterGroups; if (shadowCasterGroups != null && shadowCasterGroups.Count > 0) { // Before doing anything check to see if any of the shadow casters are visible to this light for (var group = 0; group < shadowCasterGroups.Count; group++) { var shadowCasterGroup = shadowCasterGroups[group]; var shadowCasters = shadowCasterGroup.GetShadowCasters(); if (shadowCasters != null) { // Draw the projected shadows for the shadow caster group. Writing into the group stencil buffer bit for (var i = 0; i < shadowCasters.Count; i++) { var shadowCaster = shadowCasters[i]; if (shadowCaster.IsLit(light)) { hasShadow = true; break; } } } } if (hasShadow) { cmdBuffer.SetRenderTarget(renderTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare); if (colorBit == 0) { cmdBuffer.ClearRenderTarget(true, true, Color.clear); // clear stencil } using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadowColorsLookup[colorBit])) { var shadowRadius = light.boundingSphere.radius; cmdBuffer.SetGlobalVector(k_LightPosID, light.transform.position); cmdBuffer.SetGlobalFloat(k_ShadowRadiusID, shadowRadius); cmdBuffer.SetGlobalColor(k_ShadowColorMaskID, k_ColorLookup[colorBit]); var projectedShadowsMaterial = pass.rendererData.GetProjectedShadowMaterial(colorBit); var selfShadowMaterial = pass.rendererData.GetSpriteSelfShadowMaterial(colorBit); var unshadowMaterial = pass.rendererData.GetSpriteUnshadowMaterial(colorBit); var setGlobalStencilMaterial = pass.rendererData.GetStencilOnlyShadowMaterial(colorBit); for (var group = 0; group < shadowCasterGroups.Count; group++) { var shadowCasterGroup = shadowCasterGroups[group]; var shadowCasters = shadowCasterGroup.GetShadowCasters(); if (shadowCasters != null) { // Draw the projected shadows for the shadow caster group. Writing into the group stencil buffer bit for (var i = 0; i < shadowCasters.Count; i++) { var shadowCaster = shadowCasters[i]; if (shadowCaster.IsLit(light)) { if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender)) { if (shadowCaster.castsShadows) { SetShadowProjectionGlobals(cmdBuffer, shadowCaster); cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.transform.localToWorldMatrix, projectedShadowsMaterial, 0, 0); } } } } // Draw the sprites, either as self shadowing or unshadowing for (var i = 0; i < shadowCasters.Count; i++) { var shadowCaster = shadowCasters[i]; if (shadowCaster.IsLit(light)) { if (shadowCaster != null && shadowCaster.IsShadowedLayer(layerToRender)) { if (shadowCaster.useRendererSilhouette) { // Draw using the sprite renderer var renderer = (Renderer)null; shadowCaster.TryGetComponent <Renderer>(out renderer); if (renderer != null) { var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial; if (material != null) { cmdBuffer.DrawRenderer(renderer, material); } } } else { var meshMat = shadowCaster.transform.localToWorldMatrix; var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial; // Draw using the shadow mesh if (material != null) { cmdBuffer.DrawMesh(shadowCaster.mesh, meshMat, material); } } } } } // Draw the projected shadows for the shadow caster group. Writing clearing the group stencil bit, and setting the global bit for (var i = 0; i < shadowCasters.Count; i++) { var shadowCaster = shadowCasters[i]; if (shadowCaster.IsLit(light)) { if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender)) { if (shadowCaster.castsShadows) { SetShadowProjectionGlobals(cmdBuffer, shadowCaster); cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.transform.localToWorldMatrix, projectedShadowsMaterial, 0, 1); } } } } } } } } } } }
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; } }