@@ -1825,7 +1825,7 @@ def __init__(self):
18251825 + os .pathsep
18261826 + os .environ ["PATH" ]
18271827 )
1828-
1828+
18291829
18301830 def read_primitive_mesh (self , br , primitive_count , aloc_name ):
18311831 for primitive_index in range (primitive_count ): # size of box = 52
@@ -2241,6 +2241,18 @@ def load_aloc(filepath):
22412241 return aloc , [aloc_obj ]
22422242
22432243
2244+ def get_local_space_bbox_center (obj ):
2245+ return 0.125 * sum ((mathutils .Vector (ls_corner ) for ls_corner in obj .bound_box ), mathutils .Vector ())
2246+
2247+
2248+ def get_bounding_sphere_data (obj , ws_mat , lsbbox_center = None ):
2249+ if lsbbox_center is None :
2250+ lsbbox_center = get_local_space_bbox_center (obj )
2251+ wsbbox_center = ws_mat @ lsbbox_center
2252+ radius = max ((mathutils .Vector (ws_mat @ mathutils .Vector (ls_corner )) - wsbbox_center ).xy for ls_corner in obj .bound_box )
2253+ return wsbbox_center , radius .length
2254+
2255+
22442256def load_scenario (context , path_to_nav_json , path_to_output_obj_file , mesh_type , lod_mask , build_type ):
22452257 start = timer ()
22462258 log ("INFO" , "Loading scenario." , "load_scenario" )
@@ -2253,6 +2265,34 @@ def load_scenario(context, path_to_nav_json, path_to_output_obj_file, mesh_type,
22532265 room_color_index = 0
22542266 room_folder_color_index = 0
22552267 geo_node_name = "HitmanMapNode"
2268+
2269+ #Get the "pathfinding include" box
2270+ pf_include_box_info = None
2271+ pf_box_bounding_sphere_center = None
2272+ pf_box_bounding_sphere_radius = None
2273+ for pf_box in data ['pfBoxes' ]:
2274+ if pf_box ["type" ]["data" ] == "PFBT_INCLUDE_MESH_COLLISION" :
2275+ coords = ["w" ,"x" ,"y" ,"z" ]
2276+ pf_include_box_info = [
2277+ mathutils .Vector ([pf_box ["position" ][coord ] for coord in coords [1 :]]),
2278+ mathutils .Quaternion ([pf_box ["rotation" ][coord ] for coord in coords ]),
2279+ mathutils .Vector ([pf_box ["scale" ]["data" ][coord ] for coord in coords [1 :]]),
2280+ ]
2281+ break
2282+ if pf_include_box_info is not None :
2283+ bpy .ops .mesh .primitive_cube_add (size = 1 )
2284+ box = bpy .context .active_object
2285+ box .location = pf_include_box_info [0 ]
2286+ box .rotation_mode = "QUATERNION"
2287+ box .rotation_quaternion = pf_include_box_info [1 ]
2288+ box .scale = pf_include_box_info [2 ]
2289+ bpy .context .view_layer .update ()
2290+ pf_box_bounding_sphere_center , pf_box_bounding_sphere_radius = get_bounding_sphere_data (box , box .matrix_world )
2291+ box .select_set (True )
2292+ bpy .context .view_layer .objects .active = box
2293+ bpy .ops .object .delete (use_global = False )
2294+
2295+ geo_node_name = "HitmanMapNode"
22562296 if build_type == "instance" :
22572297 #link the geonode
22582298 filepath = os .path .join (os .path .dirname (os .path .abspath (__file__ )), "res.blend" )
@@ -2268,7 +2308,7 @@ def load_scenario(context, path_to_nav_json, path_to_output_obj_file, mesh_type,
22682308 mesh_hash = hash_and_entity ['alocHash' ]
22692309 else :
22702310 mesh_hash = hash_and_entity ['primHash' ]
2271-
2311+
22722312 room_folder_name = hash_and_entity ["roomFolderName" ][:63 ]
22732313 if room_folder_name not in bpy .data .collections :
22742314 coll = bpy .data .collections .new (room_folder_name )
@@ -2290,7 +2330,7 @@ def load_scenario(context, path_to_nav_json, path_to_output_obj_file, mesh_type,
22902330 entity = hash_and_entity ['entity' ]
22912331 transform = {"position" : entity ["position" ], "rotate" : entity ["rotation" ],
22922332 "scale" : entity ["scale" ]["data" ], "id" : entity ["id" ]}
2293-
2333+
22942334 if mesh_hash not in transforms :
22952335 transforms [mesh_hash ] = []
22962336 room_names [mesh_hash ] = []
@@ -2374,13 +2414,26 @@ def load_scenario(context, path_to_nav_json, path_to_output_obj_file, mesh_type,
23742414 mesh_i += len (transforms [mesh_hash ])
23752415 continue
23762416 if build_type == "instance" :
2417+ #different instances transforms
2418+ aloc_positions = [mathutils .Vector ((transforms [mesh_hash ][i ]["position" ]["x" ], transforms [mesh_hash ][i ]["position" ]["y" ], transforms [mesh_hash ][i ]["position" ]["z" ])) for i in range (t_size )]
2419+ aloc_rotations = [mathutils .Quaternion ((transforms [mesh_hash ][i ]["rotate" ]["w" ], transforms [mesh_hash ][i ]["rotate" ]["x" ], transforms [mesh_hash ][i ]["rotate" ]["y" ], transforms [mesh_hash ][i ]["rotate" ]["z" ])).to_euler () for i in range (t_size )]
2420+ aloc_scales = [mathutils .Vector ((transforms [mesh_hash ][i ]["scale" ]["x" ], transforms [mesh_hash ][i ]["scale" ]["y" ], transforms [mesh_hash ][i ]["scale" ]["z" ])) for i in range (t_size )]
23772421 for obj in objects :
2378- # if mesh_hash +"_placement" in bpy.data.objects: #not sure why there are dups sometimes
2379- # continue
2380- #different instances transforms
2381- positions = [mathutils .Vector ((transforms [mesh_hash ][i ]["position" ]["x" ], transforms [mesh_hash ][i ]["position" ]["y" ], transforms [mesh_hash ][i ]["position" ]["z" ])) for i in range (t_size )]
2382- rotations = [mathutils .Quaternion ((transforms [mesh_hash ][i ]["rotate" ]["w" ], transforms [mesh_hash ][i ]["rotate" ]["x" ], transforms [mesh_hash ][i ]["rotate" ]["y" ], transforms [mesh_hash ][i ]["rotate" ]["z" ])).to_euler () for i in range (t_size )]
2383- scales = [mathutils .Vector ((transforms [mesh_hash ][i ]["scale" ]["x" ], transforms [mesh_hash ][i ]["scale" ]["y" ], transforms [mesh_hash ][i ]["scale" ]["z" ])) for i in range (t_size )]
2422+ culled_indices = set ()
2423+ #basic culling prepass using bounding spheres
2424+ if pf_box_bounding_sphere_center is not None :
2425+ lsbbox_center = get_local_space_bbox_center (obj )
2426+ for u , (pos , rot , scale ) in enumerate (zip (aloc_positions , aloc_rotations , aloc_scales )):
2427+ inst_mat = mathutils .Matrix .LocRotScale (pos , rot , scale )
2428+ instance_bbox_center , instance_bbox_radius = get_bounding_sphere_data (obj , inst_mat , lsbbox_center )
2429+ threshold = (instance_bbox_radius + pf_box_bounding_sphere_radius )
2430+ if (instance_bbox_center - pf_box_bounding_sphere_center ).length_squared > threshold * threshold :
2431+ culled_indices .add (u )
2432+
2433+ positions = [aloc_positions [u ] for u in range (t_size ) if u not in culled_indices ]
2434+ rotations = [aloc_rotations [u ] for u in range (t_size ) if u not in culled_indices ]
2435+ scales = [aloc_scales [u ] for u in range (t_size ) if u not in culled_indices ]
2436+
23842437 #create the "fake" placement mesh
23852438 mesh = bpy .data .meshes .new (mesh_hash + "_placement" )
23862439 mesh .from_pydata (positions , [], [])
@@ -2404,27 +2457,51 @@ def load_scenario(context, path_to_nav_json, path_to_output_obj_file, mesh_type,
24042457 modifier ["Socket_3" ] = "rotation"
24052458 modifier ["Socket_4" ] = "scale"
24062459 else :
2407- for i in range (0 , t_size ):
2408- mesh_transform = transforms [mesh_hash ][i ]
2460+ cur = None
2461+ aloc_positions = [mathutils .Vector ((transforms [mesh_hash ][i ]["position" ]["x" ], transforms [mesh_hash ][i ]["position" ]["y" ], transforms [mesh_hash ][i ]["position" ]["z" ])) for i in range (t_size )]
2462+ aloc_rotations = [mathutils .Quaternion ((transforms [mesh_hash ][i ]["rotate" ]["w" ], transforms [mesh_hash ][i ]["rotate" ]["x" ], transforms [mesh_hash ][i ]["rotate" ]["y" ], transforms [mesh_hash ][i ]["rotate" ]["z" ])) for i in range (t_size )]
2463+ aloc_scales = [mathutils .Vector ((transforms [mesh_hash ][i ]["scale" ]["x" ], transforms [mesh_hash ][i ]["scale" ]["y" ], transforms [mesh_hash ][i ]["scale" ]["z" ])) for i in range (t_size )]
2464+ o_size = len (objects )
2465+ positions = []
2466+ rotations = []
2467+ scales = []
2468+ for o_i in range (o_size ):
2469+ obj = objects [o_i ]
2470+ culled_indices = set ()
2471+ #basic culling prepass using bounding spheres
2472+ if pf_box_bounding_sphere_center is not None :
2473+ lsbbox_center = get_local_space_bbox_center (obj )
2474+ for u , (pos , rot , scale ) in enumerate (zip (aloc_positions , aloc_rotations , aloc_scales )):
2475+ inst_mat = mathutils .Matrix .LocRotScale (pos , rot , scale )
2476+ instance_bbox_center , instance_bbox_radius = get_bounding_sphere_data (obj , inst_mat , lsbbox_center )
2477+ threshold = (instance_bbox_radius + pf_box_bounding_sphere_radius )
2478+ if (instance_bbox_center - pf_box_bounding_sphere_center ).length_squared > threshold * threshold :
2479+ culled_indices .add (u )
2480+
2481+ positions .append ([aloc_positions [u ] for u in range (t_size ) if u not in culled_indices ])
2482+ rotations .append ([aloc_rotations [u ] for u in range (t_size ) if u not in culled_indices ])
2483+ scales .append ([aloc_scales [u ] for u in range (t_size ) if u not in culled_indices ])
2484+ for i in range (t_size ):
24092485 room_name = room_names [mesh_hash ][i ]
2410- p = mesh_transform ["position" ]
2411- r = mesh_transform ["rotate" ]
2412- s = mesh_transform ["scale" ]
2486+ mesh_id = transforms [mesh_hash ][i ]["id" ]
24132487 log ("INFO" , "Transforming " + mesh_type + " [" + str (current_mesh_in_scene_index ) + "/" + str (meshes_in_scenario_count ) + "]: " + mesh_hash + " #" + str (i ) + " Mesh: [" + str (mesh_i + 1 ) + "/" + str (mesh_count ) + "] Room name: " + room_name , "load_scenario" )
24142488 mesh_i += 1
2415- for obj in objects :
2416- if i != 0 :
2417- cur = obj .copy ()
2418- else :
2489+ for o_i in range (o_size ):
2490+ if i >= len (positions [o_i ]):
2491+ continue
2492+ obj = objects [o_i ]
2493+ if cur is None :
24192494 cur = obj
24202495 bpy .context .scene .collection .objects .unlink (obj )
2496+ else :
2497+ cur = obj .copy ()
24212498 bpy .data .collections .get (room_name ).objects .link (cur )
2422- cur .name = mesh_hash + "_" + mesh_transform [ "id" ]
2499+ cur .name = mesh_hash + "_" + mesh_id
24232500 cur .select_set (True )
2424- cur .scale = mathutils .Vector ((s [ "x" ], s [ "y" ], s [ "z" ]))
2501+ cur .scale = mathutils .Vector ((scales [ o_i ][ i ][ 0 ], scales [ o_i ][ i ][ 1 ], scales [ o_i ][ i ][ 2 ]))
24252502 cur .rotation_mode = 'QUATERNION'
2426- cur .rotation_quaternion = (r [ "w" ], r [ "x" ], r [ "y" ], r [ "z" ])
2427- cur .location = mathutils .Vector ((p [ "x" ], p [ "y" ], p [ "z" ]))
2503+ cur .rotation_quaternion = (rotations [ o_i ][ i ][ 0 ], rotations [ o_i ][ i ][ 1 ], rotations [ o_i ][ i ][ 2 ], rotations [ o_i ][ i ][ 3 ])
2504+ cur .location = mathutils .Vector ((positions [ o_i ][ i ][ 0 ], positions [ o_i ][ i ][ 1 ], positions [ o_i ][ i ][ 2 ]))
24282505 cur .select_set (False )
24292506
24302507 missing_mesh_hashes = transforms .keys () - processed_mesh_hashes
0 commit comments