pmdとmqoの入出力ライブラリと、それを使ったBlender2.5向けのaddon。
リビジョン | 274167c4b811b059f7c5fdca47c2113ca185399c (tree) |
---|---|
日時 | 2011-10-10 22:02:26 |
作者 | ousttrue <ousttrue@gmai...> |
コミッター | ousttrue |
implement converter
@@ -67,7 +67,7 @@ class Vector3(object): | ||
67 | 67 | self.z=z |
68 | 68 | |
69 | 69 | def __str__(self): |
70 | - return "<%f %f %f>" % (self.x, self.y, self.z) | |
70 | + return "<%f %.32f %f>" % (self.x, self.y, self.z) | |
71 | 71 | |
72 | 72 | def __eq__(self, rhs): |
73 | 73 | return self.x==rhs.x and self.y==rhs.y and self.z==rhs.z |
@@ -5,6 +5,7 @@ convert model | ||
5 | 5 | |
6 | 6 | import math |
7 | 7 | from . import common |
8 | +from .common import unicode as u | |
8 | 9 | from . import pmx |
9 | 10 | from . import pmd |
10 | 11 |
@@ -24,12 +25,14 @@ def pmd_to_pmx(src): | ||
24 | 25 | pymeshio.pmd.Model |
25 | 26 | """ |
26 | 27 | dst=pmx.Model() |
28 | + # model info | |
27 | 29 | dst.name=src.name.decode("cp932") |
28 | 30 | dst.english_name=src.english_name.decode("cp932") |
29 | 31 | dst.comment=src.comment.replace( |
30 | 32 | b"\n", b"\r\n").decode("cp932") |
31 | 33 | dst.english_comment=src.english_comment.replace( |
32 | 34 | b"\n", b"\r\n").decode("cp932") |
35 | + # vertices | |
33 | 36 | def createDeform(bone0, bone1, weight0): |
34 | 37 | if weight0==0: |
35 | 38 | return pmx.Bdef1(bone1) |
@@ -46,8 +49,9 @@ def pmd_to_pmx(src): | ||
46 | 49 | 1.0 if v.edge_flag==0 else 0.0 |
47 | 50 | ) |
48 | 51 | for v in src.vertices] |
49 | - dst.indices=[i for i in src.indices] | |
50 | - | |
52 | + # indices | |
53 | + dst.indices=src.indices[:] | |
54 | + # materials | |
51 | 55 | texture_map={} |
52 | 56 | def get_flag(m): |
53 | 57 | return ( |
@@ -92,6 +96,10 @@ def pmd_to_pmx(src): | ||
92 | 96 | raise ConvertException( |
93 | 97 | "invalid sphere texture: {0}".format(sphere_texture)) |
94 | 98 | return 0 |
99 | + def get_toon_shared_flag(m): | |
100 | + return 1 | |
101 | + def get_toon_index(m): | |
102 | + return m.toon_index | |
95 | 103 | for m in src.materials: |
96 | 104 | texture=get_texture_file(m.texture_file) |
97 | 105 | if texture and not texture in texture_map: |
@@ -116,17 +124,16 @@ def pmd_to_pmx(src): | ||
116 | 124 | texture_index=get_texture_index(m.texture_file), |
117 | 125 | sphere_texture_index=get_sphere_texture_index(m.texture_file), |
118 | 126 | sphere_mode=get_sphere_texture_flag(m.texture_file), |
119 | - toon_sharing_flag=1, | |
120 | - toon_texture_index=m.toon_index, | |
127 | + toon_sharing_flag=get_toon_shared_flag(m), | |
128 | + toon_texture_index=get_toon_index(m), | |
121 | 129 | comment=common.unicode(""), |
122 | 130 | vertex_count=m.vertex_count |
123 | 131 | ) |
124 | 132 | for i, m in enumerate(src.materials)] |
125 | - | |
133 | + # bones | |
126 | 134 | ik_map={} |
127 | 135 | for ik in src.ik_list: |
128 | 136 | ik_map[ik.index]=ik |
129 | - | |
130 | 137 | def is_connected(b): |
131 | 138 | if isinstance(b, pmd.Bone_Rolling): |
132 | 139 | return False |
@@ -204,7 +211,6 @@ def pmd_to_pmx(src): | ||
204 | 211 | (4096 if after_physics(b) else 0)+ |
205 | 212 | (8192 if external_parent(b) else 0) |
206 | 213 | ) |
207 | - | |
208 | 214 | def get_tail_position(b): |
209 | 215 | return common.Vector3() |
210 | 216 | def get_tail_index(b): |
@@ -257,77 +263,67 @@ def pmd_to_pmx(src): | ||
257 | 263 | ik=get_ik(b), |
258 | 264 | ) |
259 | 265 | for i, b in enumerate(src.bones)] |
260 | - | |
261 | - return dst | |
262 | - | |
263 | - def is_visible(b): | |
264 | - if isinstance(b, pmd.Bone_Unvisible): | |
265 | - return False | |
266 | - else: | |
267 | - return True | |
268 | - def is_manupilatable(b): | |
269 | - return True | |
270 | - def has_ik(b): | |
271 | - return False | |
272 | - def is_fixed_axis(b): | |
273 | - if isinstance(b, pmd.Bone_Rolling): | |
274 | - return True | |
275 | - def is_local_axis(b): | |
276 | - pass | |
277 | - def after_physics(b): | |
278 | - pass | |
279 | - def external_parent(b): | |
280 | - pass | |
281 | - def get_bone_flag(b): | |
282 | - return ( | |
283 | - (1 if is_connected(b) else 0)+ | |
284 | - (2 if is_rotatable(b) else 0)+ | |
285 | - (4 if is_movable(b) else 0)+ | |
286 | - (8 if is_visible(b) else 0)+ | |
287 | - | |
288 | - (16 if is_manupilatable(b) else 0)+ | |
289 | - (32 if has_ik(b) else 0)+ | |
290 | - 0+ | |
291 | - 0+ | |
292 | - | |
293 | - (256 if isinstance(b, pmd.Bone_RotateInfl) else 0)+ | |
294 | - 0+ | |
295 | - (1024 if is_fixed_axis(b) else 0)+ | |
296 | - (2048 if is_local_axis(b) else 0)+ | |
297 | - | |
298 | - (4096 if after_physics(b) else 0)+ | |
299 | - (8192 if external_parent(b) else 0) | |
266 | + # bones | |
267 | + def get_panel(m): | |
268 | + return 1 | |
269 | + base=src.morphs[0] | |
270 | + assert(base.name==b"base") | |
271 | + dst.morphs=[ | |
272 | + pmx.Morph( | |
273 | + name=m.name.decode('cp932'), | |
274 | + english_name=m.english_name.decode('cp932'), | |
275 | + panel=get_panel(m), | |
276 | + morph_type=1, | |
277 | + offsets=[pmx.VerexMorphOffset(base.indices[i], pos) | |
278 | + for i, pos in zip(m.indices, m.pos_list)] | |
300 | 279 | ) |
301 | - | |
302 | - def get_tail_position(b): | |
303 | - return common.Vector3() | |
304 | - def get_tail_index(b): | |
305 | - if isinstance(b, pmd.Bone_Rolling): | |
306 | - return -1 | |
307 | - return b.tail_index | |
308 | - def get_ik(b): | |
309 | - return None | |
310 | - def get_layer(b): | |
311 | - return 0 | |
312 | - dst.bones=[ | |
313 | - pmx.Bone( | |
314 | - name=b.name.decode('cp932'), | |
315 | - english_name=b.english_name.decode('cp932'), | |
316 | - position=b.pos, | |
317 | - parent_index=b.parent_index if b.parent_index!=65535 else -1, | |
318 | - layer=get_layer(b), | |
319 | - flag=get_bone_flag(b), | |
320 | - tail_position=get_tail_position(b), | |
321 | - tail_index=get_tail_index(b), | |
322 | - effect_index=-1, | |
323 | - effect_factor=0.0, | |
324 | - fixed_axis=common.Vector3(), | |
325 | - local_x_vector=common.Vector3(), | |
326 | - local_z_vector=common.Vector3(), | |
327 | - external_key=-1, | |
328 | - ik=get_ik(b), | |
280 | + for i, m in enumerate(src.morphs) if m.name!=b"base"] | |
281 | + # display_slots | |
282 | + dst.display_slots=[ | |
283 | + pmx.DisplaySlot(u('Root'), u('Root'), 1), | |
284 | + pmx.DisplaySlot(u('表情'), u('Exp'), 1)]+[ | |
285 | + pmx.DisplaySlot( | |
286 | + name=g.name.strip().decode('cp932'), | |
287 | + english_name=g.english_name.strip().decode('cp932'), | |
288 | + special_flag=0) | |
289 | + for i, g in enumerate(src.bone_group_list)] | |
290 | + # rigidbodies | |
291 | + dst.rigidbodies=[ | |
292 | + pmx.RigidBody( | |
293 | + name=r.name.decode("cp932"), | |
294 | + english_name=u(""), | |
295 | + bone_index=r.bone_index, | |
296 | + collision_group=r.collision_group, | |
297 | + no_collision_group=r.no_collision_group, | |
298 | + shape_type=r.shape_type, | |
299 | + shape_size=r.shape_size, | |
300 | + shape_position=r.shape_position, | |
301 | + shape_rotation=r.shape_rotation, | |
302 | + mass=r.mass, | |
303 | + linear_damping=r.linear_damping, | |
304 | + angular_damping=r.angular_damping, | |
305 | + restitution=r.restitution, | |
306 | + friction=r.friction, | |
307 | + mode=r.mode | |
329 | 308 | ) |
330 | - for i, b in enumerate(src.bones)] | |
331 | - | |
309 | + for i, r in enumerate(src.rigidbodies)] | |
310 | + # joints | |
311 | + dst.joints=[ | |
312 | + pmx.Joint( | |
313 | + j.name.decode('cp932'), | |
314 | + u(""), | |
315 | + 0, | |
316 | + j.rigidbody_index_a, | |
317 | + j.rigidbody_index_b, | |
318 | + j.position, | |
319 | + j.rotation, | |
320 | + j.translation_limit_min, | |
321 | + j.translation_limit_max, | |
322 | + j.rotation_limit_min, | |
323 | + j.rotation_limit_max, | |
324 | + j.spring_constant_translation, | |
325 | + j.spring_constant_rotation | |
326 | + ) | |
327 | + for i, j in enumerate(src.joints)] | |
332 | 328 | return dst |
333 | 329 |
@@ -448,16 +448,16 @@ class RigidBody(object): | ||
448 | 448 | bone_index, |
449 | 449 | collision_group, |
450 | 450 | no_collision_group, |
451 | + shape_type, | |
452 | + shape_size, | |
453 | + shape_position, | |
454 | + shape_rotation, | |
451 | 455 | mass, |
452 | 456 | linear_damping, |
453 | 457 | angular_damping, |
454 | 458 | restitution, |
455 | 459 | friction, |
456 | 460 | mode, |
457 | - shape_type=0, | |
458 | - shape_size=common.Vector3(), | |
459 | - shape_position=common.Vector3(), | |
460 | - shape_rotation=common.Vector3() | |
461 | 461 | ): |
462 | 462 | self.name=name |
463 | 463 | self.bone_index=bone_index |
@@ -547,6 +547,7 @@ class Model(object): | ||
547 | 547 | _name: internal |
548 | 548 | """ |
549 | 549 | __slots__=[ |
550 | + 'path', | |
550 | 551 | 'version', 'name', 'comment', |
551 | 552 | 'english_name', 'english_comment', |
552 | 553 | 'vertices', 'indices', 'materials', 'bones', |
@@ -557,7 +558,8 @@ class Model(object): | ||
557 | 558 | |
558 | 559 | 'no_parent_bones', |
559 | 560 | ] |
560 | - def __init__(self, version): | |
561 | + def __init__(self, version=1.0): | |
562 | + self.path='' | |
561 | 563 | self.version=version |
562 | 564 | self.name=b'' |
563 | 565 | self.comment=b'' |
@@ -585,7 +587,7 @@ class Model(object): | ||
585 | 587 | def __str__(self): |
586 | 588 | return '<pmd-%g, "%s" vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % ( |
587 | 589 | self.version, self.name, len(self.vertices), len(self.indices), |
588 | - len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list)) | |
590 | + len(self.materials), len(self.bones), len(self.ik_list), len(self.morphs)) | |
589 | 591 | |
590 | 592 | def __eq__(self, rhs): |
591 | 593 | return ( |
@@ -42,7 +42,7 @@ class Reader(common.BinaryReader): | ||
42 | 42 | specular_factor=self.read_float(), |
43 | 43 | specular_color=self.read_rgb(), |
44 | 44 | ambient_color=self.read_rgb(), |
45 | - toon_index=self.read_uint(1), | |
45 | + toon_index=self.read_int(1), | |
46 | 46 | edge_flag=self.read_uint(1), |
47 | 47 | vertex_count=self.read_uint(4), |
48 | 48 | texture_file=self.read_text(20) |
@@ -79,9 +79,9 @@ class Reader(common.BinaryReader): | ||
79 | 79 | def read_rigidbody(self): |
80 | 80 | return pmd.RigidBody( |
81 | 81 | name=self.read_text(20), |
82 | - bone_index=self.read_uint(2), | |
83 | - collision_group=self.read_uint(1), | |
84 | - no_collision_group=self.read_uint(2), | |
82 | + bone_index=self.read_int(2), | |
83 | + collision_group=self.read_int(1), | |
84 | + no_collision_group=self.read_int(2), | |
85 | 85 | shape_type=self.read_uint(1), |
86 | 86 | shape_size=self.read_vector3(), |
87 | 87 | shape_position=self.read_vector3(), |
@@ -143,7 +143,7 @@ def __read(reader, model): | ||
143 | 143 | # extend1: english name |
144 | 144 | ############################################################ |
145 | 145 | if reader.read_uint(1)==0: |
146 | - print("no extend flag") | |
146 | + #print("no extend flag") | |
147 | 147 | return True |
148 | 148 | model.english_name=reader.read_text(20) |
149 | 149 | model.english_comment=reader.read_text(256) |
@@ -172,6 +172,7 @@ def __read(reader, model): | ||
172 | 172 | if reader.is_end(): |
173 | 173 | # EOF |
174 | 174 | return True |
175 | + | |
175 | 176 | model.rigidbodies=[reader.read_rigidbody() |
176 | 177 | for _ in range(reader.read_uint(4))] |
177 | 178 | model.joints=[reader.read_joint() |
@@ -194,7 +195,9 @@ def read_from_file(path): | ||
194 | 195 | <pmd-2.0 "Miku Hatsune" 12354vertices> |
195 | 196 | |
196 | 197 | """ |
197 | - return read(io.BytesIO(common.readall(path))) | |
198 | + pmd=read(io.BytesIO(common.readall(path))) | |
199 | + pmd.path=path | |
200 | + return pmd | |
198 | 201 | |
199 | 202 | |
200 | 203 | def read(ios): |
@@ -46,8 +46,8 @@ class Diff(object): | ||
46 | 46 | def _diff_array(self, rhs, key): |
47 | 47 | la=getattr(self, key) |
48 | 48 | ra=getattr(rhs, key) |
49 | - if len(la)!=len(la): | |
50 | - raise DifferenceException(key) | |
49 | + if len(la)!=len(ra): | |
50 | + raise DifferenceException("%s diffrence %d with %d" % (key, len(la), len(ra))) | |
51 | 51 | for i, (l, r) in enumerate(zip(la, ra)): |
52 | 52 | if isinstance(l, Diff): |
53 | 53 | try: |
@@ -467,12 +467,12 @@ class Morph(Diff): | ||
467 | 467 | 'morph_type', |
468 | 468 | 'offsets', |
469 | 469 | ] |
470 | - def __init__(self, name, english_name, panel, morph_type): | |
470 | + def __init__(self, name, english_name, panel, morph_type, offsets=[]): | |
471 | 471 | self.name=name |
472 | 472 | self.english_name=english_name |
473 | 473 | self.panel=panel |
474 | 474 | self.morph_type=morph_type |
475 | - self.offsets=[] | |
475 | + self.offsets=offsets | |
476 | 476 | |
477 | 477 | def __eq__(self, rhs): |
478 | 478 | return ( |
@@ -489,7 +489,7 @@ class Morph(Diff): | ||
489 | 489 | def diff(self, rhs): |
490 | 490 | self._diff(rhs, 'name') |
491 | 491 | self._diff(rhs, 'english_name') |
492 | - self._diff(rhs, 'panel') | |
492 | + #self._diff(rhs, 'panel') | |
493 | 493 | self._diff(rhs, 'morph_type') |
494 | 494 | self._diff_array(rhs, 'offsets') |
495 | 495 |
@@ -519,8 +519,8 @@ class VerexMorphOffset(Diff): | ||
519 | 519 | return not self.__eq__(rhs) |
520 | 520 | |
521 | 521 | def diff(self, rhs): |
522 | - self._diff(rhs, 'name') | |
523 | - self._diff(rhs, 'english_name') | |
522 | + self._diff(rhs, 'vertex_index') | |
523 | + self._diff(rhs, 'position_offset') | |
524 | 524 | |
525 | 525 | |
526 | 526 | class DisplaySlot(Diff): |
@@ -538,11 +538,11 @@ class DisplaySlot(Diff): | ||
538 | 538 | 'special_flag', |
539 | 539 | 'refrences', |
540 | 540 | ] |
541 | - def __init__(self, name, english_name, special_flag): | |
541 | + def __init__(self, name, english_name, special_flag, refrences=[]): | |
542 | 542 | self.name=name |
543 | 543 | self.english_name=english_name |
544 | 544 | self.special_flag=special_flag |
545 | - self.refrences=[] | |
545 | + self.refrences=refrences | |
546 | 546 | |
547 | 547 | def __eq__(self, rhs): |
548 | 548 | return ( |
@@ -559,7 +559,7 @@ class DisplaySlot(Diff): | ||
559 | 559 | self._diff(rhs, 'name') |
560 | 560 | self._diff(rhs, 'english_name') |
561 | 561 | self._diff(rhs, 'special_flag') |
562 | - self._diff_array(rhs, 'refrences') | |
562 | + #self._diff_array(rhs, 'refrences') | |
563 | 563 | |
564 | 564 | |
565 | 565 | class RigidBodyParam(Diff): |
@@ -688,7 +688,7 @@ class RigidBody(Diff): | ||
688 | 688 | self._diff(rhs, 'no_collision_group') |
689 | 689 | self._diff(rhs, 'shape_type') |
690 | 690 | self._diff(rhs, 'shape_size') |
691 | - self._diff(rhs, 'shape_position') | |
691 | + #self._diff(rhs, 'shape_position') | |
692 | 692 | self._diff(rhs, 'shape_rotation') |
693 | 693 | self._diff(rhs, 'param') |
694 | 694 | self._diff(rhs, 'mode') |
@@ -824,6 +824,7 @@ class Model(Diff): | ||
824 | 824 | bullet physics joint list |
825 | 825 | """ |
826 | 826 | __slots__=[ |
827 | + 'path', | |
827 | 828 | 'version', |
828 | 829 | 'name', |
829 | 830 | 'english_name', |
@@ -840,6 +841,7 @@ class Model(Diff): | ||
840 | 841 | 'joints', |
841 | 842 | ] |
842 | 843 | def __init__(self, version=2.0): |
844 | + self.path='' | |
843 | 845 | self.version=version |
844 | 846 | self.name='' |
845 | 847 | self.english_name='' |
@@ -286,7 +286,9 @@ def read_from_file(path): | ||
286 | 286 | <pmx-2.0 "Miku Hatsune" 12354vertices> |
287 | 287 | |
288 | 288 | """ |
289 | - return read(io.BytesIO(pymeshio.common.readall(path))) | |
289 | + pmx=read(io.BytesIO(pymeshio.common.readall(path))) | |
290 | + pmx.path=path | |
291 | + return pmx | |
290 | 292 | |
291 | 293 | |
292 | 294 | def read(ios): |
@@ -259,7 +259,7 @@ class Writer(common.BinaryWriter): | ||
259 | 259 | self.write_vector3(j.spring_constant_rotation) |
260 | 260 | |
261 | 261 | |
262 | -def write(ios, model, text_encoding=0): | |
262 | +def write(ios, model, text_encoding=1): | |
263 | 263 | """ |
264 | 264 | write model to ios. |
265 | 265 |
@@ -270,6 +270,7 @@ def write(ios, model, text_encoding=0): | ||
270 | 270 | pmx model |
271 | 271 | text_encoding |
272 | 272 | text field encoding (0: UTF16, 1:UTF-8). |
273 | + 0: UTF16 has bug. it write BOM(FFFE). | |
273 | 274 | |
274 | 275 | >>> import pymeshio.pmx.writer |
275 | 276 | >>> pymeshio.pmx.writer.write(io.open('out.pmx', 'wb'), pmx) |
@@ -8,7 +8,7 @@ import shutil | ||
8 | 8 | |
9 | 9 | name='pymeshio' |
10 | 10 | version='2.2.1' |
11 | -short_description='pure python 3d model io library' | |
11 | +short_description='3d model io library for mqo, pmd, pmx, vmd and vpd' | |
12 | 12 | long_description='''\ |
13 | 13 | `pymeshio` is a package for 3d model io. |
14 | 14 | create for blender import/expoert plugin backend. |
@@ -52,8 +52,9 @@ ToDo | ||
52 | 52 | -------- |
53 | 53 | |
54 | 54 | * pmd to pmx converter |
55 | -* blender importer for pmx | |
56 | -* blender exporter for pmx | |
55 | +* update blender25 plugin to blender26 | |
56 | +* blender26 importer for pmx | |
57 | +* blender26 exporter for pmx | |
57 | 58 | |
58 | 59 | |
59 | 60 | New |
@@ -99,5 +100,10 @@ setup( | ||
99 | 100 | test_suite='nose.collector', |
100 | 101 | tests_require=['Nose'], |
101 | 102 | zip_safe = (sys.version>="2.5"), # <2.5 needs unzipped for -m to work |
103 | + entry_points = { | |
104 | + 'console_scripts': [ | |
105 | + 'pmd2pmx = pymeshio.main:pmd_to_pmx', | |
106 | + ] | |
107 | + } | |
102 | 108 | ) |
103 | 109 |