internal bool LightIsPendingPlacement(HDAdditionalLightData light, ShadowMapType shadowMapType) { if (shadowMapType == ShadowMapType.PunctualAtlas) { return(punctualShadowAtlas.LightIsPendingPlacement(light)); } if (shadowMapType == ShadowMapType.AreaLightAtlas) { return(areaShadowAtlas.LightIsPendingPlacement(light)); } return(false); }
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 ReserveCookieAtlasSlots(HDRayTracingLights rayTracingLights) { for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightArray.Count; ++lightIdx) { // Grab the additional light data to process HDAdditionalLightData additionalLightData = rayTracingLights.hdLightArray[lightIdx]; // Fetch the light component for this light additionalLightData.gameObject.TryGetComponent(out lightComponent); // Reserve the cookie resolution in the 2D atlas m_RenderPipeline.ReserveCookieAtlasTexture(additionalLightData, lightComponent, additionalLightData.type); } }
internal bool FullLightShadowHasRenderedAtLeastOnce(HDAdditionalLightData lightData) { int cachedShadowIdx = lightData.lightIdxForCachedShadows; if (lightData.type == HDLightType.Point) { bool allRendered = true; for (int i = 0; i < 6; ++i) { allRendered = allRendered && m_ShadowsWithValidData.ContainsKey(cachedShadowIdx + i); } return(allRendered); } return(m_ShadowsWithValidData.ContainsKey(cachedShadowIdx)); }
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; } }
internal void ScheduleShadowUpdate(HDAdditionalLightData light) { var lightType = light.type; if (lightType == HDLightType.Point || lightType == HDLightType.Spot) { punctualShadowAtlas.ScheduleShadowUpdate(light); } else if (lightType == HDLightType.Area) { areaShadowAtlas.ScheduleShadowUpdate(light); } else if (lightType == HDLightType.Directional) { MarkAllDirectionalShadowsForUpdate(); } }
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); } }
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 RegisterLight(HDAdditionalLightData lightData) { // If we are trying to register something that we have already placed, we do nothing if (lightData.lightIdxForCachedShadows >= 0 && m_PlacedShadows.ContainsKey(lightData.lightIdxForCachedShadows)) { return; } // We register only if not already pending placement and if enabled. if (!m_RegisteredLightDataPendingPlacement.ContainsKey(lightData.lightIdxForCachedShadows) && lightData.isActiveAndEnabled) { #if UNITY_2020_2_OR_NEWER lightData.legacyLight.useViewFrustumForShadowCasterCull = false; #endif lightData.lightIdxForCachedShadows = GetNextLightIdentifier(); RegisterTransformCacheSlot(lightData); m_RegisteredLightDataPendingPlacement.Add(lightData.lightIdxForCachedShadows, lightData); m_CanTryPlacement = true; } }
bool RenderLightScreenSpaceShadows(HDCamera hdCamera, CommandBuffer cmd) { using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.RaytracingLightShadow))) { using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.RaytracingLightShadow))) { // Loop through all the potential screen space light shadows for (int lightIdx = 0; lightIdx < m_ScreenSpaceShadowIndex; ++lightIdx) { // This matches the directional light if (!m_CurrentScreenSpaceShadowData[lightIdx].valid) { continue; } // Fetch the light data and additional light data LightData currentLight = m_lightList.lights[m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex]; HDAdditionalLightData currentAdditionalLightData = m_CurrentScreenSpaceShadowData[lightIdx].additionalLightData; // Trigger the right algorithm based on the light type switch (currentLight.lightType) { case GPULightType.Rectangle: { RenderAreaScreenSpaceShadow(cmd, hdCamera, currentLight, currentAdditionalLightData, m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex); } break; case GPULightType.Point: case GPULightType.Spot: { RenderPunctualScreenSpaceShadow(cmd, hdCamera, currentLight, currentAdditionalLightData, m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex); } break; } } } return(true); } }
// We do our own hash here because Unity does not provide correct hash for builtin types // Moreover, we don't want to test every single parameters of the light so we filter them here in this specific function. int GetSunLightHashCode(Light light) { HDAdditionalLightData ald = light.GetComponent <HDAdditionalLightData>(); unchecked { // Sun could influence the sky (like for procedural sky). We need to handle this possibility. If sun property change, then we need to update the sky int hash = 13; hash = hash * 23 + light.transform.position.GetHashCode(); hash = hash * 23 + light.transform.rotation.GetHashCode(); hash = hash * 23 + light.color.GetHashCode(); hash = hash * 23 + light.colorTemperature.GetHashCode(); hash = hash * 23 + light.intensity.GetHashCode(); // Note: We don't take into account cookie as it doesn't influence GI if (ald != null) { hash = hash * 23 + ald.lightDimmer.GetHashCode(); } return(hash); } }
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); }
bool RenderLightScreenSpaceShadows(RenderGraph renderGraph, HDCamera hdCamera, PrepassOutput prepassOutput, TextureHandle depthBuffer, TextureHandle normalBuffer, TextureHandle motionVectorsBuffer, TextureHandle historyValidityBuffer, TextureHandle rayCountTexture, TextureHandle screenSpaceShadowArray) { // Loop through all the potential screen space light shadows for (int lightIdx = 0; lightIdx < m_ScreenSpaceShadowIndex; ++lightIdx) { // This matches the directional light if (!m_CurrentScreenSpaceShadowData[lightIdx].valid) { continue; } // Fetch the light data and additional light data LightData currentLight = m_GpuLightsBuilder.lights[m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex]; HDAdditionalLightData currentAdditionalLightData = m_CurrentScreenSpaceShadowData[lightIdx].additionalLightData; // Trigger the right algorithm based on the light type switch (currentLight.lightType) { case GPULightType.Rectangle: { RenderAreaScreenSpaceShadow(renderGraph, hdCamera, currentLight, currentAdditionalLightData, m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex, prepassOutput, depthBuffer, normalBuffer, motionVectorsBuffer, rayCountTexture, screenSpaceShadowArray); } break; case GPULightType.Point: case GPULightType.Spot: { RenderPunctualScreenSpaceShadow(renderGraph, hdCamera, currentLight, currentAdditionalLightData, m_CurrentScreenSpaceShadowData[lightIdx].lightDataIndex, prepassOutput, depthBuffer, normalBuffer, motionVectorsBuffer, historyValidityBuffer, rayCountTexture, screenSpaceShadowArray); } break; } } return(true); }
internal void ScheduleShadowUpdate(HDAdditionalLightData light, int subShadowIndex) { var lightType = light.type; if (lightType == HDLightType.Spot) { punctualShadowAtlas.ScheduleShadowUpdate(light); } if (lightType == HDLightType.Area) { areaShadowAtlas.ScheduleShadowUpdate(light); } if (lightType == HDLightType.Point) { Debug.Assert(subShadowIndex < 6); punctualShadowAtlas.ScheduleShadowUpdate(light.lightIdxForCachedShadows + subShadowIndex); } if (lightType == HDLightType.Directional) { Debug.Assert(subShadowIndex < m_MaxShadowCascades); m_DirectionalShadowPendingUpdate[subShadowIndex] = 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); }
void BuildGPULightVolumes(HDCamera hdCamera, HDRayTracingLights rayTracingLights) { int totalNumLights = rayTracingLights.lightCount; // Make sure the light volume buffer has the right size if (m_LightVolumesCPUArray == null || totalNumLights != m_LightVolumesCPUArray.Length) { ResizeVolumeBuffer(totalNumLights); } // Set Light volume data to the CPU buffer punctualLightCount = 0; areaLightCount = 0; envLightCount = 0; totalLightCount = 0; int realIndex = 0; for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightArray.Count; ++lightIdx) { HDAdditionalLightData currentLight = 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 not add it if it is null for that invalid frame if (currentLight != null) { Light light = currentLight.gameObject.GetComponent <Light>(); if (light == null || !light.enabled) { continue; } if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && !currentLight.includeForRayTracing) { continue; } // Reserve space in the cookie atlas m_RenderPipeline.ReserveCookieAtlasTexture(currentLight, light, currentLight.type); // Compute the camera relative position Vector3 lightPositionRWS = currentLight.gameObject.transform.position; if (ShaderConfig.s_CameraRelativeRendering != 0) { lightPositionRWS -= hdCamera.camera.transform.position; } // Grab the light range float lightRange = light.range; if (currentLight.type != HDLightType.Area) { m_LightVolumesCPUArray[realIndex].range = new Vector3(lightRange, lightRange, lightRange); m_LightVolumesCPUArray[realIndex].position = lightPositionRWS; m_LightVolumesCPUArray[realIndex].active = (currentLight.gameObject.activeInHierarchy ? 1 : 0); m_LightVolumesCPUArray[realIndex].lightIndex = (uint)lightIdx; m_LightVolumesCPUArray[realIndex].shape = 0; m_LightVolumesCPUArray[realIndex].lightType = 0; punctualLightCount++; } else { // let's compute the oobb of the light influence volume first Vector3 oobbDimensions = new Vector3(currentLight.shapeWidth + 2 * lightRange, currentLight.shapeHeight + 2 * lightRange, lightRange); // One-sided Vector3 extents = 0.5f * oobbDimensions; Vector3 oobbCenter = lightPositionRWS + extents.z * currentLight.gameObject.transform.forward; // Let's now compute an AABB that matches the previously defined OOBB OOBBToAABBBounds(oobbCenter, extents, currentLight.gameObject.transform.up, currentLight.gameObject.transform.right, currentLight.gameObject.transform.forward, ref bounds); // Fill the volume data m_LightVolumesCPUArray[realIndex].range = bounds.extents; m_LightVolumesCPUArray[realIndex].position = bounds.center; m_LightVolumesCPUArray[realIndex].active = (currentLight.gameObject.activeInHierarchy ? 1 : 0); m_LightVolumesCPUArray[realIndex].lightIndex = (uint)lightIdx; m_LightVolumesCPUArray[realIndex].shape = 1; m_LightVolumesCPUArray[realIndex].lightType = 1; areaLightCount++; } realIndex++; } } int indexOffset = realIndex; // Set Env Light volume data to the CPU buffer for (int lightIdx = 0; lightIdx < rayTracingLights.reflectionProbeArray.Count; ++lightIdx) { HDProbe currentEnvLight = rayTracingLights.reflectionProbeArray[lightIdx]; // Compute the camera relative position Vector3 probePositionRWS = currentEnvLight.influenceToWorld.GetColumn(3); if (ShaderConfig.s_CameraRelativeRendering != 0) { probePositionRWS -= hdCamera.camera.transform.position; } if (currentEnvLight != null) { if (currentEnvLight.influenceVolume.shape == InfluenceShape.Sphere) { m_LightVolumesCPUArray[lightIdx + indexOffset].shape = 0; m_LightVolumesCPUArray[lightIdx + indexOffset].range = new Vector3(currentEnvLight.influenceVolume.sphereRadius, currentEnvLight.influenceVolume.sphereRadius, currentEnvLight.influenceVolume.sphereRadius); m_LightVolumesCPUArray[lightIdx + indexOffset].position = probePositionRWS; } else { m_LightVolumesCPUArray[lightIdx + indexOffset].shape = 1; m_LightVolumesCPUArray[lightIdx + indexOffset].range = new Vector3(currentEnvLight.influenceVolume.boxSize.x / 2.0f, currentEnvLight.influenceVolume.boxSize.y / 2.0f, currentEnvLight.influenceVolume.boxSize.z / 2.0f); m_LightVolumesCPUArray[lightIdx + indexOffset].position = probePositionRWS; } m_LightVolumesCPUArray[lightIdx + indexOffset].active = (currentEnvLight.gameObject.activeInHierarchy ? 1 : 0); m_LightVolumesCPUArray[lightIdx + indexOffset].lightIndex = (uint)lightIdx; m_LightVolumesCPUArray[lightIdx + indexOffset].lightType = 2; envLightCount++; } } totalLightCount = punctualLightCount + areaLightCount + envLightCount; // Push the light volumes to the GPU m_LightVolumeGPUArray.SetData(m_LightVolumesCPUArray); }
internal bool LightIsPlaced(HDAdditionalLightData lightData) { int cachedShadowIdx = lightData.lightIdxForCachedShadows; return(cachedShadowIdx >= 0 && m_PlacedShadows.ContainsKey(cachedShadowIdx)); }
void GetLightGPUType(HDAdditionalLightData additionalData, Light light, ref GPULightType gpuLightType, ref LightCategory lightCategory) { lightCategory = LightCategory.Count; gpuLightType = GPULightType.Point; if (additionalData.lightTypeExtent == LightTypeExtent.Punctual) { lightCategory = LightCategory.Punctual; switch (light.type) { case LightType.Spot: switch (additionalData.spotLightShape) { case SpotLightShape.Cone: gpuLightType = GPULightType.Spot; break; case SpotLightShape.Pyramid: gpuLightType = GPULightType.ProjectorPyramid; break; case SpotLightShape.Box: gpuLightType = GPULightType.ProjectorBox; break; default: Debug.Assert(false, "Encountered an unknown SpotLightShape."); break; } break; case LightType.Directional: gpuLightType = GPULightType.Directional; break; case LightType.Point: gpuLightType = GPULightType.Point; break; default: Debug.Assert(false, "Encountered an unknown LightType."); break; } } else { lightCategory = LightCategory.Area; switch (additionalData.lightTypeExtent) { case LightTypeExtent.Rectangle: gpuLightType = GPULightType.Rectangle; break; case LightTypeExtent.Tube: gpuLightType = GPULightType.Tube; break; default: Debug.Assert(false, "Encountered an unknown LightType."); break; } } }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ // Functions to query and change state of a shadow // ------------------------------------------------------------------------------------------ internal bool LightIsPendingPlacement(HDAdditionalLightData lightData) { return(m_RegisteredLightDataPendingPlacement.ContainsKey(lightData.lightIdxForCachedShadows) || m_RecordsPendingPlacement.ContainsKey(lightData.lightIdxForCachedShadows)); }
internal void RemoveTransformFromCache(HDAdditionalLightData lightData) { m_TransformCaches.Remove(lightData.lightIdxForCachedShadows); }
TextureHandle DenoisePunctualScreenSpaceShadow(RenderGraph renderGraph, HDCamera hdCamera, HDAdditionalLightData additionalLightData, in LightData lightData,
/// <summary> /// This function can be used to register a light to the cached shadow system if not already registered. It is necessary to call this function if a light has been /// evicted with ForceEvictLight and it needs to be registered again. Please note that a light is automatically registered when enabled or when the shadow update changes /// from EveryFrame to OnDemand or OnEnable. /// </summary> /// <param name="lightData">The light to register.</param> public void ForceRegisterLight(HDAdditionalLightData lightData) { // Note: this is for now just calling the internal API, but having a separate API helps with future // changes to the process. RegisterLight(lightData); }
/// <summary> /// This hook allows HDRP to init the scene when creating the view /// </summary> /// <param name="SRI">The StageRuntimeInterface allowing to communicate with the LookDev</param> void IDataProvider.FirstInitScene(StageRuntimeInterface SRI) { Camera camera = SRI.camera; camera.allowHDR = true; var additionalCameraData = camera.gameObject.AddComponent <HDAdditionalCameraData>(); additionalCameraData.clearColorMode = HDAdditionalCameraData.ClearColorMode.Color; additionalCameraData.clearDepth = true; additionalCameraData.backgroundColorHDR = camera.backgroundColor; additionalCameraData.volumeAnchorOverride = camera.transform; additionalCameraData.volumeLayerMask = 1 << 31; //31 is the culling layer used in LookDev additionalCameraData.customRenderingSettings = true; additionalCameraData.renderingPathCustomFrameSettings.SetEnabled(FrameSettingsField.SSR, false); // LookDev cameras are enabled/disabled all the time so history is destroyed each frame. // In this case we know we want to keep history alive as long as the camera is. additionalCameraData.hasPersistentHistory = true; Light light = SRI.sunLight; HDAdditionalLightData additionalLightData = light.gameObject.AddComponent <HDAdditionalLightData>(); #if UNITY_EDITOR HDAdditionalLightData.InitDefaultHDAdditionalLightData(additionalLightData); #endif additionalLightData.intensity = 0f; additionalLightData.SetShadowResolution(2048); GameObject volumeGO = SRI.AddGameObject(persistent: true); volumeGO.name = "StageVolume"; Volume volume = volumeGO.AddComponent <Volume>(); volume.isGlobal = true; volume.priority = float.MaxValue; volume.enabled = false; #if UNITY_EDITOR // Make sure we invalidate the current volume when first loading a scene. int volumeProfileHash = -1; UpdateVolumeProfile(volume, out var visualEnvironment, out var sky, ref volumeProfileHash); SRI.SRPData = new LookDevDataForHDRP() { additionalCameraData = additionalCameraData, additionalLightData = additionalLightData, visualEnvironment = visualEnvironment, sky = sky, volume = volume, currentVolumeProfileHash = volumeProfileHash }; #else //remove unassigned warnings when building SRI.SRPData = new LookDevDataForHDRP() { additionalCameraData = null, additionalLightData = null, visualEnvironment = null, sky = null, volume = null }; #endif }
public void BuildSubSceneStructure(ref HDRayTracingSubScene subScene) { // If there is no render environments, then we should not generate acceleration structure if (m_Environments.Count > 0) { // This structure references all the renderers that are considered to be processed Dictionary <int, int> rendererReference = new Dictionary <int, int>(); // Destroy the acceleration structure subScene.targetRenderers = new List <Renderer>(); // Create the acceleration structure subScene.accelerationStructure = new Experimental.Rendering.RayTracingAccelerationStructure(); // We need to define the maximal number of meshes for our geometries int maxNumSubMeshes = 1; // First of all let's process all the LOD groups LODGroup[] lodGroupArray = UnityEngine.GameObject.FindObjectsOfType <LODGroup>(); for (var i = 0; i < lodGroupArray.Length; i++) { // Grab the current LOD group LODGroup lodGroup = lodGroupArray[i]; // Get the set of LODs LOD[] lodArray = lodGroup.GetLODs(); for (int lodIdx = 0; lodIdx < lodArray.Length; ++lodIdx) { LOD currentLOD = lodArray[lodIdx]; // We only want to push to the acceleration structure the first fella if (lodIdx == 0) { for (int rendererIdx = 0; rendererIdx < currentLOD.renderers.Length; ++rendererIdx) { // Convert the object's layer to an int int objectLayerValue = 1 << currentLOD.renderers[rendererIdx].gameObject.layer; // Is this object in one of the allowed layers ? if ((objectLayerValue & subScene.mask.value) != 0) { Renderer currentRenderer = currentLOD.renderers[rendererIdx]; // Add this fella to the renderer list subScene.targetRenderers.Add(currentRenderer); // Also, we need to contribute to the maximal number of sub-meshes MeshFilter currentFilter = currentRenderer.GetComponent <MeshFilter>(); if (currentFilter != null && currentFilter.sharedMesh != null) { maxNumSubMeshes = Mathf.Max(maxNumSubMeshes, currentFilter.sharedMesh.subMeshCount); } } } } // Add them to the processed set for (int rendererIdx = 0; rendererIdx < currentLOD.renderers.Length; ++rendererIdx) { Renderer currentRenderer = currentLOD.renderers[rendererIdx]; // Add this fella to the renderer list rendererReference.Add(currentRenderer.GetInstanceID(), 1); } } } // Grab all the renderers from the scene var rendererArray = UnityEngine.GameObject.FindObjectsOfType <Renderer>(); for (var i = 0; i < rendererArray.Length; i++) { // Fetch the current renderer Renderer currentRenderer = rendererArray[i]; // If it is not active skip it if (currentRenderer.enabled == false) { continue; } // Grab the current game object GameObject gameObject = currentRenderer.gameObject; // Has this object already been processed, jsut skip if (rendererReference.ContainsKey(currentRenderer.GetInstanceID())) { continue; } // Does this object have a reflection probe component? if yes we do not want to see it in the raytracing environment ReflectionProbe targetProbe = gameObject.GetComponent <ReflectionProbe>(); if (targetProbe != null) { continue; } // Convert the object's layer to an int int objectLayerValue = 1 << currentRenderer.gameObject.layer; // Is this object in one of the allowed layers ? if ((objectLayerValue & subScene.mask.value) != 0) { // Add this fella to the renderer list subScene.targetRenderers.Add(currentRenderer); } // Also, we need to contribute to the maximal number of sub-meshes MeshFilter currentFilter = currentRenderer.GetComponent <MeshFilter>(); if (currentFilter != null && currentFilter.sharedMesh != null) { maxNumSubMeshes = Mathf.Max(maxNumSubMeshes, currentFilter.sharedMesh.subMeshCount); } } bool[] subMeshFlagArray = new bool[maxNumSubMeshes]; bool[] subMeshCutoffArray = new bool[maxNumSubMeshes]; // If any object build the acceleration structure if (subScene.targetRenderers.Count != 0) { // For all the renderers that we need to push in the acceleration structure for (var i = 0; i < subScene.targetRenderers.Count; i++) { // Grab the current renderer Renderer currentRenderer = subScene.targetRenderers[i]; bool singleSided = false; if (currentRenderer.sharedMaterials != null) { // For every sub-mesh/sub-material let's build the right flags int numSubMeshes = currentRenderer.sharedMaterials.Length; // We need to build the instance flag for this renderer uint instanceFlag = 0x00; // Incorporate the shadow casting flag instanceFlag |= ((currentRenderer.shadowCastingMode == ShadowCastingMode.On) ? (uint)(1 << 2) : 0x00); for (int meshIdx = 0; meshIdx < numSubMeshes; ++meshIdx) { Material currentMaterial = currentRenderer.sharedMaterials[meshIdx]; // The material is transparent if either it has the requested keyword or is in the transparent queue range if (currentMaterial != null) { subMeshFlagArray[meshIdx] = true; // Is the material transparent? bool materialIsTransparent = currentMaterial.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT") || (HDRenderQueue.k_RenderQueue_Transparent.lowerBound <= currentMaterial.renderQueue && HDRenderQueue.k_RenderQueue_Transparent.upperBound >= currentMaterial.renderQueue) || (HDRenderQueue.k_RenderQueue_AllTransparentRaytracing.lowerBound <= currentMaterial.renderQueue && HDRenderQueue.k_RenderQueue_AllTransparentRaytracing.upperBound >= currentMaterial.renderQueue); // Propagate the right mask instanceFlag |= materialIsTransparent ? (uint)(1 << 1) : (uint)(1 << 0); // Is the material alpha tested? subMeshCutoffArray[meshIdx] = currentMaterial.IsKeywordEnabled("_ALPHATEST_ON") || (HDRenderQueue.k_RenderQueue_OpaqueAlphaTest.lowerBound <= currentMaterial.renderQueue && HDRenderQueue.k_RenderQueue_OpaqueAlphaTest.upperBound >= currentMaterial.renderQueue); // Force it to be non single sided if it has the keyword if there is a reason bool doubleSided = currentMaterial.doubleSidedGI || currentMaterial.IsKeywordEnabled("_DOUBLESIDED_ON"); singleSided |= !doubleSided; } else { subMeshFlagArray[meshIdx] = false; subMeshCutoffArray[meshIdx] = false; singleSided = true; } } // Add it to the acceleration structure subScene.accelerationStructure.AddInstance(currentRenderer, subMeshMask: subMeshFlagArray, subMeshTransparencyFlags: subMeshCutoffArray, enableTriangleCulling: singleSided, mask: instanceFlag); } } } // build the acceleration structure subScene.accelerationStructure.Build(); // Allocate the array for the lights subScene.lights = new HDRayTracingLights(); subScene.lights.hdLightArray = new List <HDAdditionalLightData>(); subScene.lights.hdDirectionalLightArray = new List <HDAdditionalLightData>(); // fetch all the lights HDAdditionalLightData[] hdLightArray = UnityEngine.GameObject.FindObjectsOfType <HDAdditionalLightData>(); // Here an important thing is to make sure that the point lights are first in the list then line then area List <HDAdditionalLightData> pointLights = new List <HDAdditionalLightData>(); List <HDAdditionalLightData> lineLights = new List <HDAdditionalLightData>(); List <HDAdditionalLightData> rectLights = new List <HDAdditionalLightData>(); for (int lightIdx = 0; lightIdx < hdLightArray.Length; ++lightIdx) { HDAdditionalLightData hdLight = hdLightArray[lightIdx]; if (hdLight.enabled) { // Convert the object's layer to an int int lightayerValue = 1 << hdLight.gameObject.layer; if ((lightayerValue & subScene.mask.value) != 0) { if (hdLight.GetComponent <Light>().type == LightType.Directional) { subScene.lights.hdDirectionalLightArray.Add(hdLight); } else { if (hdLight.lightTypeExtent == LightTypeExtent.Punctual) { pointLights.Add(hdLight); } else if (hdLight.lightTypeExtent == LightTypeExtent.Tube) { lineLights.Add(hdLight); } else { rectLights.Add(hdLight); } } } } } subScene.lights.hdLightArray.AddRange(pointLights); subScene.lights.hdLightArray.AddRange(lineLights); subScene.lights.hdLightArray.AddRange(rectLights); // Fetch all the reflection probes in the scene subScene.lights.reflectionProbeArray = new List <HDProbe>(); HDAdditionalReflectionData[] reflectionProbeArray = UnityEngine.GameObject.FindObjectsOfType <HDAdditionalReflectionData>(); for (int reflIdx = 0; reflIdx < reflectionProbeArray.Length; ++reflIdx) { HDAdditionalReflectionData reflectionProbe = reflectionProbeArray[reflIdx]; // Add it to the list if enabled if (reflectionProbe.enabled) { subScene.lights.reflectionProbeArray.Add(reflectionProbe); } } // Build the light cluster subScene.lightCluster = new HDRaytracingLightCluster(); subScene.lightCluster.Initialize(m_Resources, m_RTResources, this, m_SharedRTManager, m_RenderPipeline); // Mark this sub-scene as valid subScene.valid = true; } else { subScene.valid = false; } }
RTSAreaRayTraceParameters PrepareRTSAreaRayTraceParameters(HDCamera hdCamera, HDAdditionalLightData additionalLightData, LightData lightData, int lightIndex) { RTSAreaRayTraceParameters rtsartParams = new RTSAreaRayTraceParameters(); // Set the camera parameters rtsartParams.texWidth = hdCamera.actualWidth; rtsartParams.texHeight = hdCamera.actualHeight; rtsartParams.viewCount = hdCamera.viewCount; // Evaluation parameters rtsartParams.numSamples = additionalLightData.numRayTracingSamples; rtsartParams.lightIndex = lightIndex; // We need to build the world to area light matrix rtsartParams.worldToLocalMatrix.SetColumn(0, lightData.right); rtsartParams.worldToLocalMatrix.SetColumn(1, lightData.up); rtsartParams.worldToLocalMatrix.SetColumn(2, lightData.forward); // Compensate the relative rendering if active Vector3 lightPositionWS = lightData.positionRWS; if (ShaderConfig.s_CameraRelativeRendering != 0) { lightPositionWS -= hdCamera.camera.transform.position; } rtsartParams.worldToLocalMatrix.SetColumn(3, lightPositionWS); rtsartParams.worldToLocalMatrix.m33 = 1.0f; rtsartParams.worldToLocalMatrix = m_WorldToLocalArea.inverse; rtsartParams.historyValidity = EvaluateHistoryValidity(hdCamera); rtsartParams.filterTracedShadow = additionalLightData.filterTracedShadow; rtsartParams.areaShadowSlot = m_lightList.lights[lightIndex].screenSpaceShadowIndex; rtsartParams.filterSize = additionalLightData.filterSizeTraced; // Kernels rtsartParams.areaRaytracingShadowPrepassKernel = m_AreaRaytracingShadowPrepassKernel; rtsartParams.areaRaytracingShadowNewSampleKernel = m_AreaRaytracingShadowNewSampleKernel; rtsartParams.areaShadowApplyTAAKernel = m_AreaShadowApplyTAAKernel; rtsartParams.areaUpdateAnalyticHistoryKernel = m_AreaUpdateAnalyticHistoryKernel; rtsartParams.areaUpdateShadowHistoryKernel = m_AreaUpdateShadowHistoryKernel; rtsartParams.areaEstimateNoiseKernel = m_AreaEstimateNoiseKernel; rtsartParams.areaFirstDenoiseKernel = m_AreaFirstDenoiseKernel; rtsartParams.areaSecondDenoiseKernel = m_AreaSecondDenoiseKernel; rtsartParams.areaShadowNoDenoiseKernel = m_AreaShadowNoDenoiseKernel; // Other parameters // Grab the acceleration structure for the target camera rtsartParams.accelerationStructure = RequestAccelerationStructure(); rtsartParams.shaderVariablesRayTracingCB = m_ShaderVariablesRayTracingCB; rtsartParams.screenSpaceShadowsCS = m_ScreenSpaceShadowsCS; rtsartParams.screenSpaceShadowsRT = m_ScreenSpaceShadowsRT; rtsartParams.screenSpaceShadowsFilterCS = m_ScreenSpaceShadowsFilterCS; rtsartParams.scramblingTex = m_Asset.renderPipelineResources.textures.scramblingTex; BlueNoise blueNoise = GetBlueNoiseManager(); rtsartParams.ditheredTextureSet = blueNoise.DitheredTextureSet8SPP(); return(rtsartParams); }
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; }
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, List <HDAdditionalLightData> lightArray) { // If no lights, exit if (lightArray.Count == 0) { ResizeLightDataBuffer(1); return; } // Also we need to build the light list data if (m_LightDataGPUArray == null || m_LightDataGPUArray.count != lightArray.Count) { ResizeLightDataBuffer(lightArray.Count); } m_LightDataCPUArray.Clear(); // Build the data for every light for (int lightIdx = 0; lightIdx < lightArray.Count; ++lightIdx) { var lightData = new LightData(); HDAdditionalLightData additionalLightData = lightArray[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; GetLightGPUType(additionalLightData, light, ref gpuLightType, ref lightCategory); 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; 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 (light.type) { case LightType.Spot: lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.cookieTexArray.FetchSlice(cmd, light.cookie); break; case LightType.Point: lightData.cookieIndex = m_RenderPipeline.m_TextureCaches.cubeCookieTexArray.FetchSlice(cmd, light.cookie); break; } } else if (light.type == LightType.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); }
internal void BuildRayTracingAccelerationStructure(HDCamera hdCamera) { // Clear all the per frame-data m_RayTracingRendererReference.Clear(); m_RayTracingLights.hdDirectionalLightArray.Clear(); m_RayTracingLights.hdPointLightArray.Clear(); m_RayTracingLights.hdLineLightArray.Clear(); m_RayTracingLights.hdRectLightArray.Clear(); m_RayTracingLights.hdLightArray.Clear(); m_RayTracingLights.reflectionProbeArray.Clear(); m_RayTracingLights.lightCount = 0; m_CurrentRAS.Dispose(); m_CurrentRAS = new RayTracingAccelerationStructure(); m_ValidRayTracingState = false; m_ValidRayTracingCluster = false; m_ValidRayTracingClusterCulling = false; m_RayTracedShadowsRequired = false; m_RayTracedContactShadowsRequired = false; // If the camera does not have a ray tracing frame setting // or it is a preview camera (due to the fact that the sphere does not exist as a game object we can't create the RTAS) // we do not want to build a RTAS if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) || hdCamera.camera.cameraType == CameraType.Preview) { return; } // We only support ray traced shadows if the camera supports ray traced shadows bool screenSpaceShadowsSupported = hdCamera.frameSettings.IsEnabled(FrameSettingsField.ScreenSpaceShadows); // fetch all the lights in the scene HDAdditionalLightData[] hdLightArray = UnityEngine.GameObject.FindObjectsOfType <HDAdditionalLightData>(); for (int lightIdx = 0; lightIdx < hdLightArray.Length; ++lightIdx) { HDAdditionalLightData hdLight = hdLightArray[lightIdx]; if (hdLight.enabled) { // Check if there is a ray traced shadow in the scene m_RayTracedShadowsRequired |= (hdLight.useRayTracedShadows && screenSpaceShadowsSupported); m_RayTracedContactShadowsRequired |= (hdLight.useContactShadow.@override && hdLight.rayTraceContactShadow); switch (hdLight.type) { case HDLightType.Directional: m_RayTracingLights.hdDirectionalLightArray.Add(hdLight); break; case HDLightType.Point: case HDLightType.Spot: m_RayTracingLights.hdPointLightArray.Add(hdLight); break; case HDLightType.Area: switch (hdLight.areaLightShape) { case AreaLightShape.Rectangle: m_RayTracingLights.hdRectLightArray.Add(hdLight); break; case AreaLightShape.Tube: m_RayTracingLights.hdLineLightArray.Add(hdLight); break; //TODO: case AreaLightShape.Disc: } break; } } } // Aggregate the shadow requirement bool rayTracedShadows = m_RayTracedShadowsRequired || m_RayTracedContactShadowsRequired; m_RayTracingLights.hdLightArray.AddRange(m_RayTracingLights.hdPointLightArray); m_RayTracingLights.hdLightArray.AddRange(m_RayTracingLights.hdLineLightArray); m_RayTracingLights.hdLightArray.AddRange(m_RayTracingLights.hdRectLightArray); HDAdditionalReflectionData[] reflectionProbeArray = UnityEngine.GameObject.FindObjectsOfType <HDAdditionalReflectionData>(); for (int reflIdx = 0; reflIdx < reflectionProbeArray.Length; ++reflIdx) { HDAdditionalReflectionData reflectionProbe = reflectionProbeArray[reflIdx]; // Add it to the list if enabled if (reflectionProbe.enabled) { m_RayTracingLights.reflectionProbeArray.Add(reflectionProbe); } } m_RayTracingLights.lightCount = m_RayTracingLights.hdPointLightArray.Count + m_RayTracingLights.hdLineLightArray.Count + m_RayTracingLights.hdRectLightArray.Count + m_RayTracingLights.reflectionProbeArray.Count; AmbientOcclusion aoSettings = hdCamera.volumeStack.GetComponent <AmbientOcclusion>(); bool rtAOEnabled = aoSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSAO); ScreenSpaceReflection reflSettings = hdCamera.volumeStack.GetComponent <ScreenSpaceReflection>(); bool rtREnabled = reflSettings.enabled.value && reflSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSR); GlobalIllumination giSettings = hdCamera.volumeStack.GetComponent <GlobalIllumination>(); bool rtGIEnabled = giSettings.enable.value && giSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSGI); RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent <RecursiveRendering>(); bool rrEnabled = recursiveSettings.enable.value; SubSurfaceScattering sssSettings = hdCamera.volumeStack.GetComponent <SubSurfaceScattering>(); bool rtSSSEnabled = sssSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SubsurfaceScattering); PathTracing pathTracingSettings = hdCamera.volumeStack.GetComponent <PathTracing>(); bool ptEnabled = pathTracingSettings.enable.value; // We need to check if we should be building the ray tracing acceleration structure (if required by any effect) bool rayTracingRequired = rtAOEnabled || rtREnabled || rtGIEnabled || rrEnabled || rtSSSEnabled || ptEnabled || rayTracedShadows; if (!rayTracingRequired) { return; } // We need to process the emissive meshes of the rectangular area lights for (var i = 0; i < m_RayTracingLights.hdRectLightArray.Count; i++) { // Fetch the current renderer of the rectangular area light (if any) MeshRenderer currentRenderer = m_RayTracingLights.hdRectLightArray[i].emissiveMeshRenderer; // If there is none it means that there is no emissive mesh for this light if (currentRenderer == null) { continue; } // This objects should be included into the RAS AddInstanceToRAS(currentRenderer, rayTracedShadows, rtAOEnabled, aoSettings.layerMask.value, rtREnabled, reflSettings.layerMask.value, rtGIEnabled, giSettings.layerMask.value, rrEnabled, recursiveSettings.layerMask.value, ptEnabled, pathTracingSettings.layerMask.value); } int matCount = m_MaterialCRCs.Count; LODGroup[] lodGroupArray = UnityEngine.GameObject.FindObjectsOfType <LODGroup>(); for (var i = 0; i < lodGroupArray.Length; i++) { // Grab the current LOD group LODGroup lodGroup = lodGroupArray[i]; // Get the set of LODs LOD[] lodArray = lodGroup.GetLODs(); for (int lodIdx = 0; lodIdx < lodArray.Length; ++lodIdx) { LOD currentLOD = lodArray[lodIdx]; // We only want to push to the acceleration structure the lod0, we do not have defined way to select the right LOD at the moment if (lodIdx == 0) { for (int rendererIdx = 0; rendererIdx < currentLOD.renderers.Length; ++rendererIdx) { // Fetch the renderer that we are interested in Renderer currentRenderer = currentLOD.renderers[rendererIdx]; // This objects should but included into the RAS AddInstanceToRAS(currentRenderer, rayTracedShadows, aoSettings.rayTracing.value, aoSettings.layerMask.value, reflSettings.rayTracing.value, reflSettings.layerMask.value, giSettings.rayTracing.value, giSettings.layerMask.value, recursiveSettings.enable.value, recursiveSettings.layerMask.value, pathTracingSettings.enable.value, pathTracingSettings.layerMask.value); } } // Add them to the processed set so that they are not taken into account when processing all the renderers for (int rendererIdx = 0; rendererIdx < currentLOD.renderers.Length; ++rendererIdx) { Renderer currentRenderer = currentLOD.renderers[rendererIdx]; // Add this fella to the renderer list // Unfortunately, we need to check that this renderer was not already pushed into the list (happens if the user uses the same mesh renderer // for two LODs) if (!m_RayTracingRendererReference.ContainsKey(currentRenderer.GetInstanceID())) { m_RayTracingRendererReference.Add(currentRenderer.GetInstanceID(), 1); } } } } // Grab all the renderers from the scene var rendererArray = UnityEngine.GameObject.FindObjectsOfType <Renderer>(); for (var i = 0; i < rendererArray.Length; i++) { // Fetch the current renderer Renderer currentRenderer = rendererArray[i]; // If it is not active skip it if (currentRenderer.enabled == false) { continue; } // Grab the current game object GameObject gameObject = currentRenderer.gameObject; // Has this object already been processed, just skip it if (m_RayTracingRendererReference.ContainsKey(currentRenderer.GetInstanceID())) { continue; } // Does this object have a reflection probe component? if yes we do not want to have it in the acceleration structure if (gameObject.TryGetComponent <ReflectionProbe>(out reflectionProbe)) { continue; } // This objects should be included into the RAS AddInstanceToRAS(currentRenderer, rayTracedShadows, aoSettings.rayTracing.value, aoSettings.layerMask.value, reflSettings.rayTracing.value, reflSettings.layerMask.value, giSettings.rayTracing.value, giSettings.layerMask.value, recursiveSettings.enable.value, recursiveSettings.layerMask.value, pathTracingSettings.enable.value, pathTracingSettings.layerMask.value); } // Check if the amount of materials being tracked has changed m_MaterialsDirty |= (matCount != m_MaterialCRCs.Count); // build the acceleration structure m_CurrentRAS.Build(); // tag the structures as valid m_ValidRayTracingState = true; }
/// <summary> /// This function can be used to evict a light from its atlas. The slots occupied by such light will be available to be occupied by other shadows. /// Note that eviction happens automatically upon light destruction and, if lightData.preserveCachedShadow is false, upon disabling of the light. /// </summary> /// <param name="lightData">The light to evict from the atlas.</param> public void ForceEvictLight(HDAdditionalLightData lightData) { EvictLight(lightData); lightData.lightIdxForCachedShadows = -1; }