Disabling displacement material attribute, quality, performance

Hey, We’re using Displacement material attribute in our materials. For performance reasons, we’d like to skip this feature for slower hardware (like XSS or worse PC configs). The idea was to use Material Quality switch and set the displacement to 0 in cases of lower quality modes. Unfortunately this does nothing and the performance impact on nanite passes is the same.

Only completely disconnecting the input pin actually gets rid of the additional cost and places it along all the other materials into the “SW Rasterize (Triangles)” path.

We have had similar performance issues with Pixel Depth Offset, but in that case, connected 0 or quality switch with 0 for low quality modes actually reduces the performance impact. I believe the current implementation to be a bug.

If it’s not possible to provide a 5.5 patch with a fix to this issue, please share information on how this works, where can I find the code where this decision is made and how I should go about modifying the engine to treat Displacement 0 the same as no displacement input pin present.

Hi,

Are you able to please provide a minimal project that reproduces the issue or alternatively detailed steps to reproduce. This will help to diagnose and triage the issue that you have reported.

Hey,

I am confident I did enter the repro steps. I have no idea why they didn’t post. Here they are, the issue is simple to re-make:

  1. Use any map, I used default template non open world
  2. Create a new material, surface, opaque, default lit
  3. Input something to base color, so that the material renders, let’s say red constant (vector3, 1,0,0)
  4. Place a cube on the scene, place the material on the cube.
  5. Launch PIE, look at the cube and input those commandlines: “rhi.SetGPUCaptureOptions 1”, “r.ShowMaterialDrawEvents 1”, “profileGPU”
  6. In the profile GPU window that shows up, navigate to nanite base and post passes as shown on my screen. Notice that the only pass that takes any time is the (Triangles) pass.
  7. Go back to material, connect scalar constant of value 0 to displacement input in the material.
  8. Retry points 5 and 6. Notice that additional passes for patching and tesselations show up, even though the actual displacement is zero. Notice that the material is listed by the name in those passes, which means that the real material is used for the pass, the expensive path, instead of the cheap path with world grid material where possible.

This effectively requires us to make a new separate material master for no-displacement and second for with-displacement and then depending on quality levels reassign all materials on scene. That’s a lot of work. I’d rather have this work like Pixel Depth Offset, which disconnected and with input 0 costs the same (nothing).

Again if a fix isn’t readily available, please share with me any information you have as to where this is handled in code, what should I know when modifying it and if you have some insight - what’s the best approach to modifications in there.

Hi,

Because the `Enable Tesselation` check box is a Material Environment parameter it requires a recompilation of the material itself everytime it is changed. Currently, to selectively disable the displacement pass you will need to explicitly uncheck the `Enable Tesselation` check box in each of the Materials or Material instances and apply the appropriate material at the correct time ( e.g. potentially assigning a new dynamic material on quality change ).

You can investigate this yourself by inspecting and breakpointing various functions in the HLSLMaterialTranslator.cpp class and compiling the material in the Editor. Line 2671

OutEnvironment.SetDefineAndCompileArgument(TEXT("USES_DISPLACEMENT"), EnvironmentDefines->bUsesDisplacement);may be a good place to start.

You may be able to refactor the `bUsesDisplacement` assignment on line 1786 of HLSLMaterialTranslator.cpp ( or a similarly appropriate line depending on your use case ) to include a check for a non zero value. However, this may require extra management to ensure the variant will compile correctly ( e.g behind a feature or quality switch ) and extra steps to obtain the input value.

Another option could be to disable nanite for lower quality settings by refactoring the upstream DoesPlatformSupportNanite function found in RenderUtils.cpp to read ‘quality’ or `custom` values.