public static bool IsEnabledFor( this DebugLightFilterMode mode, GPULightType gpuLightType, SpotLightShape spotLightShape ) { switch (gpuLightType) { case GPULightType.ProjectorBox: case GPULightType.ProjectorPyramid: case GPULightType.Spot: { switch (spotLightShape) { case SpotLightShape.Box: return((mode & DebugLightFilterMode.DirectSpotBox) != 0); case SpotLightShape.Cone: return((mode & DebugLightFilterMode.DirectSpotCone) != 0); case SpotLightShape.Pyramid: return((mode & DebugLightFilterMode.DirectSpotPyramid) != 0); default: throw new ArgumentOutOfRangeException(nameof(spotLightShape)); } } case GPULightType.Tube: return((mode & DebugLightFilterMode.DirectTube) != 0); case GPULightType.Point: return((mode & DebugLightFilterMode.DirectPunctual) != 0); case GPULightType.Rectangle: return((mode & DebugLightFilterMode.DirectRectangle) != 0); case GPULightType.Directional: return((mode & DebugLightFilterMode.DirectDirectional) != 0); default: throw new ArgumentOutOfRangeException(nameof(gpuLightType)); } }
//Packs a sort key for a light public static uint PackLightSortKey(LightCategory lightCategory, GPULightType gpuLightType, LightVolumeType lightVolumeType, int lightIndex) { //We sort directional lights to be in the beginning of the list. //This ensures that we can access directional lights very easily after we sort them. uint isDirectionalMSB = gpuLightType == GPULightType.Directional ? 0u : 1u; uint sortKey = (uint)isDirectionalMSB << 31 | (uint)lightCategory << 27 | (uint)gpuLightType << 22 | (uint)lightVolumeType << 17 | (uint)lightIndex; return(sortKey); }
public static bool MapLightType(LightArchetype la, LightType lt, out GPULightType gputype, out GPUShadowType shadowtype) { switch (la) { case LightArchetype.Punctual: return(MapLightType(lt, out gputype, out shadowtype)); case LightArchetype.Rectangle: gputype = GPULightType.Rectangle; shadowtype = GPUShadowType.Unknown; return(true); case LightArchetype.Line: gputype = GPULightType.Line; shadowtype = GPUShadowType.Unknown; return(true); default: gputype = GPULightType.Spot; shadowtype = GPUShadowType.Unknown; return(false); // <- probably not what you want } }
public static bool MapLightType(LightType lt, out GPULightType gputype, out GPUShadowType shadowtype) { switch (lt) { case LightType.Spot: gputype = GPULightType.Spot; shadowtype = GPUShadowType.Spot; return(true); case LightType.Directional: gputype = GPULightType.Directional; shadowtype = GPUShadowType.Directional; return(true); case LightType.Point: gputype = GPULightType.Point; shadowtype = GPUShadowType.Point; return(true); default: case LightType.Area: gputype = GPULightType.Rectangle; shadowtype = GPUShadowType.Unknown; return(false); // area lights by themselves can't be mapped to any GPU type } }
public static bool MapLightType(LightType lt, AdditionalLightData ald, out GPULightType gputype, out GPUShadowType shadowtype) { shadowtype = GPUShadowType.Unknown; // Default for all non-punctual lights gputype = GPULightType.Spot; switch (ald.archetype) { case LightArchetype.Punctual: return(MapLightType(lt, out gputype, out shadowtype)); case LightArchetype.Area: gputype = (ald.lightWidth > 0) ? GPULightType.Rectangle : GPULightType.Line; return(true); case LightArchetype.Projector: switch (lt) { case LightType.Directional: gputype = GPULightType.ProjectorOrtho; return(true); case LightType.Spot: gputype = GPULightType.ProjectorPyramid; return(true); default: Debug.Assert(false, "Projectors can only be Spot or Directional lights."); return(false); } default: return(false); // <- probably not what you want } }
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); }
public static bool IsSpot(this GPULightType lightType) { return(lightType == GPULightType.Spot || lightType == GPULightType.ProjectorBox || lightType == GPULightType.ProjectorPyramid); }
public static bool IsAreaLight(this GPULightType lightType) { return(lightType == GPULightType.Rectangle || lightType == GPULightType.Tube); }
void BuildLightData(CommandBuffer cmd, HDCamera hdCamera, List <HDAdditionalLightData> lightArray) { // Also we need to build the light list data if (m_LightDataGPUArray == null || m_LightDataGPUArray.count != lightArray.Count) { ResizeLightDataBuffer(lightArray.Count); } // 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[lightIdx] = 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 - hdCamera.camera.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.GetInnerSpotPercent01(); 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.contactShadowIndex = -1; lightData.cookieIndex = -1; lightData.shadowIndex = -1; lightData.rayTracedAreaShadowIndex = -1; if (light != null && light.cookie != null) { // TODO: add texture atlas support for cookie textures. switch (light.type) { case LightType.Spot: lightData.cookieIndex = m_LightLoop.cookieTexArray.FetchSlice(cmd, light.cookie); break; case LightType.Point: lightData.cookieIndex = m_LightLoop.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_LightLoop.cookieTexArray.FetchSlice(cmd, Texture2D.whiteTexture); } else if (lightData.lightType == GPULightType.Rectangle && additionalLightData.areaLightCookie != null) { lightData.cookieIndex = m_LightLoop.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; } // Set the data for this light m_LightDataCPUArray[lightIdx] = lightData; } //Push the data to the GPU m_LightDataGPUArray.SetData(m_LightDataCPUArray); }
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; } } }
//Unpacks a sort key for a light public static void UnpackLightSortKey(uint sortKey, out LightCategory lightCategory, out GPULightType gpuLightType, out LightVolumeType lightVolumeType, out int lightIndex) { lightCategory = (LightCategory)((sortKey >> 27) & 0xF); gpuLightType = (GPULightType)((sortKey >> 22) & 0x1F); lightVolumeType = (LightVolumeType)((sortKey >> 17) & 0x1F); lightIndex = (int)(sortKey & 0xFFFF); }
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); }