First Pythons script LOD WIP

This is my first attempt at a relatively complicated Python script. Terrachild was so kind as to help me with a measuring script which I got working. So far so good.

import bpy

cam=bpy.data.objects['Camera'].location
object=bpy.data.objects['Cube'].location

def get_distance(point1, point2):
    v = point1-point2
    return v.length

length=get_distance(cam, object)

print(length)

Im getting the correct distance so that works out well.

Instead of the code:

bpy.data.objects['Cube'].location

I would like to substitute ‘Cube’ with something more generic. I dont want to type an enormous list of al the LOD objects in the scene, there has to be a better way.

I intend to use this script to render a forest economicly with the objects near the camera with high detail and the ones far away with less detail. I’m going to create multiple variations of a set of trees, a high rez, medium rez and low rez one.

These objects wil be hidden based on their distance to the camera.

Object.hide
Object.hide_render

If I duplicate the trees to build the forest I would get filenames like “tree_HR.011”, “tree_LR.309”, etc. If I create a forest like that I’ll go crazy typing al the names in the script.

If anyone knows a good way of doing this I would much apriciate it.

I tested this, it works:


for ob in bpy.data.objects:
    d = get_distance(cam, ob.location)
            
    if d > 16:
        bpy.data.objects[ob.name].hide_render = True
        #Or
        bpy.data.objects[ob.name].hide = True 

Here’s another option that may prove useful.
If the name of all of you tree objects starts with “tree”, like, “tree.001, tree.002” etc. then the added line below:

if ob.name.find("tree") == 0:  

will check to see each object’s name starts with “tree”
If it does, then it will do the distance checking, and hiding.
This will let you name your objects, and independently hide or show them by type.


for ob in bpy.data.objects:
    if ob.name.find("tree") == 0:    
        d = get_distance(cam, ob.location)
            
        if d > 16:
            bpy.data.objects[ob.name].hide_render = True
            #Or
            bpy.data.objects[ob.name].hide = True

I’ll try it out asap, thank you very much. :stuck_out_tongue:

maybe it is better to check if the name ‘startswith(“tree”)’ otherwise myhousetree would be found (e.g.) :wink:
Otherwise terraschild’s code looks very good!

PKHG, that’s what the following line does:

if ob.name.find("tree") == 0:

“myhousetree” will fail this test because the position of the sub-string “tree” will return “7” with “.find”

If the test string is not found then “.find” returns “-1”
If the sub-string is found then “.find” returns the index position counting from “0” from the start of the searched string.

As a result, the code above will only be true for objects whose name begins with “tree”

In addition to the string ‘tree’ or maybe instead, I also plan to evaluate on the string ‘_HR’, ‘_MR’ and ‘_LR’ representing; High Resolution, Medium Resolution and Low Resolution. This wil make it easier to add other types of objects other then trees to the LOD system.

HR, LR and MR will need to be evaluated for different distances, for example:
HR distance from camera 0 to 50 BU/ or meters
MR distance from camera 51 to 100 BU/ or meters
LR distance from camera 101 to 500 BU/ or meters
OFF distance from camera 501 and greater BU/ or meters

So you would have something like the following:
tree_01_HR.001 --> High Resolution
tree_01_MR.001 --> Medium Resolution
tree_01_LR.001 --> Low Resolution

And you would be able to do the same thing for a ‘shrubbery’ without changing the script:
shrubbery_01_HR.012 --> High Resolution
shrubbery_01_MR.012 --> Medium Resolution
shrubbery_01_LR.012 --> Low Resolution

I wont be able to test anything until later today, so Ill post some examples this evening.

Stupid from Peter, should have looked what find returns, your are right!

I got it working :slight_smile:

There’s probably a neater way of writing this but it does what it’s supposed to.

For some reason I couldnt change the following code:

if ob_HR.name.find("HR_")==0

to

if ob_HR.name.find("HR")

Removing ==0 gave an error, I just wanted to search for the string “HR” regardless of its position. I probably was oversimplefying it a bit.

I got it working by changing the names of the LOD object to start with HR_something, MR_something, LR_something, etc.

import bpy

def get_distance(point1, point2):
    v = point1-point2
    return v.length

cam=bpy.data.objects['Camera'].location


for ob_HR in bpy.data.objects:
    if ob_HR.name.find("HR_")==0:    
        d = get_distance(cam, ob_HR.location)
            
        if d < 15: # _HR Objects 15 BU away and less are visible
            bpy.data.objects[ob_HR.name].hide_render = False
            bpy.data.objects[ob_HR.name].hide = False
            
        if d > 15: # _HR Objects further then 15 BU away are are hidden
            bpy.data.objects[ob_HR.name].hide_render = True
            bpy.data.objects[ob_HR.name].hide = True
         
            
for ob_MR in bpy.data.objects:    
     if ob_MR.name.find("MR_")==0:    
        d = get_distance(cam, ob_MR.location)
            
        if d < 30: # _MR Objects 30 BU away and less are visible
            bpy.data.objects[ob_MR.name].hide_render = False
            bpy.data.objects[ob_MR.name].hide = False
            
        if d < 15: # _MR Objects 15 BU away and less are hidden
            bpy.data.objects[ob_MR.name].hide_render = True
            bpy.data.objects[ob_MR.name].hide = True
            
        if d > 30: # _MR Objects further then 30 BU away are are hidden
            bpy.data.objects[ob_MR.name].hide_render = True
            bpy.data.objects[ob_MR.name].hide = True
            
            
for ob_LR in bpy.data.objects:    
     if ob_LR.name.find("LR_")==0:    
        d = get_distance(cam, ob_LR.location)
                   
        if d < 50: # _LR Objects 50 BU away and less are visible
            bpy.data.objects[ob_LR.name].hide_render = False
            bpy.data.objects[ob_LR.name].hide = False
            
        if d < 30: # _LR Objects 30 BU away and less are hidden
            bpy.data.objects[ob_LR.name].hide_render = True
            bpy.data.objects[ob_LR.name].hide = True
            
        if d > 50: # _LR Objects further then 50 BU away are are hidden
            bpy.data.objects[ob_LR.name].hide_render = True
            bpy.data.objects[ob_LR.name].hide = True

I basicly need this script to work when rendering an animation. It would also be benefitial to have it running in realtime in the 3d workspace and on framechange.

I couldnt find anything on this, so help would be apriciated. I’ve added the Blend file with the script.

I’m almost there :slight_smile:

Attachments

MadMesh_LOD_script_wip.blend (524 KB)

Replacing:

if ob_HR.name.find("HR_")==0:

with

if ob_HR.name.find("HR")!=-1:

works better :slight_smile: