Instanced static meshes not masking, causing massive overdraw

I have a lot of foliage in my levels they use masked materials to avoid overdraw to a large degree. When placed as a static mesh actor they mask correctly and there is little overdraw as seen in the bush in the first image.

When included in the Instanced Static Mesh Actor they seem to blend over the whole material, ignoring the masking and causing massive overdraw as seen in the second image.

The sea of white that shows massive amounts of overdraw should largely show blue like the bush in the first image where the masking prevents blending from occurring where the alpha of the material is greater that the mask threshold.

I am using 4.14 with the forward renderer and have instanced stereo rendering enabled. I have not tested whether this remains true on the deferred renderer or with instanced stereo rendering disabled.

This seems like it could be related to This issue although I can’t say for sure.

Hey QSBen,

Thank you for submitting a bug report. I have reproduced this issue and logged a report for it here: Unreal Engine Issues and Bug Tracker (UE-39002)

You can track the report’s status as the issue is reviewed by our development staff. Please be aware that this issue may not be prioritized or fixed soon.

Cheers,

Ed. Just to clarify the bug report makes it sound as if the bug is only in the way the overdraw is displayed. Does this mean that the overdraw reported is not actually occurring in the in-game renderer?

That still needs to be determined. Foliage in the previous version displayed the same as other assets and there were other apparent changes to the visualizer in 4.14.

When the developers look at the report they will be able to determine if the issue is with foliage or the visualizer. At this time it is still unclear.

Hi QSBe,

I submitted a fix just now which will be in 4.15. The change in behavior since 4.13 is just with the view mode when using the forward renderer and doesn’t affect actual rendering.

In general there is a limitation with the shader complexity view modes not being very accurate for masked materials. I’ve written something about this before so I’ll just cut/paste it here:

The shader complexity view mode is not very accurate when it comes to masked materials. Shader complexity cannot use depth writes for masked materials because we need to write the cost for of all pixels including those masked away, and we can’t do that in a single pass while still updating the depth buffer. We could do multiple passes but that will not accurately reflect the benefit we get from using the depth buffer to reject pixels during the same rendering pass.
So the compromise for masked materials is, in shader complexity view mode, to first render a depth prepass to populate the depth buffer with the masked material before performing the shader complexity calculation.

(note this is the bit that is broken in 4.14)

This gives a visual representation of the overdraw for the areas masked away while treating the opaque areas of the material as if they’re regular non-masked materials but with zero overdraw cost at all.

In regular view mode, whether a depth prepass is performed depends on the “Use as Occluder” flag on the foliage type or static mesh, as well as the “Early Z Pass” flag under Project Settings, Rendering. While a depth prepass will guarantee zero overdraw for the opaque sections of your foliage, it has the extra rendering cost. You will need to determine whether it’s better for your game and your foliage to have it enabled or not.
In the case where a depth pass is not performed, there will be some overdraw for the opaque sections that depends on the drawing order of of the foliage instances. It is not possible to visualize that overdraw with the shader complexity viewmode because of the limitations of the way it works. Also, we don’t currently do any sorting when rendering chunks of foliage. But we do have a feature request ticket open, UE-35082 to sort foliage instance chunks so we render them roughly sorted from front to back. That would help minimize the overdraw for the case when a depth prepass is not used.

If you’re using source code and you’re interested to apply the visualization fix yourself, the change is very simple. Just find this code in DeferedShadingRenderer.cpp in the FDeferredShadingSceneRenderer constructor:

	// Shader complexity requires depth only pass to display masked material cost correctly
	if (ViewFamily.UseDebugViewPS() && ViewFamily.GetDebugViewShaderMode() != DVSM_OutputMaterialTextureScales)
	{
		EarlyZPassMode = DDM_AllOpaque;
	}

and move it to the very end of the function, below if (ShouldForceFullDepthPass(FeatureLevel))

Cheers
Jack

a lot Jack. This is very helpful.