static void ResetLight(MenuCommand menuCommand) { GameObject go = ((Light)menuCommand.context).gameObject; Assert.IsNotNull(go); Light light = go.GetComponent <Light>(); HDAdditionalLightData lightAdditionalData = go.GetComponent <HDAdditionalLightData>(); HDLightType lightType = lightAdditionalData.type; Assert.IsNotNull(light); Assert.IsNotNull(lightAdditionalData); Undo.RecordObjects(new UnityEngine.Object[] { light, lightAdditionalData }, "Reset HD Light"); light.Reset(); // To avoid duplicating init code we copy default settings to Reset additional data // Note: we can't call this code inside the HDAdditionalLightData, thus why we don't wrap it in a Reset() function HDUtils.s_DefaultHDAdditionalLightData.CopyTo(lightAdditionalData); lightAdditionalData.type = lightType; //reinit default intensity HDAdditionalLightData.InitDefaultHDAdditionalLightData(lightAdditionalData); //patch missing cookie texture reset in built-in light reset light.cookie = null; }
// ------------------------ Public API ------------------------------- /// <summary> /// This function verifies if a shadow map of resolution shadowResolution for a light of type lightType would fit in the atlas when inserted. /// </summary> /// <param name="shadowResolution">The resolution of the hypothetical shadow map that we are assessing.</param> /// <param name="lightType">The type of the light that cast the hypothetical shadow map that we are assessing.</param> /// <returns>True if the shadow map would fit in the atlas, false otherwise.</returns> public bool WouldFitInAtlas(int shadowResolution, HDLightType lightType) { bool fits = true; int x, y; if (lightType == HDLightType.Point) { for (int i = 0; i < 6; ++i) { fits = fits && HDShadowManager.cachedShadowManager.punctualShadowAtlas.FindSlotInAtlas(shadowResolution, out x, out y); } } if (lightType == HDLightType.Spot) { fits = fits && HDShadowManager.cachedShadowManager.punctualShadowAtlas.FindSlotInAtlas(shadowResolution, out x, out y); } if (lightType == HDLightType.Area) { fits = fits && HDShadowManager.cachedShadowManager.areaShadowAtlas.FindSlotInAtlas(shadowResolution, out x, out y); } return(fits); }
// Helper for punctual and area light unit conversion /// <summary> /// Convert a punctual light intensity in Lumen to Candela /// </summary> /// <param name="lightType"></param> /// <param name="lumen"></param> /// <param name="initialIntensity"></param> /// <param name="enableSpotReflector"></param> /// <returns></returns> public static float ConvertPunctualLightLumenToCandela(HDLightType lightType, float lumen, float initialIntensity, bool enableSpotReflector) { if (lightType == HDLightType.Spot && enableSpotReflector) { // We have already calculate the correct value, just assign it return(initialIntensity); } return(ConvertPointLightLumenToCandela(lumen)); }
/// <summary> /// Add a new HDRP Light to a GameObject /// </summary> /// <param name="gameObject">The GameObject on which the light is going to be added</param> /// <param name="lightType">The Type of the HDRP light to Add</param> /// <returns>The created HDRP Light component</returns> public static HDAdditionalLightData AddHDLight(this GameObject gameObject, HDLightType lightType) { var hdLight = gameObject.AddComponent <HDAdditionalLightData>(); HDAdditionalLightData.InitDefaultHDAdditionalLightData(hdLight); hdLight.SetLightType(lightType); return(hdLight); }
/// <summary> /// If a light is added after a scene is loaded, its placement in the atlas might be not optimal and the suboptimal placement might prevent a light to find a place in the atlas. /// This function will force a defragmentation of the atlas containing lights of type lightType and redistributes the shadows inside so that the placement is optimal. Note however that this will also mark the shadow maps /// as dirty and they will be re-rendered as soon the light will come into view for the first time after this function call. /// </summary> /// <param name="lightType">The type of the light contained in the atlas that need defragmentation.</param> public void DefragAtlas(HDLightType lightType) { if (lightType == HDLightType.Area) { instance.areaShadowAtlas.DefragmentAtlasAndReRender(instance.m_InitParams); } if (lightType == HDLightType.Point || lightType == HDLightType.Spot) { instance.punctualShadowAtlas.DefragmentAtlasAndReRender(instance.m_InitParams); } }
internal void RemoveTransformFromCache(HDAdditionalLightData lightData) { HDLightType lightType = lightData.type; if (lightType == HDLightType.Spot || lightType == HDLightType.Point) { punctualShadowAtlas.RemoveTransformFromCache(lightData); } if (ShaderConfig.s_AreaLights == 1 && lightType == HDLightType.Area) { areaShadowAtlas.RemoveTransformFromCache(lightData); } }
public void Draw(HDLightType type, LightUnit lightUnit, SerializedProperty value, Rect rect, SerializedHDLight light, Editor owner) { using (new EditorGUI.IndentLevelScope(-EditorGUI.indentLevel)) { if (type == HDLightType.Directional) { DrawDirectionalUnitSlider(value, rect); } else { DrawPunctualLightUnitSlider(lightUnit, value, rect, light, owner); } } }
internal void RegisterTransformToCache(HDAdditionalLightData lightData) { HDLightType lightType = lightData.type; if (lightType == HDLightType.Spot || lightType == HDLightType.Point) { punctualShadowAtlas.RegisterTransformCacheSlot(lightData); } if (ShaderConfig.s_AreaLights == 1 && lightType == HDLightType.Area) { areaShadowAtlas.RegisterTransformCacheSlot(lightData); } if (lightType == HDLightType.Directional) { m_CachedDirectionalAngles = lightData.transform.eulerAngles; } }
protected override void OnSceneGUI() { // Each handles manipulate only one light // Thus do not rely on serialized properties HDLightType lightType = targetAdditionalData.type; if (lightType == HDLightType.Directional || lightType == HDLightType.Point || lightType == HDLightType.Area && targetAdditionalData.areaLightShape == AreaLightShape.Disc) { base.OnSceneGUI(); } else { HDLightUI.DrawHandles(targetAdditionalData, this); } }
internal void RegisterLight(HDAdditionalLightData lightData) { HDLightType lightType = lightData.type; if (lightType == HDLightType.Directional) { lightData.lightIdxForCachedShadows = 0; MarkAllDirectionalShadowsForUpdate(); } if (lightType == HDLightType.Spot || lightType == HDLightType.Point) { punctualShadowAtlas.RegisterLight(lightData); } if (ShaderConfig.s_AreaLights == 1 && lightType == HDLightType.Area && lightData.areaLightShape == AreaLightShape.Rectangle) { areaShadowAtlas.RegisterLight(lightData); } }
internal void EvictLight(HDAdditionalLightData lightData) { HDLightType lightType = lightData.type; if (lightType == HDLightType.Directional) { lightData.lightIdxForCachedShadows = -1; MarkAllDirectionalShadowsForUpdate(); } if (lightType == HDLightType.Spot || lightType == HDLightType.Point) { punctualShadowAtlas.EvictLight(lightData); } if (ShaderConfig.s_AreaLights == 1 && lightType == HDLightType.Area) { areaShadowAtlas.EvictLight(lightData); } }
private void AddLightListToRecordList(Dictionary <int, HDAdditionalLightData> lightList, HDShadowInitParameters initParams, ref List <CachedShadowRecord> recordList) { foreach (var currentLightData in lightList.Values) { int resolution = 0; resolution = currentLightData.GetResolutionFromSettings(m_ShadowType, initParams); HDLightType lightType = currentLightData.type; int numberOfShadows = (lightType == HDLightType.Point) ? 6 : 1; for (int i = 0; i < numberOfShadows; ++i) { CachedShadowRecord record; record.shadowIndex = currentLightData.lightIdxForCachedShadows + i; record.viewportSize = resolution; record.offsetInAtlas = new Vector4(-1, -1, -1, -1); // Will be set later. recordList.Add(record); } } }
/// <summary> /// Convert a punctual light intensity in Candela to Lumen /// </summary> /// <param name="lightType"></param> /// <param name="spotLightShape"></param> /// <param name="candela"></param> /// <param name="enableSpotReflector"></param> /// <param name="spotAngle"></param> /// <param name="aspectRatio"></param> /// <returns></returns> public static float ConvertPunctualLightCandelaToLumen(HDLightType lightType, SpotLightShape spotLightShape, float candela, bool enableSpotReflector, float spotAngle, float aspectRatio) { if (lightType == HDLightType.Spot && enableSpotReflector) { // We just need to multiply candela by solid angle in this case if (spotLightShape == SpotLightShape.Cone) { return(ConvertSpotLightCandelaToLumen(candela, spotAngle * Mathf.Deg2Rad, true)); } else if (spotLightShape == SpotLightShape.Pyramid) { float angleA, angleB; CalculateAnglesForPyramid(aspectRatio, spotAngle * Mathf.Deg2Rad, out angleA, out angleB); return(ConvertFrustrumLightCandelaToLumen(candela, angleA, angleB)); } else // Box { return(ConvertPointLightCandelaToLumen(candela)); } } return(ConvertPointLightCandelaToLumen(candela)); }
private void AddLightListToRecordList(Dictionary <int, HDAdditionalLightData> lightList, HDShadowInitParameters initParams, ref List <CachedShadowRecord> recordList) { foreach (var currentLightData in lightList.Values) { int resolution = 0; resolution = currentLightData.GetResolutionFromSettings(m_ShadowType, initParams); HDLightType lightType = currentLightData.type; int numberOfShadows = (lightType == HDLightType.Point) ? 6 : 1; for (int i = 0; i < numberOfShadows; ++i) { CachedShadowRecord record; record.shadowIndex = currentLightData.lightIdxForCachedShadows + i; record.viewportSize = resolution; record.offsetInAtlas = new Vector4(-1, -1, -1, -1); // Will be set later. // Only situation in which we allow not to render on placement if it is OnDemand and onDemandShadowRenderOnPlacement is false record.rendersOnPlacement = (currentLightData.shadowUpdateMode == ShadowUpdateMode.OnDemand) ? (currentLightData.forceRenderOnPlacement || currentLightData.onDemandShadowRenderOnPlacement) : true; currentLightData.forceRenderOnPlacement = false; // reset the force flag as we scheduled the rendering forcefully already. recordList.Add(record); } } }
internal static void ConvertLightIntensity(LightUnit oldLightUnit, LightUnit newLightUnit, HDAdditionalLightData hdLight, Light light) { float intensity = hdLight.intensity; float luxAtDistance = hdLight.luxAtDistance; HDLightType lightType = hdLight.ComputeLightType(light); // For punctual lights if (lightType != HDLightType.Area) { // Lumen -> if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Candela) { intensity = LightUtils.ConvertPunctualLightLumenToCandela(lightType, intensity, light.intensity, hdLight.enableSpotReflector); } else if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Lux) { intensity = LightUtils.ConvertPunctualLightLumenToLux(lightType, intensity, light.intensity, hdLight.enableSpotReflector, hdLight.luxAtDistance); } else if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Ev100) { intensity = LightUtils.ConvertPunctualLightLumenToEv(lightType, intensity, light.intensity, hdLight.enableSpotReflector); } // Candela -> else if (oldLightUnit == LightUnit.Candela && newLightUnit == LightUnit.Lumen) { intensity = LightUtils.ConvertPunctualLightCandelaToLumen(lightType, hdLight.spotLightShape, intensity, hdLight.enableSpotReflector, light.spotAngle, hdLight.aspectRatio); } else if (oldLightUnit == LightUnit.Candela && newLightUnit == LightUnit.Lux) { intensity = LightUtils.ConvertCandelaToLux(intensity, hdLight.luxAtDistance); } else if (oldLightUnit == LightUnit.Candela && newLightUnit == LightUnit.Ev100) { intensity = LightUtils.ConvertCandelaToEv(intensity); } // Lux -> else if (oldLightUnit == LightUnit.Lux && newLightUnit == LightUnit.Lumen) { intensity = LightUtils.ConvertPunctualLightLuxToLumen(lightType, hdLight.spotLightShape, intensity, hdLight.enableSpotReflector, light.spotAngle, hdLight.aspectRatio, hdLight.luxAtDistance); } else if (oldLightUnit == LightUnit.Lux && newLightUnit == LightUnit.Candela) { intensity = LightUtils.ConvertLuxToCandela(intensity, hdLight.luxAtDistance); } else if (oldLightUnit == LightUnit.Lux && newLightUnit == LightUnit.Ev100) { intensity = LightUtils.ConvertLuxToEv(intensity, hdLight.luxAtDistance); } // EV100 -> else if (oldLightUnit == LightUnit.Ev100 && newLightUnit == LightUnit.Lumen) { intensity = LightUtils.ConvertPunctualLightEvToLumen(lightType, hdLight.spotLightShape, intensity, hdLight.enableSpotReflector, light.spotAngle, hdLight.aspectRatio); } else if (oldLightUnit == LightUnit.Ev100 && newLightUnit == LightUnit.Candela) { intensity = LightUtils.ConvertEvToCandela(intensity); } else if (oldLightUnit == LightUnit.Ev100 && newLightUnit == LightUnit.Lux) { intensity = LightUtils.ConvertEvToLux(intensity, hdLight.luxAtDistance); } } else // For area lights { if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Nits) { intensity = LightUtils.ConvertAreaLightLumenToLuminance(hdLight.areaLightShape, intensity, hdLight.shapeWidth, hdLight.shapeHeight); } if (oldLightUnit == LightUnit.Nits && newLightUnit == LightUnit.Lumen) { intensity = LightUtils.ConvertAreaLightLuminanceToLumen(hdLight.areaLightShape, intensity, hdLight.shapeWidth, hdLight.shapeHeight); } if (oldLightUnit == LightUnit.Nits && newLightUnit == LightUnit.Ev100) { intensity = LightUtils.ConvertLuminanceToEv(intensity); } if (oldLightUnit == LightUnit.Ev100 && newLightUnit == LightUnit.Nits) { intensity = LightUtils.ConvertEvToLuminance(intensity); } if (oldLightUnit == LightUnit.Ev100 && newLightUnit == LightUnit.Lumen) { intensity = LightUtils.ConvertAreaLightEvToLumen(hdLight.areaLightShape, intensity, hdLight.shapeWidth, hdLight.shapeHeight); } if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Ev100) { intensity = LightUtils.ConvertAreaLightLumenToEv(hdLight.areaLightShape, intensity, hdLight.shapeWidth, hdLight.shapeHeight); } } hdLight.intensity = intensity; }
// This is not correct, we use candela instead of luminance but this is request from artists to support EV100 on punctual light /// <summary> /// Convert a punctual light intensity in Lumen to EV100. /// This is not physically correct but it's handy to have EV100 for punctual lights. /// </summary> /// <param name="lightType"></param> /// <param name="lumen"></param> /// <param name="initialIntensity"></param> /// <param name="enableSpotReflector"></param> /// <returns></returns> public static float ConvertPunctualLightLumenToEv(HDLightType lightType, float lumen, float initialIntensity, bool enableSpotReflector) { float candela = ConvertPunctualLightLumenToCandela(lightType, lumen, initialIntensity, enableSpotReflector); return(ConvertCandelaToEv(candela)); }
// This is not correct, we use candela instead of luminance but this is request from artists to support EV100 on punctual light /// <summary> /// Convert a punctual light intensity in EV100 to Lumen. /// This is not physically correct but it's handy to have EV100 for punctual lights. /// </summary> /// <param name="lightType"></param> /// <param name="spotLightShape"></param> /// <param name="ev"></param> /// <param name="enableSpotReflector"></param> /// <param name="spotAngle"></param> /// <param name="aspectRatio"></param> /// <returns></returns> public static float ConvertPunctualLightEvToLumen(HDLightType lightType, SpotLightShape spotLightShape, float ev, bool enableSpotReflector, float spotAngle, float aspectRatio) { float candela = ConvertEvToCandela(ev); return(ConvertPunctualLightCandelaToLumen(lightType, spotLightShape, candela, enableSpotReflector, spotAngle, aspectRatio)); }
/// <summary> /// Convert a punctual light intensity in Lux to Lumen /// </summary> /// <param name="lightType"></param> /// <param name="spotLightShape"></param> /// <param name="lux"></param> /// <param name="enableSpotReflector"></param> /// <param name="spotAngle"></param> /// <param name="aspectRatio"></param> /// <param name="distance"></param> /// <returns></returns> public static float ConvertPunctualLightLuxToLumen(HDLightType lightType, SpotLightShape spotLightShape, float lux, bool enableSpotReflector, float spotAngle, float aspectRatio, float distance) { float candela = ConvertLuxToCandela(lux, distance); return(ConvertPunctualLightCandelaToLumen(lightType, spotLightShape, candela, enableSpotReflector, spotAngle, aspectRatio)); }
void BuildLightData(CommandBuffer cmd, HDCamera hdCamera, HDRayTracingLights rayTracingLights) { // If no lights, exit if (rayTracingLights.lightCount == 0) { ResizeLightDataBuffer(1); return; } // Also we need to build the light list data if (m_LightDataGPUArray == null || m_LightDataGPUArray.count != rayTracingLights.lightCount) { ResizeLightDataBuffer(rayTracingLights.lightCount); } m_LightDataCPUArray.Clear(); // Build the data for every light for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightArray.Count; ++lightIdx) { var lightData = new LightData(); HDAdditionalLightData additionalLightData = rayTracingLights.hdLightArray[lightIdx]; // When the user deletes a light source in the editor, there is a single frame where the light is null before the collection of light in the scene is triggered // the workaround for this is simply to add an invalid light for that frame if (additionalLightData == null) { m_LightDataCPUArray.Add(lightData); continue; } Light light = additionalLightData.gameObject.GetComponent <Light>(); // Both of these positions are non-camera-relative. float distanceToCamera = (light.gameObject.transform.position - hdCamera.camera.transform.position).magnitude; float lightDistanceFade = HDUtils.ComputeLinearDistanceFade(distanceToCamera, additionalLightData.fadeDistance); bool contributesToLighting = ((additionalLightData.lightDimmer > 0) && (additionalLightData.affectDiffuse || additionalLightData.affectSpecular)) || (additionalLightData.volumetricDimmer > 0); contributesToLighting = contributesToLighting && (lightDistanceFade > 0); if (!contributesToLighting) { continue; } lightData.lightLayers = additionalLightData.GetLightLayers(); LightCategory lightCategory = LightCategory.Count; GPULightType gpuLightType = GPULightType.Point; LightVolumeType lightVolumeType = LightVolumeType.Count; HDLightType lightType = additionalLightData.type; HDRenderPipeline.EvaluateGPULightType(lightType, additionalLightData.spotLightShape, additionalLightData.areaLightShape, ref lightCategory, ref gpuLightType, ref lightVolumeType); lightData.lightType = gpuLightType; lightData.positionRWS = light.gameObject.transform.position; bool applyRangeAttenuation = additionalLightData.applyRangeAttenuation && (gpuLightType != GPULightType.ProjectorBox); lightData.range = light.range; if (applyRangeAttenuation) { lightData.rangeAttenuationScale = 1.0f / (light.range * light.range); lightData.rangeAttenuationBias = 1.0f; if (lightData.lightType == GPULightType.Rectangle) { // Rect lights are currently a special case because they use the normalized // [0, 1] attenuation range rather than the regular [0, r] one. lightData.rangeAttenuationScale = 1.0f; } } else // Don't apply any attenuation but do a 'step' at range { // Solve f(x) = b - (a * x)^2 where x = (d/r)^2. // f(0) = huge -> b = huge. // f(1) = 0 -> huge - a^2 = 0 -> a = sqrt(huge). const float hugeValue = 16777216.0f; const float sqrtHuge = 4096.0f; lightData.rangeAttenuationScale = sqrtHuge / (light.range * light.range); lightData.rangeAttenuationBias = hugeValue; if (lightData.lightType == GPULightType.Rectangle) { // Rect lights are currently a special case because they use the normalized // [0, 1] attenuation range rather than the regular [0, r] one. lightData.rangeAttenuationScale = sqrtHuge; } } Color value = light.color.linear * light.intensity; if (additionalLightData.useColorTemperature) { value *= Mathf.CorrelatedColorTemperatureToRGB(light.colorTemperature); } lightData.color = new Vector3(value.r, value.g, value.b); lightData.forward = light.transform.forward; lightData.up = light.transform.up; lightData.right = light.transform.right; lightData.boxLightSafeExtent = 1.0f; if (lightData.lightType == GPULightType.ProjectorBox) { // Rescale for cookies and windowing. lightData.right *= 2.0f / Mathf.Max(additionalLightData.shapeWidth, 0.001f); lightData.up *= 2.0f / Mathf.Max(additionalLightData.shapeHeight, 0.001f); } else if (lightData.lightType == GPULightType.ProjectorPyramid) { // Get width and height for the current frustum var spotAngle = light.spotAngle; float frustumWidth, frustumHeight; if (additionalLightData.aspectRatio >= 1.0f) { frustumHeight = 2.0f * Mathf.Tan(spotAngle * 0.5f * Mathf.Deg2Rad); frustumWidth = frustumHeight * additionalLightData.aspectRatio; } else { frustumWidth = 2.0f * Mathf.Tan(spotAngle * 0.5f * Mathf.Deg2Rad); frustumHeight = frustumWidth / additionalLightData.aspectRatio; } // Rescale for cookies and windowing. lightData.right *= 2.0f / frustumWidth; lightData.up *= 2.0f / frustumHeight; } if (lightData.lightType == GPULightType.Spot) { var spotAngle = light.spotAngle; var innerConePercent = additionalLightData.innerSpotPercent01; var cosSpotOuterHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * Mathf.Deg2Rad), 0.0f, 1.0f); var sinSpotOuterHalfAngle = Mathf.Sqrt(1.0f - cosSpotOuterHalfAngle * cosSpotOuterHalfAngle); var cosSpotInnerHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * innerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone var val = Mathf.Max(0.0001f, (cosSpotInnerHalfAngle - cosSpotOuterHalfAngle)); lightData.angleScale = 1.0f / val; lightData.angleOffset = -cosSpotOuterHalfAngle * lightData.angleScale; // Rescale for cookies and windowing. float cotOuterHalfAngle = cosSpotOuterHalfAngle / sinSpotOuterHalfAngle; lightData.up *= cotOuterHalfAngle; lightData.right *= cotOuterHalfAngle; } else { // These are the neutral values allowing GetAngleAnttenuation in shader code to return 1.0 lightData.angleScale = 0.0f; lightData.angleOffset = 1.0f; } if (lightData.lightType != GPULightType.Directional && lightData.lightType != GPULightType.ProjectorBox) { // Store the squared radius of the light to simulate a fill light. lightData.size = new Vector2(additionalLightData.shapeRadius * additionalLightData.shapeRadius, 0); } if (lightData.lightType == GPULightType.Rectangle || lightData.lightType == GPULightType.Tube) { lightData.size = new Vector2(additionalLightData.shapeWidth, additionalLightData.shapeHeight); } lightData.lightDimmer = lightDistanceFade * (additionalLightData.lightDimmer); lightData.diffuseDimmer = lightDistanceFade * (additionalLightData.affectDiffuse ? additionalLightData.lightDimmer : 0); lightData.specularDimmer = lightDistanceFade * (additionalLightData.affectSpecular ? additionalLightData.lightDimmer * hdCamera.frameSettings.specularGlobalDimmer : 0); lightData.volumetricLightDimmer = lightDistanceFade * (additionalLightData.volumetricDimmer); lightData.contactShadowMask = 0; lightData.cookieIndex = -1; lightData.shadowIndex = -1; lightData.screenSpaceShadowIndex = -1; if (light != null && light.cookie != null) { // TODO: add texture atlas support for cookie textures. switch (lightType) { case HDLightType.Spot: lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.cookieTexArray.FetchSlice(cmd, light.cookie); break; case HDLightType.Point: lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.cubeCookieTexArray.FetchSlice(cmd, light.cookie); break; } } else if (lightType == HDLightType.Spot && additionalLightData.spotLightShape != SpotLightShape.Cone) { // Projectors lights must always have a cookie texture. // As long as the cache is a texture array and not an atlas, the 4x4 white texture will be rescaled to 128 lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.cookieTexArray.FetchSlice(cmd, Texture2D.whiteTexture); } else if (lightData.lightType == GPULightType.Rectangle && additionalLightData.areaLightCookie != null) { lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.areaLightCookieManager.FetchSlice(cmd, additionalLightData.areaLightCookie); } { lightData.shadowDimmer = 1.0f; lightData.volumetricShadowDimmer = 1.0f; } { // fix up shadow information lightData.shadowIndex = additionalLightData.shadowIndex; } // Value of max smoothness is from artists point of view, need to convert from perceptual smoothness to roughness lightData.minRoughness = (1.0f - additionalLightData.maxSmoothness) * (1.0f - additionalLightData.maxSmoothness); // No usage for the shadow masks lightData.shadowMaskSelector = Vector4.zero; { // use -1 to say that we don't use shadow mask lightData.shadowMaskSelector.x = -1.0f; lightData.nonLightMappedOnly = 0; } if (ShaderConfig.s_CameraRelativeRendering != 0) { // Caution: 'LightData.positionWS' is camera-relative after this point. Vector3 camPosWS = hdCamera.mainViewConstants.worldSpaceCameraPos; lightData.positionRWS -= camPosWS; } // Set the data for this light m_LightDataCPUArray.Add(lightData); } // Push the data to the GPU m_LightDataGPUArray.SetData(m_LightDataCPUArray); }
// 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; // 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(light.colorTemperature); } #endif #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); }
internal bool NeedRenderingDueToTransformChange(HDAdditionalLightData lightData, HDLightType lightType) { bool needUpdate = false; if (m_TransformCaches.TryGetValue(lightData.lightIdxForCachedShadows, out CachedTransform cachedTransform)) { float positionThreshold = lightData.cachedShadowTranslationUpdateThreshold; Vector3 positionDiffVec = cachedTransform.position - lightData.transform.position; float positionDiff = Vector3.Dot(positionDiffVec, positionDiffVec); if (positionDiff > positionThreshold * positionThreshold) { needUpdate = true; } if (lightType != HDLightType.Point) { float angleDiffThreshold = lightData.cachedShadowAngleUpdateThreshold; Vector3 angleDiff = cachedTransform.angles - lightData.transform.eulerAngles; // Any angle difference if (Mathf.Abs(angleDiff.x) > angleDiffThreshold || Mathf.Abs(angleDiff.y) > angleDiffThreshold || Mathf.Abs(angleDiff.z) > angleDiffThreshold) { needUpdate = true; } } if (needUpdate) { // Update the record (CachedTransform is a struct, so we remove old one and replace with a new one) m_TransformCaches.Remove(lightData.lightIdxForCachedShadows); cachedTransform.position = lightData.transform.position; cachedTransform.angles = lightData.transform.eulerAngles; m_TransformCaches.Add(lightData.lightIdxForCachedShadows, cachedTransform); } } return(needUpdate); }
internal bool NeedRenderingDueToTransformChange(HDAdditionalLightData lightData, HDLightType lightType) { if (lightData.updateUponLightMovement) { if (lightType == HDLightType.Directional) { float angleDiffThreshold = lightData.cachedShadowAngleUpdateThreshold; Vector3 angleDiff = m_CachedDirectionalAngles - lightData.transform.eulerAngles; return(Mathf.Abs(angleDiff.x) > angleDiffThreshold || Mathf.Abs(angleDiff.y) > angleDiffThreshold || Mathf.Abs(angleDiff.z) > angleDiffThreshold); } else if (lightType == HDLightType.Area) { return(areaShadowAtlas.NeedRenderingDueToTransformChange(lightData, lightType)); } else { return(punctualShadowAtlas.NeedRenderingDueToTransformChange(lightData, lightType)); } } return(false); }
void BuildLightData(CommandBuffer cmd, HDCamera hdCamera, HDRayTracingLights rayTracingLights, DebugDisplaySettings debugDisplaySettings) { // If no lights, exit if (rayTracingLights.lightCount == 0) { ResizeLightDataBuffer(1); return; } // Also we need to build the light list data if (m_LightDataGPUArray == null || m_LightDataGPUArray.count != rayTracingLights.lightCount) { ResizeLightDataBuffer(rayTracingLights.lightCount); } m_LightDataCPUArray.Clear(); // Grab the shadow settings var hdShadowSettings = hdCamera.volumeStack.GetComponent <HDShadowSettings>(); BoolScalableSetting contactShadowScalableSetting = HDAdditionalLightData.ScalableSettings.UseContactShadow(m_RenderPipeline.asset); // Build the data for every light for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightArray.Count; ++lightIdx) { // Grab the additinal light data to process HDAdditionalLightData additionalLightData = rayTracingLights.hdLightArray[lightIdx]; LightData lightData = new LightData(); // When the user deletes a light source in the editor, there is a single frame where the light is null before the collection of light in the scene is triggered // the workaround for this is simply to add an invalid light for that frame if (additionalLightData == null) { m_LightDataCPUArray.Add(lightData); continue; } // Evaluate all the light type data that we need LightCategory lightCategory = LightCategory.Count; GPULightType gpuLightType = GPULightType.Point; LightVolumeType lightVolumeType = LightVolumeType.Count; HDLightType lightType = additionalLightData.type; HDRenderPipeline.EvaluateGPULightType(lightType, additionalLightData.spotLightShape, additionalLightData.areaLightShape, ref lightCategory, ref gpuLightType, ref lightVolumeType); // Fetch the light component for this light additionalLightData.gameObject.TryGetComponent(out lightComponent); // Build the processed light data that we need ProcessedLightData processedData = new ProcessedLightData(); processedData.additionalLightData = additionalLightData; processedData.lightType = additionalLightData.type; processedData.lightCategory = lightCategory; processedData.gpuLightType = gpuLightType; processedData.lightVolumeType = lightVolumeType; // Both of these positions are non-camera-relative. processedData.distanceToCamera = (additionalLightData.gameObject.transform.position - hdCamera.camera.transform.position).magnitude; processedData.lightDistanceFade = HDUtils.ComputeLinearDistanceFade(processedData.distanceToCamera, additionalLightData.fadeDistance); processedData.volumetricDistanceFade = HDUtils.ComputeLinearDistanceFade(processedData.distanceToCamera, additionalLightData.volumetricFadeDistance); processedData.isBakedShadowMask = HDRenderPipeline.IsBakedShadowMaskLight(lightComponent); // Build a visible light Color finalColor = lightComponent.color.linear * lightComponent.intensity; if (additionalLightData.useColorTemperature) { finalColor *= Mathf.CorrelatedColorTemperatureToRGB(lightComponent.colorTemperature); } visibleLight.finalColor = finalColor; visibleLight.range = lightComponent.range; // This should be done explicitely, localtoworld matrix doesn't work here localToWorldMatrix.SetColumn(3, lightComponent.gameObject.transform.position); localToWorldMatrix.SetColumn(2, lightComponent.transform.forward); localToWorldMatrix.SetColumn(1, lightComponent.transform.up); localToWorldMatrix.SetColumn(0, lightComponent.transform.right); visibleLight.localToWorldMatrix = localToWorldMatrix; visibleLight.spotAngle = lightComponent.spotAngle; int shadowIndex = additionalLightData.shadowIndex; int screenSpaceShadowIndex = -1; int screenSpaceChannelSlot = -1; Vector3 lightDimensions = new Vector3(0.0f, 0.0f, 0.0f); // Use the shared code to build the light data m_RenderPipeline.GetLightData(cmd, hdCamera, hdShadowSettings, visibleLight, lightComponent, in processedData, shadowIndex, contactShadowScalableSetting, isRasterization: false, ref lightDimensions, ref screenSpaceShadowIndex, ref screenSpaceChannelSlot, ref lightData); // We make the light position camera-relative as late as possible in order // to allow the preceding code to work with the absolute world space coordinates. Vector3 camPosWS = hdCamera.mainViewConstants.worldSpaceCameraPos; HDRenderPipeline.UpdateLightCameraRelativetData(ref lightData, camPosWS); // Set the data for this light m_LightDataCPUArray.Add(lightData); } // Push the data to the GPU m_LightDataGPUArray.SetData(m_LightDataCPUArray); }
void BuildLightData(CommandBuffer cmd, HDCamera hdCamera, HDRayTracingLights rayTracingLights, DebugDisplaySettings debugDisplaySettings) { // If no lights, exit if (rayTracingLights.lightCount == 0) { ResizeLightDataBuffer(1); return; } // Also we need to build the light list data if (m_LightDataGPUArray == null || m_LightDataGPUArray.count != rayTracingLights.lightCount) { ResizeLightDataBuffer(rayTracingLights.lightCount); } m_LightDataCPUArray.Clear(); // Grab the shadow settings var hdShadowSettings = hdCamera.volumeStack.GetComponent <HDShadowSettings>(); BoolScalableSetting contactShadowScalableSetting = HDAdditionalLightData.ScalableSettings.UseContactShadow(m_RenderPipeline.asset); // Build the data for every light HDLightRenderDatabase lightEntities = HDLightRenderDatabase.instance; var processedLightEntity = new HDProcessedVisibleLight() { shadowMapFlags = HDProcessedVisibleLightsBuilder.ShadowMapFlags.None }; var globalConfig = HDGpuLightsBuilder.CreateGpuLightDataJobGlobalConfig.Create(hdCamera, hdShadowSettings); var shadowInitParams = m_RenderPipeline.currentPlatformRenderPipelineSettings.hdShadowInitParams; for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightEntityArray.Count; ++lightIdx) { // Grab the additinal light data to process int dataIndex = lightEntities.GetEntityDataIndex(rayTracingLights.hdLightEntityArray[lightIdx]); HDAdditionalLightData additionalLightData = lightEntities.hdAdditionalLightData[dataIndex]; LightData lightData = new LightData(); // When the user deletes a light source in the editor, there is a single frame where the light is null before the collection of light in the scene is triggered // the workaround for this is simply to add an invalid light for that frame if (additionalLightData == null) { m_LightDataCPUArray.Add(lightData); continue; } // Evaluate all the light type data that we need LightCategory lightCategory = LightCategory.Count; GPULightType gpuLightType = GPULightType.Point; LightVolumeType lightVolumeType = LightVolumeType.Count; HDLightType lightType = additionalLightData.type; HDRenderPipeline.EvaluateGPULightType(lightType, additionalLightData.spotLightShape, additionalLightData.areaLightShape, ref lightCategory, ref gpuLightType, ref lightVolumeType); // Fetch the light component for this light additionalLightData.gameObject.TryGetComponent(out lightComponent); ref HDLightRenderData lightRenderData = ref lightEntities.GetLightDataAsRef(dataIndex); // Build the processed light data that we need processedLightEntity.dataIndex = dataIndex; processedLightEntity.gpuLightType = gpuLightType; processedLightEntity.lightType = additionalLightData.type; processedLightEntity.distanceToCamera = (additionalLightData.transform.position - hdCamera.camera.transform.position).magnitude; processedLightEntity.lightDistanceFade = HDUtils.ComputeLinearDistanceFade(processedLightEntity.distanceToCamera, lightRenderData.fadeDistance); processedLightEntity.lightVolumetricDistanceFade = HDUtils.ComputeLinearDistanceFade(processedLightEntity.distanceToCamera, lightRenderData.volumetricFadeDistance); processedLightEntity.isBakedShadowMask = HDRenderPipeline.IsBakedShadowMaskLight(lightComponent); // Build a visible light visibleLight.finalColor = LightUtils.EvaluateLightColor(lightComponent, additionalLightData); visibleLight.range = lightComponent.range; // This should be done explicitly, localToWorld matrix doesn't work here localToWorldMatrix.SetColumn(3, lightComponent.gameObject.transform.position); localToWorldMatrix.SetColumn(2, lightComponent.transform.forward); localToWorldMatrix.SetColumn(1, lightComponent.transform.up); localToWorldMatrix.SetColumn(0, lightComponent.transform.right); visibleLight.localToWorldMatrix = localToWorldMatrix; visibleLight.spotAngle = lightComponent.spotAngle; int shadowIndex = additionalLightData.shadowIndex; Vector3 lightDimensions = new Vector3(0.0f, 0.0f, 0.0f); // Use the shared code to build the light data HDGpuLightsBuilder.CreateGpuLightDataJob.ConvertLightToGPUFormat( lightCategory, gpuLightType, globalConfig, lightComponent.lightShadowCasterMode, lightComponent.bakingOutput, visibleLight, processedLightEntity, lightRenderData, out var _, ref lightData); m_RenderPipeline.gpuLightList.ProcessLightDataShadowIndex(cmd, shadowInitParams, lightType, lightComponent, additionalLightData, shadowIndex, ref lightData); // We make the light position camera-relative as late as possible in order // to allow the preceding code to work with the absolute world space coordinates. Vector3 camPosWS = hdCamera.mainViewConstants.worldSpaceCameraPos; HDRenderPipeline.UpdateLightCameraRelativetData(ref lightData, camPosWS); // Set the data for this light m_LightDataCPUArray.Add(lightData); }