public void OnEnable( ) { Lightmapping.RequestLightsDelegate testDel = (Light [] requests, Unity.Collections.NativeArray <LightDataGI> lightsOutput) => { DirectionalLight dLight = new DirectionalLight( ); PointLight point = new PointLight( ); SpotLight spot = new SpotLight( ); RectangleLight rect = new RectangleLight( ); LightDataGI ld = new LightDataGI( ); for (int i = 0; i < requests.Length; i++) { Light l = requests [i]; switch (l.type) { case UnityEngine.LightType.Directional: LightmapperUtils.Extract(l, ref dLight); ld.Init(ref dLight); break; case UnityEngine.LightType.Point: LightmapperUtils.Extract(l, ref point); ld.Init(ref point); break; case UnityEngine.LightType.Spot: LightmapperUtils.Extract(l, ref spot); ld.Init(ref spot); break; case UnityEngine.LightType.Area: LightmapperUtils.Extract(l, ref rect); ld.Init(ref rect); break; default: ld.InitNoBake(l.GetInstanceID( )); break; } ld.falloff = FalloffType.InverseSquared; lightsOutput [i] = ld; } }; Lightmapping.SetDelegate(testDel); }
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; } } }
// Return true if the light must be added to the baking public static bool LightDataGIExtract(Light l, ref LightDataGI ld) { var add = l.GetComponent <HDAdditionalLightData>(); if (add == null) { add = HDUtils.s_DefaultHDAdditionalLightData; } // TODO: Only take into account the light dimmer when we have real time GI. ld.instanceID = l.GetInstanceID(); ld.color = add.affectDiffuse ? LinearColor.Convert(l.color, l.intensity) : LinearColor.Black(); ld.indirectColor = add.affectDiffuse ? LightmapperUtils.ExtractIndirect(l) : LinearColor.Black(); // Note that the HDRI is correctly integrated in the GlobalIllumination system, we don't need to do anything regarding it. ld.mode = LightmapperUtils.Extract(l.lightmapBakeType); ld.shadow = (byte)(l.shadows != LightShadows.None ? 1 : 0); if (add.lightTypeExtent == LightTypeExtent.Punctual) { // For HDRP we need to divide the analytic light color by PI (HDRP do explicit PI division for Lambert, but built in Unity and the GI don't for punctual lights) // We apply it on both direct and indirect are they are separated, seems that direct is no used if we used mixed mode with indirect or shadowmask bake. ld.color.intensity /= Mathf.PI; ld.indirectColor.intensity /= Mathf.PI; switch (l.type) { case LightType.Directional: ld.orientation.SetLookRotation(l.transform.forward, Vector3.up); ld.position = Vector3.zero; ld.range = 0.0f; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.shadows != LightShadows.None ? (Mathf.Deg2Rad * l.shadowAngle) : 0.0f; #else ld.shape0 = 0.0f; #endif ld.shape1 = 0.0f; ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Directional; ld.falloff = FalloffType.Undefined; break; case LightType.Spot: ld.orientation = l.transform.rotation; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = l.spotAngle * Mathf.Deg2Rad; // coneAngle is the full angle ld.innerConeAngle = l.spotAngle * Mathf.Deg2Rad * add.GetInnerSpotPercent01(); #if UNITY_EDITOR ld.shape0 = l.shadows != LightShadows.None ? l.shadowRadius : 0.0f; #else ld.shape0 = 0.0f; #endif ld.shape1 = 0.0f; ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Spot; ld.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; /* * switch (add.spotLightShape) * { * case SpotLightShape.Cone: * break; * case SpotLightShape.Pyramid: * break; * case SpotLightShape.Box: * break; * default: * Debug.Assert(false, "Encountered an unknown SpotLightShape."); * break; * } */ break; case LightType.Point: ld.orientation = Quaternion.identity; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.shadows != LightShadows.None ? l.shadowRadius : 0.0f; #else ld.shape0 = 0.0f; #endif ld.shape1 = 0.0f; ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Point; ld.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; break; // Note: We don't support this type in HDRP, but ini just in case case LightType.Area: ld.orientation = l.transform.rotation; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.areaSize.x; ld.shape1 = l.areaSize.y; #else ld.shape0 = 0.0f; ld.shape1 = 0.0f; #endif ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle; ld.falloff = FalloffType.Undefined; break; default: Debug.Assert(false, "Encountered an unknown LightType."); break; } } else if (add.lightTypeExtent == LightTypeExtent.Rectangle) { ld.orientation = l.transform.rotation; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.areaSize.x; ld.shape1 = l.areaSize.y; #else ld.shape0 = 0.0f; ld.shape1 = 0.0f; #endif // TEMP: for now, if we bake a rectangle type this will disable the light for runtime, need to speak with GI team about it! ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle; ld.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; } else if (add.lightTypeExtent == LightTypeExtent.Line) { ld.InitNoBake(ld.instanceID); } else { Debug.Assert(false, "Encountered an unknown LightType."); } return(true); }
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, 1.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: 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.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(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; // 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 (m_MixedLightingSetup == MixedLightingSetup.None && lightData.light.shadows != LightShadows.None) { m_MixedLightingSetup = MixedLightingSetup.Subtractive; } } }
// Return true if the light must be added to the baking public static bool LightDataGIExtract(Light l, ref LightDataGI ld) { var add = l.GetComponent <HDAdditionalLightData>(); if (add == null) { add = HDUtils.s_DefaultHDAdditionalLightData; } // TODO: Currently color temperature is not handled at runtime, need to expose useColorTemperature publicly Color cct = new Color(1.0f, 1.0f, 1.0f); #if UNITY_EDITOR if (add.useColorTemperature) { cct = Mathf.CorrelatedColorTemperatureToRGB(l.colorTemperature); } #endif // TODO: Only take into account the light dimmer when we have real time GI. ld.instanceID = l.GetInstanceID(); LinearColor directColor, indirectColor; directColor = add.affectDiffuse ? LinearColor.Convert(l.color, l.intensity) : LinearColor.Black(); directColor.red *= cct.r; directColor.green *= cct.g; directColor.blue *= cct.b; indirectColor = add.affectDiffuse ? LightmapperUtils.ExtractIndirect(l) : LinearColor.Black(); indirectColor.red *= cct.r; indirectColor.green *= cct.g; indirectColor.blue *= cct.b; #if UNITY_EDITOR LightMode lightMode = LightmapperUtils.Extract(l.lightmapBakeType); #else LightMode lightMode = LightmapperUtils.Extract(l.bakingOutput.lightmapBakeType); #endif ld.color = directColor; ld.indirectColor = indirectColor; // Note that the HDRI is correctly integrated in the GlobalIllumination system, we don't need to do anything regarding it. // The difference is that `l.lightmapBakeType` is the intent, e.g.you want a mixed light with shadowmask. But then the overlap test might detect more than 4 overlapping volumes and force a light to fallback to baked. // In that case `l.bakingOutput.lightmapBakeType` would be baked, instead of mixed, whereas `l.lightmapBakeType` would still be mixed. But this difference is only relevant in editor builds #if UNITY_EDITOR ld.mode = LightmapperUtils.Extract(l.lightmapBakeType); #else ld.mode = LightmapperUtils.Extract(l.bakingOutput.lightmapBakeType); #endif ld.shadow = (byte)(l.shadows != LightShadows.None ? 1 : 0); if (add.lightTypeExtent == LightTypeExtent.Punctual) { // For HDRP we need to divide the analytic light color by PI (HDRP do explicit PI division for Lambert, but built in Unity and the GI don't for punctual lights) // We apply it on both direct and indirect are they are separated, seems that direct is no used if we used mixed mode with indirect or shadowmask bake. ld.color.intensity /= Mathf.PI; ld.indirectColor.intensity /= Mathf.PI; directColor.intensity /= Mathf.PI; indirectColor.intensity /= Mathf.PI; switch (l.type) { case LightType.Directional: ld.orientation.SetLookRotation(l.transform.forward, Vector3.up); ld.position = Vector3.zero; ld.range = 0.0f; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.shadows != LightShadows.None ? (Mathf.Deg2Rad * l.shadowAngle) : 0.0f; #else ld.shape0 = 0.0f; #endif ld.shape1 = 0.0f; ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Directional; ld.falloff = FalloffType.Undefined; break; case LightType.Spot: switch (add.spotLightShape) { case SpotLightShape.Cone: { SpotLight spot; spot.instanceID = l.GetInstanceID(); spot.shadow = l.shadows != LightShadows.None; spot.mode = lightMode; #if UNITY_EDITOR spot.sphereRadius = l.shadows != LightShadows.None ? l.shadowRadius : 0.0f; #else spot.sphereRadius = 0.0f; #endif spot.position = l.transform.position; spot.orientation = l.transform.rotation; spot.color = directColor; spot.indirectColor = indirectColor; spot.range = l.range; spot.coneAngle = l.spotAngle * Mathf.Deg2Rad; spot.innerConeAngle = l.spotAngle * Mathf.Deg2Rad * add.innerSpotPercent01; spot.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; spot.angularFalloff = AngularFalloffType.AnalyticAndInnerAngle; ld.Init(ref spot); ld.shape1 = (float)AngularFalloffType.AnalyticAndInnerAngle; } break; case SpotLightShape.Pyramid: { SpotLightPyramidShape pyramid; pyramid.instanceID = l.GetInstanceID(); pyramid.shadow = l.shadows != LightShadows.None; pyramid.mode = lightMode; pyramid.position = l.transform.position; pyramid.orientation = l.transform.rotation; pyramid.color = directColor; pyramid.indirectColor = indirectColor; pyramid.range = l.range; pyramid.angle = l.spotAngle * Mathf.Deg2Rad; pyramid.aspectRatio = add.aspectRatio; pyramid.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; ld.Init(ref pyramid); } break; case SpotLightShape.Box: { SpotLightBoxShape box; box.instanceID = l.GetInstanceID(); box.shadow = l.shadows != LightShadows.None; box.mode = lightMode; box.position = l.transform.position; box.orientation = l.transform.rotation; box.color = directColor; box.indirectColor = indirectColor; box.range = l.range; box.width = add.shapeWidth; box.height = add.shapeHeight; ld.Init(ref box); } break; default: Debug.Assert(false, "Encountered an unknown SpotLightShape."); break; } break; case LightType.Point: ld.orientation = Quaternion.identity; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.shadows != LightShadows.None ? l.shadowRadius : 0.0f; #else ld.shape0 = 0.0f; #endif ld.shape1 = 0.0f; ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Point; ld.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; break; // Note: We don't support this type in HDRP, but ini just in case case LightType.Rectangle: ld.orientation = l.transform.rotation; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.areaSize.x; ld.shape1 = l.areaSize.y; #else ld.shape0 = 0.0f; ld.shape1 = 0.0f; #endif ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle; ld.falloff = FalloffType.Undefined; break; default: Debug.Assert(false, "Encountered an unknown LightType."); break; } } else if (add.lightTypeExtent == LightTypeExtent.Rectangle) { ld.orientation = l.transform.rotation; ld.position = l.transform.position; ld.range = l.range; ld.coneAngle = 0.0f; ld.innerConeAngle = 0.0f; #if UNITY_EDITOR ld.shape0 = l.areaSize.x; ld.shape1 = l.areaSize.y; #else ld.shape0 = 0.0f; ld.shape1 = 0.0f; #endif // TEMP: for now, if we bake a rectangle type this will disable the light for runtime, need to speak with GI team about it! ld.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle; ld.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; } else if (add.lightTypeExtent == LightTypeExtent.Tube) { ld.InitNoBake(ld.instanceID); } else { Debug.Assert(false, "Encountered an unknown LightType."); } return(true); }
void InitializeLightConstants(NativeArray <VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightAttenuation, out Vector4 lightSpotDir, out LightCookie cookie) { lightPos = k_DefaultLightPosition; lightColor = k_DefaultLightColor; lightAttenuation = k_DefaultLightAttenuation; lightSpotDir = k_DefaultLightSpotDirection; cookie = null; // 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, 1.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 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.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(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; Texture lightTex = light.cookie; LWRPAdditionalLightData data = light.gameObject.GetComponent <LWRPAdditionalLightData>(); if (lightTex && data) { cookie = new LightCookie { Tex = lightTex, LightMat = light.transform.worldToLocalMatrix, CookieSize = light.cookieSize, Falloff = data.lightCookieFalloff, cookieColor = data.lightCookieColor, }; } 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; } } }
// Return true if the light must be added to the baking public static bool LightDataGIExtract(Light light, ref LightDataGI lightDataGI) { var add = light.GetComponent <HDAdditionalLightData>(); if (add == null) { add = HDUtils.s_DefaultHDAdditionalLightData; } Cookie cookie; LightmapperUtils.Extract(light, out cookie); lightDataGI.cookieID = cookie.instanceID; lightDataGI.cookieScale = cookie.scale; Color cct = new Color(1.0f, 1.0f, 1.0f); if (add.useColorTemperature) { cct = Mathf.CorrelatedColorTemperatureToRGB(light.colorTemperature); } #if UNITY_EDITOR LightMode lightMode = LightmapperUtils.Extract(light.lightmapBakeType); #else LightMode lightMode = LightmapperUtils.Extract(light.bakingOutput.lightmapBakeType); #endif float lightDimmer = 1; if (lightMode == LightMode.Realtime && add.affectDiffuse) { lightDimmer = add.lightDimmer; } lightDataGI.instanceID = light.GetInstanceID(); LinearColor directColor, indirectColor; directColor = add.affectDiffuse ? LinearColor.Convert(light.color, light.intensity) : LinearColor.Black(); directColor.red *= cct.r; directColor.green *= cct.g; directColor.blue *= cct.b; directColor.intensity *= lightDimmer; indirectColor = add.affectDiffuse ? LightmapperUtils.ExtractIndirect(light) : LinearColor.Black(); indirectColor.red *= cct.r; indirectColor.green *= cct.g; indirectColor.blue *= cct.b; indirectColor.intensity *= lightDimmer; lightDataGI.color = directColor; lightDataGI.indirectColor = indirectColor; // Note that the HDRI is correctly integrated in the GlobalIllumination system, we don't need to do anything regarding it. // The difference is that `l.lightmapBakeType` is the intent, e.g.you want a mixed light with shadowmask. But then the overlap test might detect more than 4 overlapping volumes and force a light to fallback to baked. // In that case `l.bakingOutput.lightmapBakeType` would be baked, instead of mixed, whereas `l.lightmapBakeType` would still be mixed. But this difference is only relevant in editor builds #if UNITY_EDITOR lightDataGI.mode = LightmapperUtils.Extract(light.lightmapBakeType); #else lightDataGI.mode = LightmapperUtils.Extract(light.bakingOutput.lightmapBakeType); #endif lightDataGI.shadow = (byte)(light.shadows != LightShadows.None ? 1 : 0); HDLightType lightType = add.ComputeLightType(light); if (lightType != HDLightType.Area) { // For HDRP we need to divide the analytic light color by PI (HDRP do explicit PI division for Lambert, but built in Unity and the GI don't for punctual lights) // We apply it on both direct and indirect are they are separated, seems that direct is no used if we used mixed mode with indirect or shadowmask bake. lightDataGI.color.intensity /= Mathf.PI; lightDataGI.indirectColor.intensity /= Mathf.PI; directColor.intensity /= Mathf.PI; indirectColor.intensity /= Mathf.PI; } switch (lightType) { case HDLightType.Directional: lightDataGI.orientation = light.transform.rotation; lightDataGI.position = light.transform.position; lightDataGI.range = 0.0f; lightDataGI.coneAngle = add.shapeWidth; lightDataGI.innerConeAngle = add.shapeHeight; #if UNITY_EDITOR lightDataGI.shape0 = light.shadows != LightShadows.None ? (Mathf.Deg2Rad * light.shadowAngle) : 0.0f; #else lightDataGI.shape0 = 0.0f; #endif lightDataGI.shape1 = 0.0f; lightDataGI.type = UnityEngine.Experimental.GlobalIllumination.LightType.Directional; lightDataGI.falloff = FalloffType.Undefined; lightDataGI.coneAngle = add.shapeWidth; lightDataGI.innerConeAngle = add.shapeHeight; break; case HDLightType.Spot: switch (add.spotLightShape) { case SpotLightShape.Cone: { SpotLight spot; spot.instanceID = light.GetInstanceID(); spot.shadow = light.shadows != LightShadows.None; spot.mode = lightMode; #if UNITY_EDITOR spot.sphereRadius = light.shadows != LightShadows.None ? light.shadowRadius : 0.0f; #else spot.sphereRadius = 0.0f; #endif spot.position = light.transform.position; spot.orientation = light.transform.rotation; spot.color = directColor; spot.indirectColor = indirectColor; spot.range = light.range; spot.coneAngle = light.spotAngle * Mathf.Deg2Rad; spot.innerConeAngle = light.spotAngle * Mathf.Deg2Rad * add.innerSpotPercent01; spot.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; spot.angularFalloff = AngularFalloffType.AnalyticAndInnerAngle; lightDataGI.Init(ref spot, ref cookie); lightDataGI.shape1 = (float)AngularFalloffType.AnalyticAndInnerAngle; if (light.cookie != null) { lightDataGI.cookieID = light.cookie.GetInstanceID(); } else if (add.IESSpot != null) { lightDataGI.cookieID = add.IESSpot.GetInstanceID(); } else { lightDataGI.cookieID = 0; } } break; case SpotLightShape.Pyramid: { SpotLightPyramidShape pyramid; pyramid.instanceID = light.GetInstanceID(); pyramid.shadow = light.shadows != LightShadows.None; pyramid.mode = lightMode; pyramid.position = light.transform.position; pyramid.orientation = light.transform.rotation; pyramid.color = directColor; pyramid.indirectColor = indirectColor; pyramid.range = light.range; pyramid.angle = light.spotAngle * Mathf.Deg2Rad; pyramid.aspectRatio = add.aspectRatio; pyramid.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; lightDataGI.Init(ref pyramid, ref cookie); if (light.cookie != null) { lightDataGI.cookieID = light.cookie.GetInstanceID(); } else if (add.IESSpot != null) { lightDataGI.cookieID = add.IESSpot.GetInstanceID(); } else { lightDataGI.cookieID = 0; } } break; case SpotLightShape.Box: { SpotLightBoxShape box; box.instanceID = light.GetInstanceID(); box.shadow = light.shadows != LightShadows.None; box.mode = lightMode; box.position = light.transform.position; box.orientation = light.transform.rotation; box.color = directColor; box.indirectColor = indirectColor; box.range = light.range; box.width = add.shapeWidth; box.height = add.shapeHeight; lightDataGI.Init(ref box, ref cookie); if (light.cookie != null) { lightDataGI.cookieID = light.cookie.GetInstanceID(); } else if (add.IESSpot != null) { lightDataGI.cookieID = add.IESSpot.GetInstanceID(); } else { lightDataGI.cookieID = 0; } } break; default: Debug.Assert(false, "Encountered an unknown SpotLightShape."); break; } break; case HDLightType.Point: lightDataGI.orientation = light.transform.rotation; lightDataGI.position = light.transform.position; lightDataGI.range = light.range; lightDataGI.coneAngle = 0.0f; lightDataGI.innerConeAngle = 0.0f; #if UNITY_EDITOR lightDataGI.shape0 = light.shadows != LightShadows.None ? light.shadowRadius : 0.0f; #else lightDataGI.shape0 = 0.0f; #endif lightDataGI.shape1 = 0.0f; lightDataGI.type = UnityEngine.Experimental.GlobalIllumination.LightType.Point; lightDataGI.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; break; case HDLightType.Area: switch (add.areaLightShape) { case AreaLightShape.Rectangle: lightDataGI.orientation = light.transform.rotation; lightDataGI.position = light.transform.position; lightDataGI.range = light.range; lightDataGI.coneAngle = 0.0f; lightDataGI.innerConeAngle = 0.0f; lightDataGI.shape0 = add.shapeWidth; lightDataGI.shape1 = add.shapeHeight; // TEMP: for now, if we bake a rectangle type this will disable the light for runtime, need to speak with GI team about it! lightDataGI.type = UnityEngine.Experimental.GlobalIllumination.LightType.Rectangle; lightDataGI.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; if (add.areaLightCookie != null) { lightDataGI.cookieID = add.areaLightCookie.GetInstanceID(); } else if (add.IESSpot != null) { lightDataGI.cookieID = add.IESSpot.GetInstanceID(); } else { lightDataGI.cookieID = 0; } break; case AreaLightShape.Tube: lightDataGI.InitNoBake(lightDataGI.instanceID); break; case AreaLightShape.Disc: lightDataGI.orientation = light.transform.rotation; lightDataGI.position = light.transform.position; lightDataGI.range = light.range; lightDataGI.coneAngle = 0.0f; lightDataGI.innerConeAngle = 0.0f; #if UNITY_EDITOR lightDataGI.shape0 = light.areaSize.x; lightDataGI.shape1 = light.areaSize.y; #else lightDataGI.shape0 = 0.0f; lightDataGI.shape1 = 0.0f; #endif // TEMP: for now, if we bake a rectangle type this will disable the light for runtime, need to speak with GI team about it! lightDataGI.type = UnityEngine.Experimental.GlobalIllumination.LightType.Disc; lightDataGI.falloff = add.applyRangeAttenuation ? FalloffType.InverseSquared : FalloffType.InverseSquaredNoRangeAttenuation; lightDataGI.cookieID = add.areaLightCookie ? add.areaLightCookie.GetInstanceID() : 0; break; default: Debug.Assert(false, "Encountered an unknown AreaLightShape."); break; } break; default: Debug.Assert(false, "Encountered an unknown LightType."); break; } return(true); }