Skip to content

Commit e48afd4

Browse files
committed
update for the mzd and template
1 parent bc59de8 commit e48afd4

6 files changed

Lines changed: 253 additions & 58 deletions

File tree

build_addon.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
from zipfile import ZipFile
22
import os
33

4+
45
addondirectory = 'simloader'
5-
templatedirectory = 'template'
6+
templatedirectory = 'template'
7+
mzddirectory = 'mzd'
68
meshiodirectory = 'extern/meshio/src/meshio'
79
fileseqdirectory = 'extern/fileseq/src/fileseq'
810
futuredirectory = 'extern/python-future/src/future'
911
richdirectory = 'extern/rich/rich'
1012

11-
12-
dirs = {addondirectory:addondirectory,
13-
templatedirectory:templatedirectory,
14-
meshiodirectory:'meshio',
15-
fileseqdirectory:'fileseq',
16-
futuredirectory:'future',
17-
richdirectory:'rich',
13+
dirs = {
14+
addondirectory: addondirectory,
15+
templatedirectory: templatedirectory,
16+
meshiodirectory: 'meshio',
17+
fileseqdirectory: 'fileseq',
18+
futuredirectory: 'future',
19+
richdirectory: 'rich',
20+
mzddirectory: mzddirectory,
1821
}
1922

20-
with ZipFile('simloader_addon.zip','w') as addonzip:
23+
with ZipFile('simloader_addon.zip', 'w') as addonzip:
2124
# write all directories
22-
for k,v in dirs.items():
25+
for k, v in dirs.items():
2326
for subdir, dirs, files in os.walk(k):
2427
for file in files:
25-
if "__pycache__" in subdir:
28+
if "__pycache__" in subdir:
2629
continue
2730
filepath = os.path.join(subdir, file)
28-
relative_path = os.path.relpath(filepath,k)
31+
relative_path = os.path.relpath(filepath, k)
2932
endpath = os.path.join(v, relative_path)
3033
endpath = os.path.join('simloaderaddon/', endpath)
31-
addonzip.write(filepath,endpath)
34+
addonzip.write(filepath, endpath)
3235

3336
# write init.py
34-
addonzip.write('__init__.py','simloaderaddon/__init__.py')
35-
36-
37+
addonzip.write('__init__.py', 'simloaderaddon/__init__.py')

mzd/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .mzd import readMZD
1+
from .mzd import readMZD_to_bpymesh,readMZD_to_meshio
22

33

4-
__all__ = [readMZD]
4+
__all__ = [readMZD_to_bpymesh,readMZD_to_meshio]

mzd/mzd.py

Lines changed: 152 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
num_nodes_to_name = {3: 'triangle', 4: 'quad'}
88

99

10-
# import bpy
11-
def readMZD(filepath):
10+
def readMZD_to_meshio(filepath):
1211
out_numVertices = None
1312
out_numPolygons = None
1413
out_vertPositions = None
@@ -129,6 +128,156 @@ def readMZD(filepath):
129128
out_vertAttribute = np.frombuffer(byte, dtype=np.float32)
130129
point_data['uvw_map'] = out_vertAttribute.reshape((out_numVerticeAttributes, 3))
131130

131+
# For the rest of attributes, because meshio doest not support attributes on nodes, (equivalent to face cornder in blender)
132+
# So the attributes data will be skipped
133+
elif chunkID == 0xDA7A0011: # node normals.
134+
file.seek(size, 1)
135+
pass
136+
elif chunkID == 0xDA7A0013: # node colors.
137+
file.seek(size, 1)
138+
pass
139+
elif chunkID == 0xDA7A0014: # node UVWs.
140+
file.seek(size, 1)
141+
pass
142+
else:
143+
file.seek(size, 1)
144+
pass
145+
return meshio.Mesh(out_vertPositions.reshape((out_numVertices, 3)), cells, point_data)
146+
147+
def readMZD_to_bpymesh(filepath, mesh):
148+
shade_scheme = False
149+
if mesh.polygons:
150+
shade_scheme = mesh.polygons[0].use_smooth
151+
152+
if len(mesh.vertices)>0:
153+
mesh.clear_geometry()
154+
155+
out_numVertices = None
156+
out_numPolygons = None
157+
out_vertPositions = None
158+
out_numNodes = None # number of loops
159+
out_polyVIndicesNum = None # faces_loop_total
160+
out_polyVIndices = None #loops_vert_idx
161+
162+
with open(filepath, 'rb') as file:
163+
byte = file.read(24)
164+
if byte != head:
165+
return -4
166+
while 1:
167+
# check if it reach the end
168+
byte = file.read(24)
169+
if byte == end:
170+
break
171+
else:
172+
# if not reach the end, rewind the pointer back 24 bytes
173+
file.seek(-24, 1)
174+
175+
byte = file.read(4)
176+
chunkID = int.from_bytes(byte, byteorder='little')
177+
178+
byte = file.read(24)
179+
name = byte
180+
181+
byte = file.read(4)
182+
size = int.from_bytes(byte, byteorder='little')
183+
184+
if chunkID == 0x0ABC0001: # vertices and polygons.
185+
186+
byte = file.read(4)
187+
out_numVertices = int.from_bytes(byte, byteorder='little')
188+
if out_numVertices < 0:
189+
return -127
190+
if out_numVertices == 0:
191+
break
192+
193+
byte = file.read(12 * out_numVertices)
194+
out_vertPositions = np.frombuffer(byte, dtype=np.float32)
195+
196+
byte = file.read(4)
197+
out_numPolygons = int.from_bytes(byte, byteorder='little')
198+
199+
byte = file.read(out_numPolygons)
200+
out_polyVIndicesNum = np.frombuffer(byte, dtype=np.uint8)
201+
out_numNodes = out_polyVIndicesNum.sum(dtype=np.int32)
202+
203+
byte = file.read(4)
204+
numBytesPerPolyVInd = int.from_bytes(byte, byteorder='little')
205+
206+
if numBytesPerPolyVInd == 4:
207+
# int
208+
byte = file.read(out_numNodes * numBytesPerPolyVInd)
209+
out_polyVIndices = np.frombuffer(byte, dtype=np.int32)
210+
elif numBytesPerPolyVInd == 2:
211+
# unsigned short
212+
byte = file.read(out_numNodes * numBytesPerPolyVInd)
213+
# WARNING: not sure if it's correct
214+
# uncovered branch from test data
215+
out_polyVIndices = np.frombuffer(byte, dtype=np.uint16)
216+
else:
217+
return -127
218+
219+
mesh.vertices.add(out_numVertices)
220+
mesh.vertices.foreach_set('co',out_vertPositions)
221+
222+
mesh.loops.add(out_numNodes)
223+
mesh.loops.foreach_set('vertex_index',out_polyVIndices)
224+
225+
mesh.polygons.add(out_numPolygons)
226+
mesh.polygons.foreach_set('loop_total',out_polyVIndicesNum)
227+
faces_loop_start = None
228+
229+
if out_polyVIndicesNum.size > 0:
230+
faces_loop_start = np.cumsum(out_polyVIndicesNum)
231+
faces_loop_start = np.roll(faces_loop_start, 1)
232+
faces_loop_start[0] = 0
233+
mesh.polygons.foreach_set('loop_start',faces_loop_start)
234+
mesh.polygons.foreach_set("use_smooth", [shade_scheme] * out_numPolygons)
235+
mesh.update()
236+
mesh.validate()
237+
238+
elif chunkID == 0xDA7A0001: # vertex normals.
239+
byte = file.read(4)
240+
out_numVerticeAttributes = int.from_bytes(byte, byteorder='little')
241+
if out_numVerticeAttributes != out_numVertices:
242+
return -127
243+
244+
byte = file.read(out_numVerticeAttributes * 6)
245+
out_vertAttribute = np.frombuffer(byte, dtype=np.uint16)
246+
out_vertAttribute = table[out_vertAttribute]
247+
# point_data['normal'] = out_vertAttribute.reshape((out_numVerticeAttributes, 3))
248+
249+
elif chunkID == 0xDA7A0002: # vertex motions
250+
byte = file.read(4)
251+
out_numVerticeAttributes = int.from_bytes(byte, byteorder='little')
252+
if out_numVerticeAttributes != out_numVertices:
253+
return -127
254+
255+
byte = file.read(out_numVerticeAttributes * 6)
256+
out_vertAttribute = np.frombuffer(byte, dtype=np.uint16)
257+
out_vertAttribute = table[out_vertAttribute]
258+
# point_data['velocity'] = out_vertAttribute.reshape((out_numVerticeAttributes, 3))
259+
260+
elif chunkID == 0xDA7A0003: # vertex colors
261+
byte = file.read(4)
262+
out_numVerticeAttributes = int.from_bytes(byte, byteorder='little')
263+
if out_numVerticeAttributes != out_numVertices:
264+
return -127
265+
266+
byte = file.read(out_numVerticeAttributes * 8)
267+
out_vertAttribute = np.frombuffer(byte, dtype=np.uint16)
268+
out_vertAttribute = table[out_vertAttribute]
269+
# point_data['color'] = out_vertAttribute.reshape((out_numVerticeAttributes, 3))
270+
271+
elif chunkID == 0xDA7A0004: # vertex UVWs.
272+
byte = file.read(4)
273+
out_numVerticeAttributes = int.from_bytes(byte, byteorder='little')
274+
if out_numVerticeAttributes != out_numVertices:
275+
return -127
276+
277+
byte = file.read(out_numVerticeAttributes * 12)
278+
out_vertAttribute = np.frombuffer(byte, dtype=np.float32)
279+
# point_data['uvw_map'] = out_vertAttribute.reshape((out_numVerticeAttributes, 3))
280+
132281
elif chunkID == 0xDA7A0011: # node normals.
133282
file.seek(size, 1)
134283
print(6)
@@ -144,8 +293,4 @@ def readMZD(filepath):
144293
else:
145294
# print(name)
146295
file.seek(size, 1)
147-
pass
148-
return meshio.Mesh(out_vertPositions.reshape((out_numVertices, 3)), cells, point_data)
149-
150-
def constructMZD(filepath):
151-
pass
296+
pass

simloader/importer.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from mathutils import Matrix
88
import mzd
99

10-
supported_mesh_format = [ 'triangle', 'quad']
10+
supported_mesh_format = ['triangle', 'quad']
1111

12-
def update_mesh(meshio_mesh, object):
12+
13+
def update_mesh(meshio_mesh, mesh):
1314
# extract information from the meshio mesh
14-
mesh = object.data
1515
mesh_vertices = meshio_mesh.points
1616

1717
n_poly = 0
@@ -26,15 +26,16 @@ def update_mesh(meshio_mesh, object):
2626
shade_scheme = mesh.polygons[0].use_smooth
2727
for cell in meshio_mesh.cells:
2828
if cell.type not in supported_mesh_format:
29-
if cell.type!="vertex":
29+
# vertex is not mesh type, but supported
30+
if cell.type != "vertex":
3031
show_message_box(cell.type + " is unsupported mesh format yet")
3132
continue
3233
data = cell.data
3334
n_poly += len(data)
3435
n_loop += data.shape[0] * data.shape[1]
3536
loops_vert_idx = np.append(loops_vert_idx, data.ravel())
3637
faces_loop_total = np.append(faces_loop_total, np.ones((len(data)), dtype=np.int32) * data.shape[1])
37-
if faces_loop_total.size>0:
38+
if faces_loop_total.size > 0:
3839
faces_loop_start = np.cumsum(faces_loop_total)
3940
# Add a zero as first entry
4041
faces_loop_start = np.roll(faces_loop_start, 1)
@@ -123,7 +124,7 @@ def create_obj(fileseq, use_relaitve, transform_matrix=Matrix([[1, 0, 0, 0], [0,
123124
object.SIMLOADER.enabled = enabled
124125
object.matrix_world = transform_matrix
125126
if enabled:
126-
update_mesh(meshio_mesh, object)
127+
update_mesh(meshio_mesh, object.data)
127128
bpy.context.collection.objects.link(object)
128129

129130

@@ -152,21 +153,27 @@ def update_obj(scene, depsgraph=None):
152153
show_message_box(traceback.format_exc(), "running script: " + obj.SIMLOADER.script_name + " failed: " + str(e),
153154
"ERROR")
154155
continue
155-
if 'preprocess' not in locals():
156-
show_message_box('function preprocess not found', "ERROR")
157-
continue
156+
157+
if 'process' in locals():
158+
user_process = locals()['process']
159+
user_process(fs, current_frame, obj.data)
160+
continue
161+
162+
elif 'preprocess' in locals():
158163
user_preprocess = locals()['preprocess']
159164
meshio_mesh = user_preprocess(fs, current_frame)
160-
if not isinstance(meshio_mesh, meshio.Mesh):
161-
show_message_box('function preprocess does not return meshio object', "ERROR")
162-
continue
163165
else:
164166
filepath = fs[current_frame % len(fs)]
165167
try:
166168
meshio_mesh = meshio.read(filepath)
167169
except Exception as e:
168170
show_message_box("Error when reading: " + filepath + ",\n" + traceback.format_exc(),
169-
"Meshio Loading Error" + str(e),
170-
icon="ERROR")
171+
"Meshio Loading Error" + str(e),
172+
icon="ERROR")
171173
continue
172-
update_mesh(meshio_mesh, obj)
174+
175+
176+
if not isinstance(meshio_mesh, meshio.Mesh):
177+
show_message_box('function preprocess does not return meshio object', "ERROR")
178+
continue
179+
update_mesh(meshio_mesh, obj.data)

template/mzd_template.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This is the template specifically show how to load mzd files.
2+
# For more information about mzd, you can find at https://github.com/InteractiveComputerGraphics/MayaMeshTools/tree/main/extern/mzd
3+
# For general information about how to write template, please look at the template.py
4+
5+
6+
import meshio
7+
import fileseq
8+
import bpy
9+
import mzd
10+
11+
12+
# In general we suggest to directly use process for performance and compatibility reason,
13+
# meshio does not support face corner attributes
14+
# However, if you want an easy way to modify the mesh, then meshio.mesh could be the choice
15+
16+
def process(fileseq: fileseq.FileSequence, frame_number: int, mesh:bpy.types.Mesh):
17+
frame_number = frame_number % len(fileseq)
18+
mzd.readMZD_to_bpymesh(fileseq[frame_number],mesh)
19+
20+
# this will be ignored
21+
def preprocess(fileseq: fileseq.FileSequence, frame_number: int) -> meshio.Mesh:
22+
frame_number = frame_number % len(fileseq)
23+
mesh = mzd.readMZD_to_meshio(fileseq[frame_number])
24+
return mesh

0 commit comments

Comments
 (0)