AutoEntityLODs ( entity[,tolerance#][,levels] )

Parameters

entity - mesh entity, or a parent of mesh entities, that gets simpler versions of itself

tolerance# (optional) - how many pixels of difference you accept before a simpler version takes over; 1 (default). Smaller keeps full detail further away, larger saves more

levels (optional) - most versions to make, from 0 to 4; 0 lets AutoEntityLODs decide (default)

Description

Makes simpler versions of a mesh and swaps them in as it gets smaller on screen.

A detailed boulder costs as much at 200 metres as it does at 2. AutoEntityLODs builds up to four cheaper copies of the mesh, each with about half the triangles of the one before, and attaches them as its levels of detail: no modelling program, no extra files, no distances to guess. It returns how many meshes got versions, counting the entity and its child meshes, so a model loaded with LoadAnimMesh gets them throughout. 0 means nothing was detailed enough to gain: meshes under 300 triangles are left alone.

Each version knows how far it strays from the full mesh, and takes over once that difference would look smaller than tolerance pixels from the camera. So the switch follows the entity's scale, the camera's CameraZoom and the size of its viewport by itself: a giant statue keeps its detail further away than a pebble, and a sniper scope zoomed in four times brings the detail back. EntityLODDistance tells you where each switch is for a camera.

The versions fade into each other over a short band around each switch, so they do not pop. Call EntityLODTransition afterwards to set your own width, or 0 to switch straight from one to the next.

The simplifier only chooses which vertices to keep, and keeps those exactly as they were, so textures, vertex colours and lightmap coordinates stay put. A mesh with automatic versions is still lightmapped by BakeLighting, versions included; hand-made levels from AddEntityLOD are lit by probes instead. Every version has the same surfaces as the full mesh, so per-surface materials and EntityMaterial slots keep working, and painting the mesh paints its versions too.

Characters get versions too. Each version keeps its vertices' bone weights and morph target deltas, so it walks with the same skeleton and makes the same faces as the full mesh, and SetMorphWeight changes every version at once. The simplifier keeps triangles where bones meet and where morph targets move the surface, so elbows still bend and smiles still curve. Adding or clearing morph targets afterwards counts as changing the mesh.

The versions belong to the mesh data, so CopyEntity copies share them, and calling AutoEntityLODs on a copy with the same levels costs nothing. Making them takes about 3 ms per 1,000 triangles on a fast PC, so do it once on a template while your level loads, then stamp out copies. Or make them before the game runs at all: SaveMesh keeps them in the model's .glb file, which loads with them ready to draw. A mesh that loaded with levels like that keeps them: AutoEntityLODs with levels 0 only sets their tolerance, and asking for a number of levels makes new versions instead.

Gotcha: levels of detail affect drawing only. Collisions, picks and physics keep using the full mesh. If you change the mesh afterwards (VertexCoords, ScaleMesh, AddMesh and so on), its versions show a shape it no longer has, so the mesh draws at full detail until you call AutoEntityLODs again. It replaces any levels the mesh had, including AddEntityLOD ones, and AddEntityLOD cannot add to automatic versions: use ClearEntityLODs first.

See also: CountEntityLODs, EntityLODDistance, ForceEntityLOD, SimplifyEntityLOD, AddEntityLOD, EntityLODTransition.

Example

; AutoEntityLODs Example
; ----------------------

Graphics3D 640,480,0,2
SetBuffer BackBuffer()

camera=CreateCamera()
PositionEntity camera,0,2,-6

light=CreateLight()
RotateEntity light,45,45,0

; A detailed boulder: 6,240 triangles
rock=CreateSphere(40)
ScaleMesh rock,1.2,0.8,1
EntityColor rock,150,140,120

; A row of boulders running into the distance
Dim rocks(9)
For n=0 To 9
    rocks(n)=CopyEntity(rock)
    PositionEntity rocks(n),(n Mod 2)*4-2,0,4+n*6
Next
HideEntity rock

; Simpler versions take over once they look less than this many pixels off
tolerance#=1
For n=0 To 9
    AutoEntityLODs rocks(n),tolerance
Next

wire=False

While Not KeyDown(1)

    ; [ / ] halve or double the tolerance and make the versions again
    change#=0
    If KeyHit(26) And tolerance>0.25 Then change=0.5
    If KeyHit(27) And tolerance<8 Then change=2
    If change>0
        tolerance=tolerance*change
        For n=0 To 9
            AutoEntityLODs rocks(n),tolerance
        Next
    EndIf

    ; Space shows the triangles
    If KeyHit(57) Then wire=Not wire
    WireFrame wire

    For n=0 To 9
        TurnEntity rocks(n),0,0.2,0
    Next

    ; Arrow keys move the camera
    If KeyDown(200) Then MoveEntity camera,0,0,0.1
    If KeyDown(208) Then MoveEntity camera,0,0,-0.1
    If KeyDown(203) Then TurnEntity camera,0,1,0
    If KeyDown(205) Then TurnEntity camera,0,-1,0

    RenderWorld

    Text 0,0,"Arrow keys: move camera   [ / ] : tolerance   Space: wireframe   Esc: exit"
    Text 0,20,"AutoEntityLODs rock,"+tolerance+"   ("+CountEntityLODs(rocks(0))+" simpler versions)"
    Text 0,40,"Triangles drawn: "+TrisRendered()+" of "+10*EntityLODTriangles(rocks(0),0)

    Flip

Wend

End

Index