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; HDLightRenderDatabase lightEntities = HDLightRenderDatabase.instance; for (int lightIdx = 0; lightIdx < rayTracingLights.hdLightEntityArray.Count; ++lightIdx) { int dataIndex = lightEntities.GetEntityDataIndex(rayTracingLights.hdLightEntityArray[lightIdx]); HDAdditionalLightData currentLight = lightEntities.hdAdditionalLightData[dataIndex]; // 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 the light is flagged as baked and has been effectively been baked, we need to skip it and not add it to the light cluster if (light.bakingOutput.lightmapBakeType == LightmapBakeType.Baked && light.bakingOutput.isBaked) { continue; } // If this light should not be included when ray tracing is active on the camera, skip it 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]; if (currentEnvLight != null) { // If the reflection probe is disabled, we should not be adding it if (!currentEnvLight.enabled) { continue; } // If the reflection probe is not baked yet. if (!currentEnvLight.HasValidRenderedData()) { continue; } // Compute the camera relative position Vector3 probePositionRWS = currentEnvLight.influenceToWorld.GetColumn(3); if (ShaderConfig.s_CameraRelativeRendering != 0) { probePositionRWS -= hdCamera.camera.transform.position; } 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); }
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); }
void CollectLightsForRayTracing(HDCamera hdCamera, ref bool transformDirty) { // fetch all the lights in the scene HDLightRenderDatabase lightEntities = HDLightRenderDatabase.instance; for (int lightIdx = 0; lightIdx < lightEntities.lightCount; ++lightIdx) { HDLightRenderEntity lightRenderEntity = lightEntities.lightEntities[lightIdx]; HDAdditionalLightData hdLight = lightEntities.hdAdditionalLightData[lightIdx]; if (hdLight != null && hdLight.enabled && hdLight != HDUtils.s_DefaultHDAdditionalLightData) { // Flag that needs to be overriden by the light and tells us if the light will need the RTAS bool hasRayTracedShadows = false; // Indicates that a transform has changed in our scene (mesh or light) transformDirty |= hdLight.transform.hasChanged; hdLight.transform.hasChanged = false; switch (hdLight.type) { case HDLightType.Directional: { hasRayTracedShadows = hdLight.ShadowsEnabled() && hdLight.useScreenSpaceShadows && hdLight.useRayTracedShadows; m_RayTracingLights.hdDirectionalLightArray.Add(hdLight); } break; case HDLightType.Point: case HDLightType.Spot: { hasRayTracedShadows = hdLight.ShadowsEnabled() && hdLight.useRayTracedShadows; m_RayTracingLights.hdPointLightArray.Add(lightRenderEntity); } break; case HDLightType.Area: { hasRayTracedShadows = hdLight.ShadowsEnabled() && hdLight.useRayTracedShadows; switch (hdLight.areaLightShape) { case AreaLightShape.Rectangle: m_RayTracingLights.hdRectLightArray.Add(lightRenderEntity); break; case AreaLightShape.Tube: m_RayTracingLights.hdLineLightArray.Add(lightRenderEntity); break; //TODO: case AreaLightShape.Disc: } break; } } // Check if there is a ray traced shadow in the scene m_RayTracedShadowsRequired |= hasRayTracedShadows; m_RayTracedContactShadowsRequired |= (hdLight.useContactShadow.@override && hdLight.rayTraceContactShadow); } } // Add the lights to the structure m_RayTracingLights.hdLightEntityArray.AddRange(m_RayTracingLights.hdPointLightArray); m_RayTracingLights.hdLightEntityArray.AddRange(m_RayTracingLights.hdLineLightArray); m_RayTracingLights.hdLightEntityArray.AddRange(m_RayTracingLights.hdRectLightArray); // Process the lights 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 // Skip the probe if the probe has never rendered (in real time cases) or if texture is null if (reflectionProbe != null && reflectionProbe.enabled && reflectionProbe.ReflectionProbeIsEnabled() && reflectionProbe.gameObject.activeSelf && reflectionProbe.HasValidRenderedData()) { m_RayTracingLights.reflectionProbeArray.Add(reflectionProbe); } } m_RayTracingLights.lightCount = m_RayTracingLights.hdPointLightArray.Count + m_RayTracingLights.hdLineLightArray.Count + m_RayTracingLights.hdRectLightArray.Count + m_RayTracingLights.reflectionProbeArray.Count; }