/// <summary> /// Function that returns the ray tracing and path tracing effects that are enabled for a given camera. /// </summary> /// <param name="hdCamera">The input camera</param> /// <param name="rayTracedShadows">Flag that defines if at least one light has ray traced shadows.</param> /// <param name="rayTracedContactShadows">Flag that defines if at least one light has ray traced contact shadows</param> /// <returns>HDEffectsParameters type.</returns> public static HDEffectsParameters EvaluateEffectsParameters(HDCamera hdCamera, bool rayTracedShadows, bool rayTracedContactShadows) { HDEffectsParameters parameters = new HDEffectsParameters(); // Aggregate the shadow requirements parameters.shadows = hdCamera.frameSettings.IsEnabled(FrameSettingsField.ScreenSpaceShadows) && (rayTracedShadows || rayTracedContactShadows); // Aggregate the ambient occlusion parameters AmbientOcclusion aoSettings = hdCamera.volumeStack.GetComponent <AmbientOcclusion>(); parameters.ambientOcclusion = aoSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSAO); parameters.aoLayerMask = aoSettings.layerMask.value; // Aggregate the reflections parameters ScreenSpaceReflection reflSettings = hdCamera.volumeStack.GetComponent <ScreenSpaceReflection>(); parameters.reflections = reflSettings.enabled.value && ScreenSpaceReflection.RayTracingActive(reflSettings) && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSR); parameters.reflLayerMask = reflSettings.layerMask.value; // Aggregate the global illumination parameters GlobalIllumination giSettings = hdCamera.volumeStack.GetComponent <GlobalIllumination>(); parameters.globalIllumination = giSettings.enable.value && GlobalIllumination.RayTracingActive(giSettings) && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSGI); parameters.giLayerMask = giSettings.layerMask.value; // Aggregate the global illumination parameters RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent <RecursiveRendering>(); parameters.recursiveRendering = recursiveSettings.enable.value; parameters.recursiveLayerMask = recursiveSettings.layerMask.value; // Aggregate the sub surface parameters SubSurfaceScattering sssSettings = hdCamera.volumeStack.GetComponent <SubSurfaceScattering>(); parameters.subSurface = sssSettings.rayTracing.value && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SubsurfaceScattering); // Aggregate the path parameters PathTracing pathTracingSettings = hdCamera.volumeStack.GetComponent <PathTracing>(); parameters.pathTracing = pathTracingSettings.enable.value; parameters.ptLayerMask = pathTracingSettings.layerMask.value; // We need to check if at least one effect will require the acceleration structure parameters.rayTracingRequired = parameters.ambientOcclusion || parameters.reflections || parameters.globalIllumination || parameters.recursiveRendering || parameters.subSurface || parameters.pathTracing || parameters.shadows; // Return the result return(parameters); }
internal void BuildRayTracingAccelerationStructure(HDCamera hdCamera) { // Resets the rtas manager m_RTASManager.Reset(); // Resets the light lists m_RayTracingLights.Reset(); // Reset all the flags 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)) { return; } // Collect the lights CollectLightsForRayTracing(hdCamera, ref m_RTASManager.transformsDirty); // Evaluate the parameters of the effects HDEffectsParameters effectParameters = EvaluateEffectsParameters(hdCamera, m_RayTracedShadowsRequired, m_RayTracedContactShadowsRequired); if (!effectParameters.rayTracingRequired) { return; } // Grab the ray tracing settings RayTracingSettings rtSettings = hdCamera.volumeStack.GetComponent <RayTracingSettings>(); #if UNITY_EDITOR if (rtSettings.buildMode.value == RTASBuildMode.Automatic || hdCamera.camera.cameraType == CameraType.SceneView) #else if (rtSettings.buildMode.value == RTASBuildMode.Automatic) #endif { // Cull the scene for the RTAS RayTracingInstanceCullingResults cullingResults = m_RTASManager.Cull(hdCamera, effectParameters); // Update the material dirtiness for the PT if (effectParameters.pathTracing) { m_RTASManager.transformsDirty |= cullingResults.transformsChanged; for (int i = 0; i < cullingResults.materialsCRC.Length; i++) { RayTracingInstanceMaterialCRC matCRC = cullingResults.materialsCRC[i]; m_RTASManager.materialsDirty |= UpdateMaterialCRC(matCRC.instanceID, matCRC.crc); } } // Build the ray tracing acceleration structure m_RTASManager.Build(hdCamera); // tag the structures as valid m_ValidRayTracingState = true; } else { // If the user fed a non null ray tracing acceleration structure, then we are all set. if (hdCamera.rayTracingAccelerationStructure != null) { m_ValidRayTracingState = true; } } }
/// <summary> /// Function that adds a renderer to a ray tracing acceleration structure. /// </summary> /// <param name="targetRTAS">Ray Tracing Acceleration structure the renderer should be added to.</param> /// <param name="currentRenderer">The renderer that should be added to the RTAS.</param> /// <param name="effectsParameters">Structure defining the enabled ray tracing and path tracing effects for a camera.</param> /// <param name="transformDirty">Flag that indicates if the renderer's transform has changed.</param> /// <param name="materialsDirty">Flag that indicates if any of the renderer's materials have changed.</param> /// <returns></returns> public static AccelerationStructureStatus AddInstanceToRAS(RayTracingAccelerationStructure targetRTAS, Renderer currentRenderer, HDEffectsParameters effectsParameters, ref bool transformDirty, ref bool materialsDirty) { // Get all the materials of the mesh renderer currentRenderer.GetSharedMaterials(materialArray); // If the array is null, we are done if (materialArray == null) { return(AccelerationStructureStatus.NullMaterial); } // For every sub-mesh/sub-material let's build the right flags int numSubMeshes = 1; if (!(currentRenderer.GetType() == typeof(SkinnedMeshRenderer))) { currentRenderer.TryGetComponent(out MeshFilter meshFilter); if (meshFilter == null || meshFilter.sharedMesh == null) { return(AccelerationStructureStatus.MissingMesh); } numSubMeshes = meshFilter.sharedMesh.subMeshCount; } else { SkinnedMeshRenderer skinnedMesh = (SkinnedMeshRenderer)currentRenderer; if (skinnedMesh.sharedMesh == null) { return(AccelerationStructureStatus.MissingMesh); } numSubMeshes = skinnedMesh.sharedMesh.subMeshCount; } // Let's clamp the number of sub-meshes to avoid throwing an unwanted error numSubMeshes = Mathf.Min(numSubMeshes, maxNumSubMeshes); // Get the layer of this object int objectLayerValue = 1 << currentRenderer.gameObject.layer; // We need to build the instance flag for this renderer uint instanceFlag = 0x00; bool doubleSided = false; bool materialIsOnlyTransparent = true; bool hasTransparentSubMaterial = false; // We disregard the ray traced shadows option when in Path Tracing bool rayTracedShadow = effectsParameters.shadows && !effectsParameters.pathTracing; // Deactivate Path Tracing if the object does not belong to the path traced layer(s) bool pathTracing = effectsParameters.pathTracing && (bool)((effectsParameters.ptLayerMask & objectLayerValue) != 0); for (int meshIdx = 0; meshIdx < numSubMeshes; ++meshIdx) { // Initially we consider the potential mesh as invalid bool validMesh = false; if (materialArray.Count > meshIdx) { // Grab the material for the current sub-mesh Material currentMaterial = materialArray[meshIdx]; // Make sure that the material is HDRP's and non-decal if (IsValidRayTracedMaterial(currentMaterial)) { // Mesh is valid given that all requirements are ok validMesh = true; // First mark the thing as valid subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled; // Evaluate what kind of materials we are dealing with bool alphaTested = IsAlphaTestedMaterial(currentMaterial); bool transparentMaterial = IsTransparentMaterial(currentMaterial); // Aggregate the transparency info materialIsOnlyTransparent &= transparentMaterial; hasTransparentSubMaterial |= transparentMaterial; // Append the additional flags depending on what kind of sub mesh this is if (!transparentMaterial && !alphaTested) { subMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.ClosestHitOnly; } else if (transparentMaterial) { subMeshFlagArray[meshIdx] |= RayTracingSubMeshFlags.UniqueAnyHitCalls; } // Check if we want to enable double-sidedness for the mesh // (note that a mix of single and double-sided materials will result in a double-sided mesh in the AS) doubleSided |= currentMaterial.doubleSidedGI || currentMaterial.IsKeywordEnabled("_DOUBLESIDED_ON"); // Check if the material has changed since last time we were here if (!materialsDirty) { materialsDirty |= UpdateMaterialCRC(currentMaterial.GetInstanceID(), currentMaterial.ComputeCRC()); } } } // If the mesh was not valid, exclude it (without affecting sidedness) if (!validMesh) { subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Disabled; } } // If the material is considered opaque, every sub-mesh has to be enabled and with unique any hit calls if (!materialIsOnlyTransparent && hasTransparentSubMaterial) { for (int meshIdx = 0; meshIdx < numSubMeshes; ++meshIdx) { subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.UniqueAnyHitCalls; } } // Propagate the opacity mask only if all sub materials are opaque bool isOpaque = !hasTransparentSubMaterial; if (isOpaque) { instanceFlag |= (uint)(RayTracingRendererFlag.Opaque); } if (rayTracedShadow || pathTracing) { if (hasTransparentSubMaterial) { // Raise the shadow casting flag if needed instanceFlag |= ((currentRenderer.shadowCastingMode != ShadowCastingMode.Off) ? (uint)(RayTracingRendererFlag.CastShadowTransparent) : 0x00); } else { // Raise the shadow casting flag if needed instanceFlag |= ((currentRenderer.shadowCastingMode != ShadowCastingMode.Off) ? (uint)(RayTracingRendererFlag.CastShadowOpaque) : 0x00); } } // We consider a mesh visible by reflection, gi, etc if it is not in the shadow only mode. bool meshIsVisible = currentRenderer.shadowCastingMode != ShadowCastingMode.ShadowsOnly; if (effectsParameters.ambientOcclusion && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Ambient Occlusion flag if needed instanceFlag |= ((effectsParameters.aoLayerMask & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.AmbientOcclusion) : 0x00; } if (effectsParameters.reflections && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Screen Space Reflection flag if needed instanceFlag |= ((effectsParameters.reflLayerMask & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.Reflection) : 0x00; } if (effectsParameters.globalIllumination && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Global Illumination flag if needed instanceFlag |= ((effectsParameters.giLayerMask & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.GlobalIllumination) : 0x00; } if (effectsParameters.recursiveRendering && meshIsVisible) { // Raise the Recursive Rendering flag if needed instanceFlag |= ((effectsParameters.recursiveLayerMask & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.RecursiveRendering) : 0x00; } if (effectsParameters.pathTracing && meshIsVisible) { // Raise the Path Tracing flag if needed instanceFlag |= (uint)(RayTracingRendererFlag.PathTracing); } // If the object was not referenced if (instanceFlag == 0) { return(AccelerationStructureStatus.Added); } // Add it to the acceleration structure targetRTAS.AddInstance(currentRenderer, subMeshFlags: subMeshFlagArray, enableTriangleCulling: !doubleSided, mask: instanceFlag); // Indicates that a transform has changed in our scene (mesh or light) transformDirty |= currentRenderer.transform.hasChanged; currentRenderer.transform.hasChanged = false; // return the status return((!materialIsOnlyTransparent && hasTransparentSubMaterial) ? AccelerationStructureStatus.TransparencyIssue : AccelerationStructureStatus.Added); }