-
Notifications
You must be signed in to change notification settings - Fork 0
/
shapes_builder.py
203 lines (170 loc) · 7.7 KB
/
shapes_builder.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import os
import tools
import config
import xml.etree.ElementTree as etree
def build(root, geometries, materials_ids, links_simple, links_revert):
"""
Exports all the geometry into a folder for later use in the scene.
Return a list of ids for the geometry
"""
if config.verbose : print("shapes_builder_fbx launched")
savepath = config.filepath+"export\\meshes\\"
if not os.path.exists(savepath) :
os.makedirs(savepath)
comment = etree.Comment("Shapes.")
root.append(comment)
geometries_id = []
# Only keep geometries with polygonvertex
geometries = [geometry for geometry in geometries if geometry.find("PolygonVertexIndex") != None ]
for geometry in geometries :
id, type, obj = geometry.get("value").replace("::","").split(", ")
if obj != "Mesh" : print("Unknown Geometry obj : "+obj+" (id="+id+")")
geometries_id.append(id)
if id not in links_revert :
if verbose : print("Model "+id+" never used. Not writing it to file.")
else :
properties = tools.getProperties(geometry)
linked_materials = links_revert[id] if id in links_revert else [] # Get the model(s) containing this geometry (Only the models reference materials)
if len(linked_materials) == 1 :
linked_materials = links_simple[linked_materials[0]]
else :
print("Multiple models containing geometry "+id+" ???")
linked_materials = []
linked_materials = [link for link in linked_materials if link in materials_ids] #Only keep ids of materials
# I think that the index for materials is based on the order they appear in the file
# Maybe not, but i see no other info in the fbx to know that, so that's what i use and it seems to work
vertices_data = geometry.find("Vertices")
nb_vertices = int(vertices_data.get("value").replace("*",""))
polygons_data = geometry.find("PolygonVertexIndex")
nb_poly_ind = int(polygons_data.get("value").replace("*",""))
edges_data = geometry.find("Edges")
nb_edges = int( edges_data.get("value").replace("*",""))
normal_layer = geometry.find("LayerElementNormal")
if normal_layer != None :
normals_data = normal_layer.find("Normals")
normalsW_data = normal_layer.find("NormalsW")
nb_normals = int( normals_data.get("value").replace("*",""))
nb_normalsW = int(normalsW_data.get("value").replace("*",""))
uv_layer = geometry.find("LayerElementUV")
if uv_layer != None :
uv_data = uv_layer.find("UV")
uv_index_data = uv_layer.find("UVIndex")
nb_uv_data = int( uv_data.get("value").replace("*",""))
nb_uv_index = int(uv_index_data.get("value").replace("*",""))
material_layer= geometry.find("LayerElementMaterial")
if material_layer != None :
material_data = list(map(int, material_layer.find("Materials").find("a").text.split(",")))
if material_layer.find("MappingInformationType").text == "AllSame" :
material_data = nb_poly_ind * [material_data[0]]
vertices_in = [tools.str2float2str(num) for num in vertices_data.find("a").text.split(",")]
polygons_in = list(map(int, polygons_data.find("a").text.split(",")))
edges_in = [tools.str2float2str(num) for num in edges_data.find("a").text.split(",")]
normals_in = [tools.str2float2str(num) for num in normals_data.find("a").text.split(",")]
normalsW_in = [tools.str2float2str(num) for num in normalsW_data.find("a").text.split(",")]
uv_in = [tools.str2float2str(num) for num in uv_data.find("a").text.split(",")]
uv_index_in = list(map(int, uv_index_data.find("a").text.split(",")))
vertices, polygon_vertex_index, normals, uv = [], [], [], []
if nb_vertices % 3 != 0 :
print("Points values not a multiple of 3 !")
for i in range(int(nb_vertices / 3)) :
vertices.append(vertices_in[3*i : 3*i+3])
curr_vertex = []
for index in polygons_in :
if index < 0 :
curr_vertex.append(-index-1)
polygon_vertex_index.append(curr_vertex)
curr_vertex = []
else :
curr_vertex.append(index)
nb_polygons = len(polygon_vertex_index)
if normal_layer != None :
normal_type = normal_layer.find("ReferenceInformationType").text
if normal_type == "Direct" :
for i in range(int(nb_normals/3)) :
normals.append(normals_in[3*i : 3*i+3])
elif normal_type == "IndexToDirect" :
# TODO
print("NORMAL INDEXTODIRECT DOESN'T WORK RIGHT NOW")
else :
print("Unknown ReferenceInformationType for normal in obj "+id)
else :
print("NO NORMALS for object with id "+id)
if uv_layer != None :
uv_type = uv_layer.find("ReferenceInformationType").text
if uv_type == "Direct" :
for i in range(int(nb_uv_data/2)) :
uv.append(uv_in[2*i : 2*i+2])
elif uv_type == "IndexToDirect" :
for i in range(int(nb_uv_index)) :
index = uv_index_in[i]
uv.append(uv_in[2*index : 2*index+2])
else :
print("Unknown ReferenceInformationType for uv in obj "+id)
uv = ["0 0"] * nb_poly_ind
else :
if config.verbose : print("No uv for object with id "+id+". Using default of 0, 0")
uv = ["0 0"] * nb_poly_ind
materials = geometry.find("LayerElementMaterial")
if materials != None :
materials = list(map(int, materials.find("Materials").find("a").text.split(",")))
if materials == None or len(materials) <= 1 :
materials = [0 for i in range(nb_polygons)]
max_material = max(materials)
# The shapegroup will contain all meshes with different materials, and allow instanciation
shapegroup = tools.create_obj(root, "shape", "shapegroup", id)
# Initialize
for i in range(max_material + 1) :
vertex_text = []
poly_index = []
total_index = 0
curr_polygon_vertex_num = 0
for j in range(len(polygon_vertex_index)) :
vertex_indexes = polygon_vertex_index[j]
curr_poly_index = []
for k in range(len(vertex_indexes)) :
# Only keep polygons with the current material
if material_layer == None or material_data[j] == i :
curr_poly_index.append(str(total_index))
total_index += 1
vertex_index = vertex_indexes[k]
curr_vertex_text = " ".join(vertices[vertex_index]) + " "
curr_vertex_text += " ".join( normals[curr_polygon_vertex_num]) + " "
curr_vertex_text += " ".join( uv[curr_polygon_vertex_num])
vertex_text.append(curr_vertex_text)
curr_polygon_vertex_num += 1
# Generate multiple triangle to replace polygons (not supported by Mitsuba Renderer)
if len(curr_poly_index) > 3 :
for k in range(len(curr_poly_index) - 2) :
curr_poly = [curr_poly_index[0]] + curr_poly_index[k+1:k+3]
poly_index.append(curr_poly)
elif len(curr_poly_index) > 0 :
poly_index.append(curr_poly_index)
if vertex_text != [] : # Export only non-empty objects
output = open(savepath+id+"_"+str(i)+".ply", "w")
output.write("ply\n")
output.write("format ascii 1.0\n")
output.write("element vertex " + str(len(vertex_text))+"\n")
output.write(
"""property float32 x
property float32 y
property float32 z
property float32 nx
property float32 ny
property float32 nz
property float32 u
property float32 v
""")
output.write("element face "+str(len(poly_index))+"\n")
output.write("property list uint8 int32 vertex_indices\n")
output.write("end_header\n")
for vert in vertex_text :
output.write(vert+"\n")
for poly in poly_index : # Only triangles
output.write("3 "+" ".join(poly)+"\n")
shape = tools.create_obj(shapegroup, "shape", "ply")
tools.set_value(shape, "string", "filename", "meshes/"+id+"_"+str(i)+".ply")
try :
tools.set_value(shape, "ref", "bsdf", linked_materials[i])
except IndexError :
if config.verbose : print("No material found for object "+id+", index "+str(i))
return geometries_id