LoD level of detail


#
# LoD by cotaks
#


# Place a property on the object that needs LoD, call it lod_mesh and put the origional object name in it.
# Make a low poly mesh, call that mesh: origionalname_far (so put _far behind the name that you used in last step).
# Add the origional mesh name to the dict in get_distances(cont)

# Only 1 object type needs a property, either the high one or low one depending on what you place in the main scene.


# Use the update_lod_list(cont) to update the list when needed


def lod(cont):
    
    own = cont.owner

    if not 'lod_list' in own:
        update_lod_list(cont)
        get_distances(cont)
    
    #Assign the object where the lod calculates from
    player = own.scene.active_camera
                
    for obj in own['lod_list']:
        
        distance    = player.getDistanceTo(obj)
        mesh_name   = obj['lod_mesh']
            
        # get LOD distances
        min, max  = own['lod_distances'][mesh_name][0], own['lod_distances'][mesh_name][1]
        
        if distance <= min:
            visible(obj, True)           
            change_mesh(obj, mesh_name)
        elif distance > min and distance <= max:
            visible(obj, True)
            change_mesh(obj, mesh_name + '_far')
        else:
            visible(obj, False)  


def update_lod_list(cont):
    
    own = cont.owner   
    own['lod_list'] = [obj for obj in own.scene.objects if 'lod_mesh' in obj]
          
             
def get_distances(cont):
       
    own = cont.owner
    
    own['lod_distances'] = { # mesh name - min - max
                    'Cylinder.003':         [10,20], 
                    'flower_red':           [20,50],
                    'flower_blue':          [20,40],
                    'platform_stone':       [40,75],
                    'platform_grass':       [40,75],
                    'platform_sand':        [40,75],
                    'platform_tree':        [40,75]
                    }


def visible(obj, state):
    
    if state:
        if not obj.visible:
            #obj.restoreDynamics()
            obj.visible = True
            
    elif not state:
        if obj.visible:
            #obj.suspendDynamics()
            obj.visible = False
        

def change_mesh(obj, mesh_name):
    
    mesh = obj.meshes[0].name


    if mesh != mesh_name:
        obj.replaceMesh(mesh_name)
1 Like

This is almost exactly what I was doing with my LOD script :smile:

I ended up scrapping it though…since I now have so much stuff being dynamically generated and removed that it was getting long in the teeth and I had to keep updating the lod objects list…which was hurting performance…but the method is sound.

This script is better than the integrated lod manager in the BGE? if so, in wich way?

you can adjust things more dynamically for one without needing to go and change all the lod ranges for example…and you can change other settings as show above(suspendDynamics())…

it is slower though…mine was at least :blush:

Better in terms of faster, no, the build in should be faster.
Better in terms of do whatever you want, yes because you can do whatever you want without the restrictions of the build in mechanism. turn objects invisible, remove/add objects, change distances on the fly instead of 1 by 1, build a lod menu for it and the user can change the distances on the fly, just to name a few things.

But if you are building an open world, with over 3000 objects (in the list), it will take a bite out of the performance, however you can set the tic rate in the always controlled to counter it. I have no idea how the build in react to that amount.

it doesn’t do very well…I tried that with 2K trees and even with the tick rate at 60 there were other issues with blender and the GE in general that just didn’t get along well…

OTOH I do not remember if I just place 2K trees or loaded them via code??? so this can be tested I guess…I just don’t have time to play with this atm :blush:

It of course depends on the user system as well, i can handle 3500, with tic rate set to 60 (once a second update). But it will eat away performance every second, from 72+ to around 58-62.

For huge open world’s i recommend using less objects by joining them together, or simply try to use the build in lod system and see if that works (i never used the build in, so i don’t know).

it may be better to update a sub list of objects(based off the initial list) to update every 30 ticks based on distance and have all the other objects just set to invisible or whatever on init.

only update this sub list if the player moves…this way it happens less often and is only cycling through a portion of the objects.

just an idea.