Skip to content

Commit 62b2a21

Browse files
Joschukadbierek
andauthored
Add basic XY bounding sphere culling (#76)
Co-authored-by: Danny Bierek <dannybierek@gmail.com>
1 parent be4f3b5 commit 62b2a21

File tree

2 files changed

+101
-24
lines changed

2 files changed

+101
-24
lines changed

include/NavKit/NavKitConfig.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
#define NavKit_VERSION_MAJOR "2"
1+
#define NavKit_VERSION_MAJOR "2"
22
#define NavKit_VERSION_MINOR "6"
3-
#define NavKit_VERSION_PATCH "1"
3+
#define NavKit_VERSION_PATCH "0"

src/resource/glacier2obj.py

Lines changed: 99 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
22442256
def 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

Comments
 (0)