A few issues with LOD Creation in UE 4.14

Hi, I’ve had a chance to upgrade my project to 4.14 and I jumped right into testing the LOD creation.

Adjusting poly count by percentage works just fine. However, adjusting by “pixel error” or “max deviation” appears to do nothing. Strange. Also, updating normals appears to do nothing as well. Can anybody else reproduce this same problem? Is there something I’m missing?

Thanks! :slight_smile:
-Neil (CaptainMigraine)

Noticed this too, but didn’t bother to investigate, would be nice to have tool tips 'ya know :wink:

Pixel error only change lod change screens size. Max deviation seems to do nothing.

2 Likes

How PixelError is used in determing screen size (as of 4.27). In case anyone is interested.

static float CalculateViewDistance(float MaxDeviation, float AllowedPixelError)
{
	// We want to solve for the depth in world space given the screen space distance between two pixels
	//
	// Assumptions:
	//   1. There is no scaling in the view matrix.
	//   2. The horizontal FOV is 90 degrees.
	//   3. The backbuffer is 1920x1080.
	//
	// If we project two points at (X,Y,Z) and (X',Y,Z) from view space, we get their screen
	// space positions: (X/Z, Y'/Z) and (X'/Z, Y'/Z) where Y' = Y * AspectRatio.
	//
	// The distance in screen space is then sqrt( (X'-X)^2/Z^2 + (Y'-Y')^2/Z^2 )
	// or (X'-X)/Z. This is in clip space, so PixelDist = 1280 * 0.5 * (X'-X)/Z.
	//
	// Solving for Z: ViewDist = (X'-X * 640) / PixelDist

	const float ViewDistance = (MaxDeviation * 960.0f) / FMath::Max(AllowedPixelError, UStaticMesh::MinimumAutoLODPixelError);
	return ViewDistance;
}
				// Note we offset ViewDistance by SphereRadius here because the MaxDeviation is known to be somewhere in the bounds of the mesh. 
				// It won't necessarily be at the origin. Before adding this factor for very high poly meshes it would calculate a very small deviation 
				// for LOD1 which translates to a very small ViewDistance and a large (larger than 1) ScreenSize. This meant you could clip the camera 
				// into the mesh but unless you were near its origin it wouldn't switch to LOD0. Adding SphereRadius to ViewDistance makes it so that 
				// the distance is to the bounds which corrects the problem.
				ScreenSize[LODIndex].Default = ComputeBoundsScreenSize(FVector::ZeroVector, Bounds.SphereRadius, FVector(0.0f, 0.0f, ViewDistance + Bounds.SphereRadius), ProjMatrix);

Ok played with it a little more and figured I’d share some findings.

First Step: Define static mesh lod groups in your Config/DefaultEngine.ini

[StaticMeshLODSettings]
Foliage=(NumLODs=5,MaxNumStreamedLODs=0,bSupportLODStreaming=0,LODPercentTriangles=50,PixelError=10,Name=LOCTEXT("FoliageLOD","Foliage"))
Aggressive=(NumLODs=4,MaxNumStreamedLODs=0,bSupportLODStreaming=0,LODPercentTriangles=50,PixelError=64,SilhouetteImportance=4,Name=LOCTEXT("LargePropLOD","Large Prop"))

Second Step: Play around with values.

PercentTriangles: How many triangles get reduced with LODs.
PixelError: Higher numbers make it so LODs happen faster (higher screensize). This caps at PreviousLOD screensize * 0.5. (ie: 1.0 / 0.5 / 0.25 / 0.12)
SilhouetteImportance: This will basically prioritize keeping “outer” triangles and maintain the silhouette. 1 seems to be base and 4 seems to be a good trade. High values can really start corrupting details in odd ways. Having a higher than 1 value helps a lot if your lower LODs are corrupting shadows too much.