bool IsValidRayTracedMaterial(Material currentMaterial) { if (currentMaterial == null || currentMaterial.shader == null) { return(false); } bool isValid; // We use a cache, to speed up the case where materials/shaders are reused many times int shaderId = currentMaterial.shader.GetInstanceID(); if (m_ShaderValidityCache.TryGetValue(shaderId, out isValid)) { return(isValid); } // For the time being, we only consider non-decal HDRP materials as valid isValid = currentMaterial.GetTag("RenderPipeline", false) == "HDRenderPipeline" && !DecalSystem.IsDecalMaterial(currentMaterial); m_ShaderValidityCache.Add(shaderId, isValid); return(isValid); }
AccelerationStructureStatus AddInstanceToRAS(Renderer currentRenderer, bool rayTracedShadow, bool aoEnabled, int aoLayerValue, bool reflEnabled, int reflLayerValue, bool giEnabled, int giLayerValue, bool recursiveEnabled, int rrLayerValue, bool pathTracingEnabled, int ptLayerValue) { // 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 unwated 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 singleSided = false; bool materialIsOnlyTransparent = true; bool hasTransparentSubMaterial = false; // We disregard the ray traced shadows option when in Path Tracing rayTracedShadow &= !pathTracingEnabled; // Deactivate Path Tracing if the object does not belong to the path traced layer(s) pathTracingEnabled &= (bool)((ptLayerValue & 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 both non-null and non-decal if (currentMaterial != null && !DecalSystem.IsDecalMaterial(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; } // 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; // Check if the material has changed since last time we were here if (!m_MaterialsDirty) { int matId = currentMaterial.GetInstanceID(); int matPrevCRC, matCurCRC = currentMaterial.ComputeCRC(); if (m_MaterialCRCs.TryGetValue(matId, out matPrevCRC)) { m_MaterialCRCs[matId] = matCurCRC; m_MaterialsDirty |= (matCurCRC != matPrevCRC); } else { m_MaterialCRCs.Add(matId, matCurCRC); } } } } // If the mesh was not valid, exclude it if (!validMesh) { subMeshFlagArray[meshIdx] = RayTracingSubMeshFlags.Disabled; singleSided = true; } } // 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 || pathTracingEnabled) { 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 (aoEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Ambient Occlusion flag if needed instanceFlag |= ((aoLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.AmbientOcclusion) : 0x00; } if (reflEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Screen Space Reflection flag if needed instanceFlag |= ((reflLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.Reflection) : 0x00; } if (giEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Global Illumination flag if needed instanceFlag |= ((giLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.GlobalIllumination) : 0x00; } if (recursiveEnabled && meshIsVisible) { // Raise the Recursive Rendering flag if needed instanceFlag |= ((rrLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.RecursiveRendering) : 0x00; } if (pathTracingEnabled && 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 m_CurrentRAS.AddInstance(currentRenderer, subMeshFlags: subMeshFlagArray, enableTriangleCulling: singleSided, mask: instanceFlag); // Indicates that a transform has changed in our scene (mesh or light) m_TransformDirty |= currentRenderer.transform.hasChanged; currentRenderer.transform.hasChanged = false; // return the status return((!materialIsOnlyTransparent && hasTransparentSubMaterial) ? AccelerationStructureStatus.TransparencyIssue : AccelerationStructureStatus.Added); }
AccelerationStructureStatus AddInstanceToRAS(Renderer currentRenderer, bool rayTracedShadow, bool aoEnabled, int aoLayerValue, bool reflEnabled, int reflLayerValue, bool giEnabled, int giLayerValue, bool recursiveEnabled, int rrLayerValue, bool pathTracingEnabled, int ptLayerValue) { // 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 unwated 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 singleSided = false; bool materialIsOnlyTransparent = true; bool hasTransparentSubMaterial = false; 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 both non-null and non-decal if (currentMaterial != null && !DecalSystem.IsDecalMaterial(currentMaterial)) { // Mesh is valid given that all requirements are ok validMesh = true; subMeshFlagArray[meshIdx] = true; // Is the sub material transparent? subMeshTransparentArray[meshIdx] = currentMaterial.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT") || (HDRenderQueue.k_RenderQueue_Transparent.lowerBound <= currentMaterial.renderQueue && HDRenderQueue.k_RenderQueue_Transparent.upperBound >= currentMaterial.renderQueue); // Aggregate the transparency info materialIsOnlyTransparent &= subMeshTransparentArray[meshIdx]; hasTransparentSubMaterial |= subMeshTransparentArray[meshIdx]; // 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; // Check if the material has changed since last time we were here if (!m_MaterialsDirty) { int matId = currentMaterial.GetInstanceID(); int matPrevCRC, matCurCRC = currentMaterial.ComputeCRC(); if (m_MaterialCRCs.TryGetValue(matId, out matPrevCRC)) { m_MaterialCRCs[matId] = matCurCRC; m_MaterialsDirty |= (matCurCRC != matPrevCRC); } else { m_MaterialCRCs.Add(matId, matCurCRC); } } } } // If the mesh was not valid, exclude it if (!validMesh) { subMeshFlagArray[meshIdx] = false; subMeshCutoffArray[meshIdx] = false; singleSided = true; } } // If the material is considered opaque, but has some transparent sub-materials if (!materialIsOnlyTransparent && hasTransparentSubMaterial) { for (int meshIdx = 0; meshIdx < numSubMeshes; ++meshIdx) { subMeshCutoffArray[meshIdx] = subMeshTransparentArray[meshIdx] ? true : subMeshCutoffArray[meshIdx]; } } // Propagate the opacity mask only if all sub materials are opaque bool isOpaque = !hasTransparentSubMaterial; if (isOpaque) { instanceFlag |= (uint)(RayTracingRendererFlag.Opaque); } if (rayTracedShadow || pathTracingEnabled) { 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 (aoEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Ambient Occlusion flag if needed instanceFlag |= ((aoLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.AmbientOcclusion) : 0x00; } if (reflEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Screen Space Reflection if needed instanceFlag |= ((reflLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.Reflection) : 0x00; } if (giEnabled && !materialIsOnlyTransparent && meshIsVisible) { // Raise the Global Illumination if needed instanceFlag |= ((giLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.GlobalIllumination) : 0x00; } if (recursiveEnabled && meshIsVisible) { // Raise the Global Illumination if needed instanceFlag |= ((rrLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.RecursiveRendering) : 0x00; } if (pathTracingEnabled && meshIsVisible) { // Raise the Global Illumination if needed instanceFlag |= ((ptLayerValue & objectLayerValue) != 0) ? (uint)(RayTracingRendererFlag.PathTracing) : 0x00; } // If the object was not referenced if (instanceFlag == 0) { return(AccelerationStructureStatus.Added); } // Add it to the acceleration structure m_TransformDirty |= currentRenderer.transform.hasChanged; m_CurrentRAS.AddInstance(currentRenderer, subMeshMask: subMeshFlagArray, subMeshTransparencyFlags: subMeshCutoffArray, enableTriangleCulling: singleSided, mask: instanceFlag); currentRenderer.transform.hasChanged = false; // return the status return((!materialIsOnlyTransparent && hasTransparentSubMaterial) ? AccelerationStructureStatus.TransparencyIssue : AccelerationStructureStatus.Added); }
static bool IsValidRayTracedMaterial(Material currentMaterial) { if (currentMaterial == null || currentMaterial.shader == null) { return(false); } // For the time being, we only consider non-decal HDRP materials as valid return(currentMaterial.GetTag("RenderPipeline", false) == "HDRenderPipeline" && !DecalSystem.IsDecalMaterial(currentMaterial));; }