LOD generation guidelines
Learn how to generate Levels of Detail (LODs) for optimal real-time rendering performance.
Read time 3 minutesLast updated a day ago
Why generate LODs?
Levels of Detail (LODs) are multiple versions of the same 3D model with varying polygon counts. Real-time engines automatically switch between these versions based on the object's distance from the camera, dramatically improving rendering performance. Key benefits of LODs:- Better frame rates - Distant objects use fewer polygons, reducing GPU workload
- Larger scenes - Support more objects in a scene without performance degradation
- Scalable performance - Automatic quality adjustment based on viewing distance
- Memory efficiency - Only high-detail meshes are used when needed
LOD generation vs optimization
While both LOD generation and optimization reduce polygon count, they serve different purposes and use different approaches: Optimization (LOD0):- Goal - Create the best quality model within performance constraints
- Approach - Conservative reduction, preserve visual fidelity
- Philosophy - Balance quality and performance for close-up viewing
- Goal - Create highly simplified versions for distant viewing
- Approach - Aggressive, destructive reduction
- Philosophy - Maximize performance, visual quality is secondary
1. Automatic LOD chain generation
The most common approach is to generate a chain of LODs using progressive decimation. Check the following example to automatically create multiple LOD levels:from pxz import core, algo, scene, polygonaldef generateLODChainCommon(occurrences, count): partOccurrences = list() for occ in occurrences: partOccurrences = partOccurrences + scene.getPartOccurrences(occ) partOccurrences = set(partOccurrences) lodOccurrences = [[] for i in range(count + 1)] # init empty list of lists processedParts = list() for partOcc in partOccurrences: partComp = scene.getComponent(partOcc, scene.ComponentType.Part) if partComp == 0 or partComp in processedParts: continue mesh = scene.getPartMesh(partComp) if mesh == 0: continue if not polygonal.getMeshDefinition(mesh).triangles: continue processedParts.append(partComp) owner = scene.getComponentOccurrence(partComp) # returns the occurrence that "owns" the component name = core.getProperty(owner, "Name") occ0 = scene.createOccurrence(name + "_LOD0") scene.setComponentOccurrence(partComp, occ0) scene.setParent(occ0, owner, addInParentInstances=True, worldPositionStays=False) instances = scene.getInstances(occ0) for instance in instances: lodOccurrences[0].append(instance) for i in range(1, count + 1): lod = scene.createOccurrence(name + "_LOD" + str(i)) partClone = core.cloneEntity(partComp) scene.setComponentOccurrence(partClone, lod) scene.setParent(lod, owner, addInParentInstances=True, worldPositionStays=False) instances = scene.getInstances(lod) for instance in instances: lodOccurrences[i].append(instance) if len(lodOccurrences[0]) == 0: raise Exception("This process works for meshes only (requires the selected parts to be tessellated first)") return lodOccurrencesdef generateLODChainTarget(occurrences: list[int], ratios: list[int]): try: core.pushProgression(len(ratios) + 1, "Generate LOD Chain") lodOccurrences = generateLODChainCommon(occurrences, len(ratios)) for i in range(len(ratios)): algo.decimateTarget(lodOccurrences[i + 1], ["ratio", ratios[i]]) core.stepProgression() except Exception as e: core.popProgression() raise e core.popProgression()ratios = [50, 25, 10] # LOD1: 50%, LOD2: 25%, LOD3: 12%generateLODChainTarget([scene.getRoot()], ratios)
How it works
The script creates multiple LOD occurrences for each mesh:- LOD0 - Your optimized master model (highest quality)
- LOD1 - First simplified version (50% of LOD0 triangles)
- LOD2 - Second simplified version (25% of LOD0 triangles)
- LOD3 - Third simplified version (10% of LOD0 triangles)
2. Advanced LOD generation
For the farthest LOD levels (typically LOD3 or LOD4), you should generate a single mesh with a single baked material to achieve optimal performance with just one draw call. Recommended approach:- Single mesh
- Merge and decimate - Combine all meshes into one, then apply aggressive decimation
- OR use retopology - Generate a simplified mesh using retopology functions like Proxy Mesh
- Single material - Create a single baked material from LOD0 using the bakeMaterials function
- One draw call - The entire object renders in a single GPU call
- Minimal overhead - Use small resolution texture and a small number of polygons