void SetupMainLightConstants(CommandBuffer cmd, ref LightData lightData) { Vector4 lightPos, lightColor, lightAttenuation, lightSpotDir, lightOcclusionChannel; InitializeLightConstants(lightData.visibleLights, lightData.mainLightIndex, out lightPos, out lightColor, out lightAttenuation, out lightSpotDir, out lightOcclusionChannel); cmd.SetGlobalVector(LightConstantBuffer._MainLightPosition, lightPos); cmd.SetGlobalVector(LightConstantBuffer._MainLightColor, lightColor); }
bool IsValidShadowCastingLight(ref LightData lightData, int i) { if (i == lightData.mainLightIndex) { return(false); } VisibleLight shadowLight = lightData.visibleLights[i]; // Point light shadows are not supported if (shadowLight.lightType == LightType.Point) { return(false); } Light light = shadowLight.light; return(light != null && light.shadows != LightShadows.None && !Mathf.Approximately(light.shadowStrength, 0.0f)); }
void SetupPerObjectLightIndices(CullingResults cullResults, ref LightData lightData) { if (lightData.additionalLightsCount == 0) { return; } var visibleLights = lightData.visibleLights; var perObjectLightIndexMap = cullResults.GetLightIndexMap(Allocator.Temp); int directionalLightsCount = 0; int additionalLightsCount = 0; // Disable all directional lights from the perobject light indices // Pipeline handles them globally. for (int i = 0; i < visibleLights.Length; ++i) { if (additionalLightsCount >= UniversalRenderPipeline.maxVisibleAdditionalLights) { break; } VisibleLight light = visibleLights[i]; if (light.lightType == LightType.Directional) { perObjectLightIndexMap[i] = -1; ++directionalLightsCount; } else { perObjectLightIndexMap[i] -= directionalLightsCount; ++additionalLightsCount; } } // Disable all remaining lights we cannot fit into the global light buffer. for (int i = directionalLightsCount + additionalLightsCount; i < visibleLights.Length; ++i) { perObjectLightIndexMap[i] = -1; } cullResults.SetLightIndexMap(perObjectLightIndexMap); perObjectLightIndexMap.Dispose(); }
void SetupShaderLightConstants(CommandBuffer cmd, ref LightData lightData) { // Clear to default all light constant data for (int i = 0; i < UniversalRenderPipeline.maxVisibleAdditionalLights; ++i) { InitializeLightConstants(lightData.visibleLights, -1, out m_AdditionalLightPositions[i], out m_AdditionalLightColors[i], out m_AdditionalLightAttenuations[i], out m_AdditionalLightSpotDirections[i], out m_AdditionalLightOcclusionProbeChannels[i]); } 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, ref lightData); SetupAdditionalLightConstants(cmd, ref lightData); }
void SetupAdditionalLightConstants(CommandBuffer cmd, ref LightData lightData) { int maxVisibleAdditionalLights = UniversalRenderPipeline.maxVisibleAdditionalLights; var lights = lightData.visibleLights; if (lightData.additionalLightsCount > 0) { int additionalLightsCount = 0; for (int i = 0; i < lights.Length && additionalLightsCount < maxVisibleAdditionalLights; ++i) { VisibleLight light = lights[i]; if (light.lightType != LightType.Directional) { InitializeLightConstants(lights, i, out m_AdditionalLightPositions[additionalLightsCount], out m_AdditionalLightColors[additionalLightsCount], out m_AdditionalLightAttenuations[additionalLightsCount], out m_AdditionalLightSpotDirections[additionalLightsCount], out m_AdditionalLightOcclusionProbeChannels[additionalLightsCount]); additionalLightsCount++; } } cmd.SetGlobalVector(LightConstantBuffer._AdditionalLightsCount, new Vector4(lightData.maxPerObjectAdditionalLightsCount, 0.0f, 0.0f, 0.0f)); } else { cmd.SetGlobalVector(LightConstantBuffer._AdditionalLightsCount, Vector4.zero); } 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); }
private void SetupLightDatas(ref UnityEngine.Rendering.Universal.LightData lightData) { //populate the buffer with le list of lights var lights = lightData.visibleLights; int index = 0; uint destLightCount = 0; Vector4 lightAttenuation; for (int i = 0; i < lights.Length; ++i) { VisibleLight light = lights[i]; Vector4 pos = light.localToWorldMatrix.GetColumn(3); if (lightData.mainLightIndex != i) { Vector3 col = new Vector3( light.finalColor.r, light.finalColor.g, light.finalColor.b); SetupLightAttenuation(ref light, out lightAttenuation); //calculate light attenuation float lightRangeSqr = light.range * light.range; float fadeStartDistanceSqr = 0.8f * 0.8f * lightRangeSqr; float fadeRangeSqr = (fadeStartDistanceSqr - lightRangeSqr); float oneOverFadeRangeSqr = 1.0f / fadeRangeSqr; float lightRangeSqrOverFadeRangeSqr = -lightRangeSqr / fadeRangeSqr; float oneOverLightRangeSqr = 1.0f / Mathf.Max(0.0001f, lightRangeSqr); lightAttenuation.x = Application.isMobilePlatform || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Switch ? oneOverFadeRangeSqr : oneOverLightRangeSqr; lightAttenuation.y = lightRangeSqrOverFadeRangeSqr; m_lightsDatas[index++] = new LightData( pos, 1, col, light.range, lightAttenuation); ++destLightCount; if (index >= mc_maxLightCount) { break; } } else { Shader.SetGlobalVector("_MainLightColor", light.finalColor); Shader.SetGlobalVector("_MainLightPosition", pos.normalized); } } if (destLightCount != ms_currentLightCount) { //清空index~ms_currentLightCount if (ms_currentLightCount > destLightCount) { for (int i = index; i < ms_currentLightCount; ++i) { m_lightsDatas[i] = new LightData( Vector3.zero, 0.0f, Vector3.zero, 0.0f, mc_defaultLightAttenuation); } } ms_currentLightCount = destLightCount; } m_lightListBuffer.SetData(m_lightsDatas); }
void RenderAdditionalShadowmapAtlas(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { NativeArray <VisibleLight> visibleLights = lightData.visibleLights; bool additionalLightHasSoftShadows = false; CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag); using (new ProfilingSample(cmd, m_ProfilerTag)) { bool anyShadowSliceRenderer = false; int shadowSlicesCount = m_AdditionalShadowCastingLightIndices.Count; for (int i = 0; i < shadowSlicesCount; ++i) { // we do the shadow strength check here again here because when using // the uniform array path we might have zero strength shadow lights. // In that case we need the shadow data buffer but we can skip // rendering them to shadowmap. if (!m_UseStructuredBuffer && Mathf.Approximately(m_AdditionalLightsShadowParams[i].x, 0.0f)) { continue; } // Index of the VisibleLight int shadowLightIndex = m_AdditionalShadowCastingLightIndices[i]; VisibleLight shadowLight = visibleLights[shadowLightIndex]; ShadowSliceData shadowSliceData = m_AdditionalLightSlices[i]; var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, shadowSliceData.projectionMatrix, shadowSliceData.resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); ShadowUtils.RenderShadowSlice(cmd, ref context, ref shadowSliceData, ref settings); additionalLightHasSoftShadows |= shadowLight.light.shadows == LightShadows.Soft; anyShadowSliceRenderer = true; } // We share soft shadow settings for main light and additional lights to save keywords. // So we check here if pipeline supports soft shadows and either main light or any additional light has soft shadows // to enable the keyword. // TODO: In PC and Consoles we can upload shadow data per light and branch on shader. That will be more likely way faster. bool mainLightHasSoftShadows = shadowData.supportsMainLightShadows && lightData.mainLightIndex != -1 && visibleLights[lightData.mainLightIndex].light.shadows == LightShadows.Soft; bool softShadows = shadowData.supportsSoftShadows && (mainLightHasSoftShadows || additionalLightHasSoftShadows); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.AdditionalLightShadows, anyShadowSliceRenderer); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows); if (anyShadowSliceRenderer) { SetupAdditionalLightsShadowReceiverConstants(cmd, ref shadowData, softShadows); } } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
static void InitializeLightData(UniversalRenderPipelineAsset settings, NativeArray <VisibleLight> visibleLights, int mainLightIndex, out LightData lightData) { int maxPerObjectAdditionalLights = UniversalRenderPipeline.maxPerObjectLights; int maxVisibleAdditionalLights = UniversalRenderPipeline.maxVisibleAdditionalLights; lightData.mainLightIndex = mainLightIndex; if (settings.additionalLightsRenderingMode != LightRenderingMode.Disabled) { lightData.additionalLightsCount = Math.Min((mainLightIndex != -1) ? visibleLights.Length - 1 : visibleLights.Length, maxVisibleAdditionalLights); lightData.maxPerObjectAdditionalLightsCount = Math.Min(settings.maxAdditionalLightsCount, maxPerObjectAdditionalLights); } else { lightData.additionalLightsCount = 0; lightData.maxPerObjectAdditionalLightsCount = 0; } lightData.shadeAdditionalLightsPerVertex = settings.additionalLightsRenderingMode == LightRenderingMode.PerVertex; lightData.visibleLights = visibleLights; lightData.supportsMixedLighting = settings.supportsMixedLighting; }
void RenderMainLightCascadeShadowmap(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag); using (new ProfilingSample(cmd, m_ProfilerTag)) { var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { var splitData = settings.splitData; splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex]; settings.splitData = splitData; Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix); } SetupMainLightShadowReceiverConstants(cmd, ref shadowData, shadowLight); } CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, true); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
void RenderAdditionalShadowmapAtlas(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { NativeArray <VisibleLight> visibleLights = lightData.visibleLights; bool additionalLightHasSoftShadows = false; CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag); using (new ProfilingSample(cmd, m_ProfilerTag)) { for (int i = 0; i < m_AdditionalShadowCastingLightIndices.Count; ++i) { int shadowLightIndex = m_AdditionalShadowCastingLightIndices[i]; VisibleLight shadowLight = visibleLights[shadowLightIndex]; if (m_AdditionalShadowCastingLightIndices.Count > 1) { ShadowUtils.ApplySliceTransform(ref m_AdditionalLightSlices[i], m_ShadowmapWidth, m_ShadowmapHeight); } var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_AdditionalLightSlices[i].projectionMatrix, m_AdditionalLightSlices[i].resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_AdditionalLightSlices[i], ref settings, m_AdditionalLightSlices[i].projectionMatrix, m_AdditionalLightSlices[i].viewMatrix); additionalLightHasSoftShadows |= shadowLight.light.shadows == LightShadows.Soft; } SetupAdditionalLightsShadowReceiverConstants(cmd, ref shadowData); } // We share soft shadow settings for main light and additional lights to save keywords. // So we check here if pipeline supports soft shadows and either main light or any additional light has soft shadows // to enable the keyword. // TODO: In PC and Consoles we can upload shadow data per light and branch on shader. That will be more likely way faster. bool mainLightHasSoftShadows = shadowData.supportsMainLightShadows && lightData.mainLightIndex != -1 && visibleLights[lightData.mainLightIndex].light.shadows == LightShadows.Soft; bool softShadows = shadowData.supportsSoftShadows && (mainLightHasSoftShadows || additionalLightHasSoftShadows); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.AdditionalLightShadows, true); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }