public void InitializeLightData(List <VisibleLight> visibleLights, out LightData lightData, Camera currentCamera) { int visibleLightsCount = Math.Min(visibleLights.Count, m_Asset.MaxPixelLights); m_SortedLightIndexMap.Clear(); lightData.shadowMapSampleType = LightShadows.None; if (visibleLightsCount <= 1) { lightData.mainLightIndex = GetMainLight(visibleLights); } else { lightData.mainLightIndex = SortLights(visibleLights, currentCamera); } // If we have a main light we don't shade it in the per-object light loop. We also remove it from the per-object cull list int mainLightPresent = (lightData.mainLightIndex >= 0) ? 1 : 0; int additionalPixelLightsCount = visibleLightsCount - mainLightPresent; int vertexLightCount = (m_Asset.SupportsVertexLight) ? Math.Min(visibleLights.Count, kMaxPerObjectLights) - additionalPixelLightsCount - mainLightPresent : 0; vertexLightCount = Math.Min(vertexLightCount, kMaxVertexLights); lightData.pixelAdditionalLightsCount = additionalPixelLightsCount; lightData.totalAdditionalLightsCount = additionalPixelLightsCount + vertexLightCount; m_MixedLightingSetup = MixedLightingSetup.None; }
void InitializeLightConstants(NativeArray <VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightAttenuation, out Vector4 lightSpotDir, out Vector4 lightOcclusionProbeChannel) { UniversalRenderPipeline.InitializeLightConstants_Common(lights, lightIndex, out lightPos, out lightColor, out lightAttenuation, out lightSpotDir, out lightOcclusionProbeChannel); // 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; } VisibleLight lightData = lights[lightIndex]; Light light = lightData.light; if (light == null) { return; } if (light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightData.light.shadows != LightShadows.None && m_MixedLightingSetup == MixedLightingSetup.None) { switch (light.bakingOutput.mixedLightingMode) { case MixedLightingMode.Subtractive: m_MixedLightingSetup = MixedLightingSetup.Subtractive; break; case MixedLightingMode.Shadowmask: m_MixedLightingSetup = MixedLightingSetup.ShadowMask; break; } } }
void SetupShaderLightConstants(CommandBuffer cmd, ref RenderingData renderingData) { 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 renderingData.lightData); SetupAdditionalLightConstants(cmd, ref renderingData); }
void SetupShaderLightConstants(CommandBuffer cmd, ref LightData lightData) { // Clear to default all light constant data for (int i = 0; i < LightweightRenderPipeline.maxVisibleAdditionalLights; ++i) { InitializeLightConstants(lightData.visibleLights, -1, out m_AdditionalLightPositions[i], out m_AdditionalLightColors[i], out m_AdditionalLightAttenuations[i], out m_AdditionalLightSpotDirections[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. // Lightweight 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 InitializeLightConstants(List <VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, out Vector4 lightSpotAttenuation) { lightPos = k_DefaultLightPosition; lightColor = k_DefaultLightColor; lightDistanceAttenuation = k_DefaultLightSpotAttenuation; lightSpotDir = k_DefaultLightSpotDirection; lightSpotAttenuation = k_DefaultLightAttenuation; // 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; } VisibleLight lightData = lights[lightIndex]; if (lightData.lightType == LightType.Directional) { Vector4 dir = -lightData.localToWorld.GetColumn(2); lightPos = new Vector4(dir.x, dir.y, dir.z, 0.0f); } else { Vector4 pos = lightData.localToWorld.GetColumn(3); lightPos = new Vector4(pos.x, pos.y, pos.z, 1.0f); } // VisibleLight.finalColor already returns color in active color space lightColor = lightData.finalColor; // Directional Light attenuation is initialize so distance attenuation always be 1.0 if (lightData.lightType != LightType.Directional) { // Light attenuation in lightweight matches the unity vanilla one. // attenuation = 1.0 / 1.0 + distanceToLightSqr * quadraticAttenuation // then a smooth factor is applied to linearly fade attenuation to light range // the attenuation smooth factor starts having effect at 80% of light range // smoothFactor = (lightRangeSqr - distanceToLightSqr) / (lightRangeSqr - fadeStartDistanceSqr) // We rewrite smoothFactor to be able to pre compute the constant terms below and apply the smooth factor // with one MAD instruction // smoothFactor = distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) // distanceSqr * oneOverFadeRangeSqr + lightRangeSqrOverFadeRangeSqr float lightRangeSqr = lightData.range * lightData.range; float fadeStartDistanceSqr = 0.8f * 0.8f * lightRangeSqr; float fadeRangeSqr = (fadeStartDistanceSqr - lightRangeSqr); float oneOverFadeRangeSqr = 1.0f / fadeRangeSqr; float lightRangeSqrOverFadeRangeSqr = -lightRangeSqr / fadeRangeSqr; float quadAtten = 25.0f / lightRangeSqr; lightDistanceAttenuation = new Vector4(quadAtten, oneOverFadeRangeSqr, lightRangeSqrOverFadeRangeSqr, 1.0f); } if (lightData.lightType == LightType.Spot) { Vector4 dir = lightData.localToWorld.GetColumn(2); lightSpotDir = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f); // Spot Attenuation with a linear falloff can be defined as // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) // This can be rewritten as // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) // If we precompute the terms in a MAD instruction float cosOuterAngle = Mathf.Cos(Mathf.Deg2Rad * lightData.spotAngle * 0.5f); // We neeed to do a null check for particle lights // This should be changed in the future // Particle lights will use an inline function float cosInnerAngle; if (lightData.light != null) { cosInnerAngle = Mathf.Cos(LightmapperUtils.ExtractInnerCone(lightData.light) * 0.5f); } else { cosInnerAngle = Mathf.Cos((2.0f * Mathf.Atan(Mathf.Tan(lightData.spotAngle * 0.5f * Mathf.Deg2Rad) * (64.0f - 18.0f) / 64.0f)) * 0.5f); } float smoothAngleRange = Mathf.Max(0.001f, cosInnerAngle - cosOuterAngle); float invAngleRange = 1.0f / smoothAngleRange; float add = -cosOuterAngle * invAngleRange; lightSpotAttenuation = new Vector4(invAngleRange, add, 0.0f); } Light light = lightData.light; // TODO: Add support to shadow mask if (light != null && light.bakingOutput.mixedLightingMode == MixedLightingMode.Subtractive && light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed) { if (m_MixedLightingSetup == MixedLightingSetup.None && lightData.light.shadows != LightShadows.None) { m_MixedLightingSetup = MixedLightingSetup.Subtractive; lightDistanceAttenuation.w = 0.0f; } } }
void InitializeLightConstants(NativeArray <VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightAttenuation, out Vector4 lightSpotDir, out Vector4 lightOcclusionProbeChannel) { lightPos = k_DefaultLightPosition; lightColor = k_DefaultLightColor; lightAttenuation = k_DefaultLightAttenuation; lightSpotDir = k_DefaultLightSpotDirection; lightOcclusionProbeChannel = k_DefaultLightsProbeChannel; // 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; } VisibleLight lightData = lights[lightIndex]; if (lightData.lightType == LightType.Directional) { Vector4 dir = -lightData.localToWorldMatrix.GetColumn(2); lightPos = new Vector4(dir.x, dir.y, dir.z, 0.0f); } else { Vector4 pos = lightData.localToWorldMatrix.GetColumn(3); lightPos = new Vector4(pos.x, pos.y, pos.z, 1.0f); } // VisibleLight.finalColor already returns color in active color space lightColor = lightData.finalColor; // Directional Light attenuation is initialize so distance attenuation always be 1.0 if (lightData.lightType != LightType.Directional) { // Light attenuation in universal matches the unity vanilla one. // attenuation = 1.0 / distanceToLightSqr // We offer two different smoothing factors. // The smoothing factors make sure that the light intensity is zero at the light range limit. // The first smoothing factor is a linear fade starting at 80 % of the light range. // smoothFactor = (lightRangeSqr - distanceToLightSqr) / (lightRangeSqr - fadeStartDistanceSqr) // We rewrite smoothFactor to be able to pre compute the constant terms below and apply the smooth factor // with one MAD instruction // smoothFactor = distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) // distanceSqr * oneOverFadeRangeSqr + lightRangeSqrOverFadeRangeSqr // The other smoothing factor matches the one used in the Unity lightmapper but is slower than the linear one. // smoothFactor = (1.0 - saturate((distanceSqr * 1.0 / lightrangeSqr)^2))^2 float lightRangeSqr = lightData.range * lightData.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, lightData.range * lightData.range); // On mobile and Nintendo Switch: Use the faster linear smoothing factor (SHADER_HINT_NICE_QUALITY). // On other devices: Use the smoothing factor that matches the GI. lightAttenuation.x = Application.isMobilePlatform || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Switch ? oneOverFadeRangeSqr : oneOverLightRangeSqr; lightAttenuation.y = lightRangeSqrOverFadeRangeSqr; } if (lightData.lightType == LightType.Spot) { Vector4 dir = lightData.localToWorldMatrix.GetColumn(2); lightSpotDir = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f); // Spot Attenuation with a linear falloff can be defined as // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) // This can be rewritten as // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) // If we precompute the terms in a MAD instruction float cosOuterAngle = Mathf.Cos(Mathf.Deg2Rad * lightData.spotAngle * 0.5f); // We neeed to do a null check for particle lights // This should be changed in the future // Particle lights will use an inline function float cosInnerAngle; if (lightData.light != null) { cosInnerAngle = Mathf.Cos(lightData.light.innerSpotAngle * Mathf.Deg2Rad * 0.5f); } else { cosInnerAngle = Mathf.Cos((2.0f * Mathf.Atan(Mathf.Tan(lightData.spotAngle * 0.5f * Mathf.Deg2Rad) * (64.0f - 18.0f) / 64.0f)) * 0.5f); } float smoothAngleRange = Mathf.Max(0.001f, cosInnerAngle - cosOuterAngle); float invAngleRange = 1.0f / smoothAngleRange; float add = -cosOuterAngle * invAngleRange; lightAttenuation.z = invAngleRange; lightAttenuation.w = add; } Light light = lightData.light; // Set the occlusion probe channel. int occlusionProbeChannel = light != null ? light.bakingOutput.occlusionMaskChannel : -1; // If we have baked the light, the occlusion channel is the index we need to sample in 'unity_ProbesOcclusion' // If we have not baked the light, the occlusion channel is -1. // In case there is no occlusion channel is -1, we set it to zero, and then set the second value in the // input to one. We then, in the shader max with the second value for non-occluded lights. lightOcclusionProbeChannel.x = occlusionProbeChannel == -1 ? 0f : occlusionProbeChannel; lightOcclusionProbeChannel.y = occlusionProbeChannel == -1 ? 1f : 0f; // TODO: Add support to shadow mask if (light != null && light.bakingOutput.mixedLightingMode == MixedLightingMode.Subtractive && light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed) { if (lightData.light.shadows != LightShadows.None) { m_MixedLightingSetup = MixedLightingSetup.Subtractive; } } if (light != null && light.bakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask && light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed) { if (lightData.light.shadows != LightShadows.None) { m_MixedLightingSetup = MixedLightingSetup.ShadowMask; } int channel = light.bakingOutput.occlusionMaskChannel; lightSpotDir.w = channel + 1; } }
void InitializeLightConstants(List <VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightAttenuation, out Vector4 lightSpotDir) { lightPos = k_DefaultLightPosition; lightColor = k_DefaultLightColor; lightAttenuation = k_DefaultLightAttenuation; lightSpotDir = k_DefaultLightSpotDirection; // 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; } VisibleLight lightData = lights[lightIndex]; if (lightData.lightType == LightType.Directional) { Vector4 dir = -lightData.localToWorld.GetColumn(2); lightPos = new Vector4(dir.x, dir.y, dir.z, k_DefaultLightAttenuation.w); } else { Vector4 pos = lightData.localToWorld.GetColumn(3); lightPos = new Vector4(pos.x, pos.y, pos.z, k_DefaultLightAttenuation.w); } // VisibleLight.finalColor already returns color in active color space lightColor = lightData.finalColor; // Directional Light attenuation is initialize so distance attenuation always be 1.0 if (lightData.lightType != LightType.Directional) { // Light attenuation in lightweight matches the unity vanilla one. // attenuation = 1.0 / distanceToLightSqr // We offer two different smoothing factors. // The smoothing factors make sure that the light intensity is zero at the light range limit. // The first smoothing factor is a linear fade starting at 80 % of the light range. // smoothFactor = (lightRangeSqr - distanceToLightSqr) / (lightRangeSqr - fadeStartDistanceSqr) // We rewrite smoothFactor to be able to pre compute the constant terms below and apply the smooth factor // with one MAD instruction // smoothFactor = distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) // distanceSqr * oneOverFadeRangeSqr + lightRangeSqrOverFadeRangeSqr // The other smoothing factor matches the one used in the Unity lightmapper but is slower than the linear one. // smoothFactor = (1.0 - saturate((distanceSqr * 1.0 / lightrangeSqr)^2))^2 float lightRangeSqr = lightData.range * lightData.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, lightData.range * lightData.range); // On mobile: Use the faster linear smoothing factor. // On other devices: Use the smoothing factor that matches the GI. lightAttenuation.x = Application.isMobilePlatform ? oneOverFadeRangeSqr : oneOverLightRangeSqr; lightAttenuation.y = lightRangeSqrOverFadeRangeSqr; } if (lightData.lightType == LightType.Spot) { Vector4 dir = lightData.localToWorld.GetColumn(2); lightSpotDir = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f); // Spot Attenuation with a linear falloff can be defined as // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) // This can be rewritten as // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) // If we precompute the terms in a MAD instruction float cosOuterAngle = Mathf.Cos(Mathf.Deg2Rad * lightData.spotAngle * 0.5f); // We neeed to do a null check for particle lights // This should be changed in the future // Particle lights will use an inline function float cosInnerAngle; if (lightData.light != null) { cosInnerAngle = Mathf.Cos(LightmapperUtils.ExtractInnerCone(lightData.light) * 0.5f); } else { cosInnerAngle = Mathf.Cos((2.0f * Mathf.Atan(Mathf.Tan(lightData.spotAngle * 0.5f * Mathf.Deg2Rad) * (64.0f - 18.0f) / 64.0f)) * 0.5f); } float smoothAngleRange = Mathf.Max(0.001f, cosInnerAngle - cosOuterAngle); float invAngleRange = 1.0f / smoothAngleRange; float add = -cosOuterAngle * invAngleRange; lightAttenuation.z = invAngleRange; lightAttenuation.w = add; } Light light = lightData.light; // TODO: Add support to shadow mask if (light != null && light.bakingOutput.mixedLightingMode == MixedLightingMode.Subtractive && light.bakingOutput.lightmapBakeType == LightmapBakeType.Mixed) { if (m_MixedLightingSetup == MixedLightingSetup.None && lightData.light.shadows != LightShadows.None) { m_MixedLightingSetup = MixedLightingSetup.Subtractive; // In subtractive light mode, main light direct contribution is baked on lightmap // In this case we setup light position w component as 0.0f so we can remove it's contribution // from realtime light computation if (lightData.lightType == LightType.Directional) { lightPos.w = 0.0f; } } } }