-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscene_split.py
153 lines (105 loc) · 3.82 KB
/
scene_split.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import mathutils
import bmesh
from .utils import *
@cache_as_property('_scene_split_catchment_boxes')
@yield_list
def room_catchment_boxes(room):
i = 0
for child in room.fast64_object.children:
if 'Bounds' in child.name:
child.name = f'Bounds{room.index}.{i}'
i += 1
yield child
def can_split(scene):
return 'Geom' in bpy.data.objects
def split(scene):
# The object to split into rooms
# TODO: Make this selectable
geom_obj = bpy.data.objects['Geom']
collection = scene.helper_collection('Split Room Geometry')
# TODO: Figure out why this needs to happen. If helpers are
# hidden, splitter fails to split anything. Why is evrything
# in Blender dependent on UI state. It's brittle and shitty.
# You just end up with code sprinkled with magic invocations
# like this and you have no idea how anything works.
scene.helpers.hide_viewport = False
for obj in bpy.data.objects:
if 'ExpGen' in obj.name:
obj.parent = None
bpy.data.objects.remove(obj)
for face in geom_obj.data.polygons:
face.hide = False
for room in scene.rooms:
room_geom = duplicate_object(geom_obj, collection)
room_geom.name = f'ExpGen {room} Geometry'
# Reparent to fast64_obj
for vertex in room_geom.data.vertices:
vertex.co = (
geom_obj.matrix_world @ vertex.co -
(room.fast64_object.matrix_world @ mathutils.Vector((0,0,0)))
)
room_geom.location = (0, 0, 0)
room_geom.parent = room.fast64_object
cull(room, room_geom)
if len(room_geom.data.vertices) == 0:
raise Exception(f"{room} has no vertices")
def cull(room, geom):
mesh = geom.data
log('culling', geom.name, 'to', room, '; mesh', mesh, 'npoly', len(mesh.polygons))
catchment_boxes = room_catchment_boxes(room)
log(len(catchment_boxes), 'catchment boxes')
started_with = len(mesh.polygons)
bpy.context.view_layer.update()
geom.hide_viewport = False
for obj in bpy.data.objects:
obj.select_set(False)
geom.select_set(True)
bpy.context.view_layer.objects.active = geom
bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
bm = bmesh.new()
bm.from_mesh(mesh)
bm.faces.ensure_lookup_table()
faces_to_delete=[
face for face in bm.faces if not any(
bounds_intersection(
object_bounds(catchment_box),
face_bounds(geom, face)
)
for catchment_box in catchment_boxes
)
]
bmesh.ops.delete(
bm,
geom=faces_to_delete,
context='FACES'
)
bm.to_mesh(mesh)
log('culled', geom.name, mesh, '; result npoly = ', len(mesh.polygons))
assert len(mesh.polygons) == started_with - len(faces_to_delete)
def face_bounds(obj, bm_face):
cos = [
obj.matrix_world @ vert.co
for vert in bm_face.verts
]
return points_bounds(cos)
def polygon_bounds(obj, mesh, polygon):
cos = [
obj.matrix_world @ mathutils.Vector(mesh.vertices[i].co)
for i in polygon.vertices
]
return points_bounds(cos)
def move_actors_to_their_rooms(scene):
move = {}
for actor in scene.actors:
for room in scene.rooms:
if room.fast64_object != actor.parent:
for box in room_catchment_boxes(room):
pos = actor.matrix_world.translation
bounds = object_bounds(box)
if bounds.contains(pos):
move[actor] = room
for actor, room in move.items():
log(f"Move {actor} to {room}")
mw = actor.matrix_world
actor.parent = room.fast64_object
actor.matrix_world = mw