Is this basically doing frustum culling on each section?
It allows you to pre-emptively cull backfacing mesh CPU-side, by creating six VertexFactories for each SceneProxy (+/- X/Y/Z).
In any Minecraft-style cube world like BrickGrid the performance boost is change-your-design-constraints huge. My primary project is more semi-uniform (cubes topped with 5x5 vert heightmaps), but since camera and primary shadowcaster are guaranteed +Z & -Pitch it yields equivalent benefits in practice.
I don’t know whether off-axis geometry would see a benefit from attempting a combinatoric approach, and I’m fairly certain there’s nothing here for marching cubes/isosurface implementations.
The secret sauce is in the VertexFactory, looks like this (just going to paste lightly modified BrickRenderComponent.cpp):
void Init(const FExampleVertexBuffer& VertexBuffer,const FPrimitiveSceneProxy* InPrimitiveSceneProxy,uint8 InFaceIndex)
{
PrimitiveSceneProxy = InPrimitiveSceneProxy;
FaceIndex = InFaceIndex;
// Bog-standard VertexFactory Init code here
}
// Elsewhere in VertexFactory...
#if UE4_HAS_IMPROVED_MESHBATCH_ELEMENT_VISIBILITY
virtual uint64 GetStaticBatchElementVisibility(const class FSceneView& View, const struct FMeshBatch* Batch) const override
{
return IsStaticBatchVisible(View.ViewMatrices.ViewOrigin,Batch) ? 1 : 0;
}
virtual uint64 GetStaticBatchElementShadowVisibility(const class FSceneView& View, const FLightSceneProxy* LightSceneProxy, const struct FMeshBatch* Batch) const override
{
return IsStaticBatchVisible(LightSceneProxy->GetPosition(),Batch) ? 1 : 0;
}
#endif //UE4_HAS_IMPROVED_MESHBATCH_ELEMENT_VISIBILITY
private:
const FPrimitiveSceneProxy* PrimitiveSceneProxy;
uint8 FaceIndex;
bool IsStaticBatchVisible(const FVector4& ViewPosition,const struct FMeshBatch* Batch) const
{
const uint8 FaceIndex = Batch->Elements[0].UserIndex;
const FBox BoundingBox = PrimitiveSceneProxy->GetBounds().GetBox();
const FVector MinRelativePosition = ViewPosition - BoundingBox.Min * ViewPosition.W;
const FVector MaxRelativePosition = ViewPosition - BoundingBox.Max * ViewPosition.W;
switch(FaceIndex)
{
case 0: return MaxRelativePosition.X < 0.0f;
case 1: return MinRelativePosition.X > 0.0f;
case 2: return MaxRelativePosition.Y < 0.0f;
case 3: return MinRelativePosition.Y > 0.0f;
case 4: return MaxRelativePosition.Z < 0.0f;
case 5: return MinRelativePosition.Z > 0.0f;
default: return false;
}
}
Some other changes for Static relevance and per-facing mesh batching are required SceneProxy-side to support, but it’s pretty straightforward stuff. Ctrl-F “void InitMeshBatch(” and “struct FFaceBatch” in BrickRenderComponent.cpp.
I’m not sure how much work would be required.
The actual code would be a matter of a few hours, but the primary issues I can see would be:
- This is specific to static SceneProxies (ProceduralMeshComponent is bDynamicRelevance = true), and
-
requiring the user to submit sections with an axis-facing enum, or something similar.
The former may introduce complications I’m not aware of (Static works just fine for all of my projects, but I adhere to a fixed world grid), and for the latter I’m not sure how comfortable you are with exposing something so potentially fragile to Blueprint, which was part of the reason I asked.
I’m not actually familiar with that code, would you consider making a pull request that adds support?
I’m honestly more of a Tech Designer, but I’d be happy to take a stab at it once 's pull request is in a Release build, if you think it would be worthwhile in light of the caveats.