private void AddMaterialToArrayAndDictionary(ScatteringParameters scatteringParameters, uint materialArrayIndex) { // "SetScatteringWidth()" throws an exception if the range is exceeded. // TODO: How to handle this? Don't throw at all? SubsurfaceScatteringBlurEffect.SetScatteringWidth(materialArrayIndex, scatteringParameters.ScatteringWidth); // Add the scattering width to the scattering width array. if (scatteringParameters.ScatteringKernel != null) { // TODO: STABILITY: What to do if the scattering width is present but no kernel? The post-process wouldn't be able to handle that correctly. // Maybe just save a dummy kernel? SubsurfaceScatteringBlurEffect.SetScatteringKernel(materialArrayIndex, scatteringParameters.ScatteringKernel); } scatteringParametersToArrayIndexDictionary[scatteringParameters] = materialArrayIndex; // Add the material to the dictionary and save its associated index in the scattering width array. }
/// <inheritdoc/> public override void Prepare(RenderDrawContext context) { if (DeduplicateMaterialParameters) { scatteringParametersToArrayIndexDictionary.Clear(); } // TODO: Generate a material array per view? This could in some cases limit the number of materials present in the array. // In case every object is visible from every view, it wouldn't save us anything though. uint materialArrayIndexCounter = 1; // We start at index 1 instead of 0 because we use index 0 to flag (and discard) non-scattering materials. // TODO: Not sure if the following line is even necessary, because we don't use any material parameters of material 0 anyway. I mean not even the kernel of material 0 is set. So either set both or none. SubsurfaceScatteringBlurEffect.SetScatteringWidth(0, 0.0f); // This element is unused because a material index of 0 means the material is not a subsurface scattering material and therefore will be skipped by the post-process. // Generate the material dictionary that contains only scattering materials: //Dispatcher.ForEach(((RootEffectRenderFeature)RootRenderFeature).RenderNodes, (ref RenderNode renderNode) => // TODO: PERFORMANCE: Use this instead? foreach (RenderNode renderNode in ((RootEffectRenderFeature)RootRenderFeature).RenderNodes) { var perDrawLayout = renderNode.RenderEffect?.Reflection?.PerDrawLayout; if (perDrawLayout == null) { continue; } var renderMesh = (RenderMesh)renderNode.RenderObject; uint materialArrayIndex = 0; // If the mesh doesn't have a scattering kernel we write index 0 into the constant buffer. if (HasScatteringKernel(renderMesh.MaterialPass)) { materialArrayIndex = AddMaterialToDictionaryAndGetArrayIndex(renderMesh, ref materialArrayIndexCounter); } WriteMaterialIndexIntoRenderNodeConstantBuffer(perDrawLayout, renderNode, materialArrayIndex); } bool scatteringMaterialsAreVisible = (materialArrayIndexCounter > 1); SubsurfaceScatteringBlurEffect.Enabled = scatteringMaterialsAreVisible; // Disable the post-process if no scattering objects are visible (to save performance). }