I'm a doctor, not a mechanic

Legacy:Ransico/LODMesh

From Unreal Wiki, The Unreal Engine Documentation Site
< Legacy:Ransico
Revision as of 05:22, 14 March 2006 by Ransico (Talk)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

LODMesh[edit]

This class is used to immitate the LOD effect found in some modern engines. LOD is a trick used to have heaps of meshes on the screen at once, without too much of a hit on the framerate. It works by reducing the number of polygons on the mesh, as it gets further away from the player.

There are generally two approaches to this:

  • you can manually create different detail models in your 3D editor, one for each level of detail
  • have some fancy algorithm do it for you.

I have chosen the first method - although more work for the modeler, it looks a lot nicer.

The main reason I am listing this class here, is a replication demo: as you can imagine, you will only want this class to run on the client, not the server at all. This is achieved by setting various things in the default properties down at the bottom, and also an IF statement in the PostBeginPlay.

/*
 * LODMesh class - implements a 2 level LOD for static meshes.
 * Lewis Weaver, 1/3/2006
 */
 
class LODMesh extends Actor
    placeable;
 
var(Display) StaticMesh LODfarMesh;     // The mesh to use for the far away model
var(Display) float LODdist;  // How far away should the LOD kick in
var(Display) bool LODrotate; // Should the mesh always rotate to face the actor, when in LOD_Far state? useful for planes
 
var enum LODStates {
    LOD_Waiting,
    LOD_Near,
    LOD_Far
} currentState;
 
// this variable avoids popping in and out rapidly
var float threshold;
 
simulated function PostBeginPlay() {
 
    // Precalculate the threshold
    if(LODDist > 2000)
        threshold = 50;
    else
        threshold = LODDist * 0.025;
 
    disable('tick');
 
    if ( Level.NetMode != NM_DedicatedServer ) {
 
        waitForPlayer();
 
    }
 
}
 
simulated function waitForPlayer() {
    setTimer(0.1, true);
    currentState = LOD_Waiting;
}
 
simulated event timer() {
    if(currentState == LOD_Waiting) {
        if(level.GetLocalPlayerController() != none) {
            if(VSize(Location - level.GetLocalPlayerController().Pawn.Location) > LODdist) {
                SetStaticMesh(LODfarMesh);
                currentState = LOD_Far;
            } else {
                SetStaticMesh(Default.StaticMesh);
                currentState = LOD_Near;
            }
            setTimer(1.0f, true);
        } else {
            SetStaticMesh(LODfarMesh);
        }
    } else if (level.GetLocalPlayerController() != none) {
        if(currentState == LOD_Far          && VSize(Location - level.GetLocalPlayerController().Pawn.Location) < LODdist - threshold) {
            SetStaticMesh(Default.StaticMesh);
            currentState = LOD_Near;
            SetRotation(Default.Rotation);
        } else if(currentState == LOD_Near  && VSize(Location - level.GetLocalPlayerController().Pawn.Location) > LODdist + threshold) {
            SetStaticMesh(LODfarMesh);
            currentState = LOD_Far;
        }
 
        if(LODrotate == true && currentState == LOD_Far) {
            SetRotation(Rotator(Location - level.GetLocalPlayerController().Pawn.Location));
        }
    } else {
        waitForPlayer();
    }
}
 
defaultProperties {
    StaticMesh=StaticMesh'cf_staticMushrooms.cf_gdc_mushroomPile01';
    LODfarMesh=StaticMesh'cf_staticMushrooms.cf_gdc_mushroom10';
    LODdist=1500;
    LODrotate=true;
 
    // Make it look different in UEd
    Texture=Texture'XEffectMat.Combos.greencross';
    bHidden=false;
    bHiddenEd=false;
 
    // Client server things - this flag combo is crucial!
    bTearOff=true;
    bNetTemporary=True;
    bGameRelevant=true;
    bNoDelete=true;
    RemoteRole=ROLE_SimulatedProxy;
 
    // Various other CPU Saving things
    Physics=PHYS_None;
 
    // Make it behiave like a normal static mesh
    bShadowCast=True;
    bCollideActors=True;
    bBlockActors=True;
    bBlockKarma=True;
    bWorldGeometry=True;
    CollisionHeight=+000001.000000;
    CollisionRadius=+000001.000000;
    bAcceptsProjectors=True;
    bUseDynamicLights=true;
    DrawType=DT_StaticMesh;
}

I hope someone finds this useful... If you have any comments, or think something should have been done better, please don't hesitate.

Comments:[edit]


Ransico: This is my first real contribution to the wiki, I hope someone finds it useful :)

MythOpus: Could you not eliminate the need for having a 'waiting' state and just make it a far or near state by default (preferably far as near may be bad for some people). That's basically how Renegade works... sort of. When you first start a game, all the textures and meshes are all minimum quality until the rendering kicks in and realizes everything should look a bit better so it renders accordingly.

HaZarD.ep: Does this really bring performance improvement? As far as I know static meshes are rendered very fast, as they are are static...when always switching back and forth this will certainly cost performance as well. Anyone done some fps test?

Ransico: The idea behind this was for a -massive- outdoor terrain, where everything was viewable at once, and there were craploads of tree's. with around 200 tree's in the world at 1 time, it would require very very low detail meshes... so I designed this to switch to a higher detail when you came up close. Basically, my low detail mesh consists of a plane... and the high detail a good polygon tree.

Ransico: Oh, and the waiting for player state is designed for when the players pawn dies, and is waiting for a respawn.