-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathconvert_spacecraft_3ds.py
More file actions
110 lines (88 loc) · 3.37 KB
/
Copy pathconvert_spacecraft_3ds.py
File metadata and controls
110 lines (88 loc) · 3.37 KB
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
import argparse
import os
import sys
import bpy
from mathutils import Vector
def reset_scene():
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
def find_mesh_objects():
return [obj for obj in bpy.context.scene.objects if obj.type == "MESH"]
def decimate_meshes(ratio):
if ratio >= 0.999:
return
for obj in find_mesh_objects():
modifier = obj.modifiers.new(name="DecimateRuntime", type="DECIMATE")
modifier.ratio = ratio
modifier.use_collapse_triangulate = True
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.modifier_apply(modifier=modifier.name)
obj.select_set(False)
def center_and_scale(target_extent):
meshes = find_mesh_objects()
if not meshes:
raise RuntimeError("No mesh objects were imported")
min_corner = [float("inf")] * 3
max_corner = [float("-inf")] * 3
for obj in meshes:
for corner in obj.bound_box:
world = obj.matrix_world @ Vector(corner)
for i in range(3):
min_corner[i] = min(min_corner[i], world[i])
max_corner[i] = max(max_corner[i], world[i])
center = [(min_corner[i] + max_corner[i]) * 0.5 for i in range(3)]
max_extent = max(max_corner[i] - min_corner[i] for i in range(3))
scale = target_extent / max_extent if max_extent > 1.0e-8 else 1.0
for obj in meshes:
obj.location.x -= center[0]
obj.location.y -= center[1]
obj.location.z -= center[2]
obj.scale = (obj.scale[0] * scale, obj.scale[1] * scale, obj.scale[2] * scale)
bpy.ops.object.select_all(action="DESELECT")
for obj in meshes:
obj.select_set(True)
bpy.context.view_layer.objects.active = meshes[0]
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
def triangulate_meshes():
for obj in find_mesh_objects():
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.mesh.quads_convert_to_tris()
bpy.ops.object.mode_set(mode="OBJECT")
obj.select_set(False)
def export_obj(output_path):
bpy.ops.object.select_all(action="DESELECT")
meshes = find_mesh_objects()
for obj in meshes:
obj.select_set(True)
bpy.context.view_layer.objects.active = meshes[0]
bpy.ops.wm.obj_export(
filepath=output_path,
export_selected_objects=True,
export_materials=True,
export_triangulated_mesh=True,
)
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--target-extent", type=float, default=2.0)
parser.add_argument("--decimate-ratio", type=float, default=1.0)
args = parser.parse_args(argv)
reset_scene()
bpy.ops.import_scene.autodesk_3ds(filepath=os.path.abspath(args.input))
decimate_meshes(args.decimate_ratio)
triangulate_meshes()
center_and_scale(args.target_extent)
os.makedirs(os.path.dirname(os.path.abspath(args.output)), exist_ok=True)
export_obj(os.path.abspath(args.output))
if __name__ == "__main__":
argv = sys.argv
if "--" in argv:
argv = argv[argv.index("--") + 1 :]
else:
argv = []
main(argv)