forked from is-blackhole/poser2egg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
egg.py
347 lines (311 loc) · 15.6 KB
/
egg.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# -*- coding: utf-8 -*-
from utils import *
from euclid import Quaternion
#supported poser texture modes
class TextureMode:
MODULATE = 'MODULATE'
NORMAL = 'NORMAL'
GLOSS = 'GLOSS'
ALPHA = 'ALPHA'
# Class for egg presentation of Poser material
class EggMaterial:
def __init__(self, poser_material):
self.poser_material = poser_material
self.name = egg_safe_same(poser_material.Name())
textures = [self._check_texture(poser_material.TextureMapFileName(), '_texture', TextureMode.MODULATE),
self._check_texture(poser_material.BumpMapFileName(), '_bump', TextureMode.NORMAL),
self._check_texture(poser_material.TransparencyMapFileName(), '_transparency', TextureMode.ALPHA)]
self.textures = filter(None, textures)
def _check_texture(self, textureName, egg_texture_name, egg_texture_mode):
texture = EggTexture(textureName, self.name + egg_texture_name, egg_texture_mode)
return texture.check_texture()
def write(self):
lines = ["<Material> %s {\n" % self.name]
lines += " <Scalar> diffr {%f} <Scalar> diffg {%f} <Scalar> diffb {%f}\n" % (self.poser_material.DiffuseColor())
sr, sg, sb = self.poser_material.SpecularColor()
lines += " <Scalar> specr {%f} <Scalar> specg {%f} <Scalar> specb {%f}\n" % (sr * 0.2, sg * 0.2, sb * 0.2)
lines += " <Scalar> shininess { 25 }"
lines += "\n}\n"
return lines
def __str__(self):
return self.name + ",".join(self.textures)
# Class for egg presentation of Poser material textures
class EggTexture:
EMPTY_TEXTURE = poser.ContentRootLocation().replace("\\", '/').replace(":", "")
ALL_TEXTURES = {}
def __init__(self, filename, texture_name, texture_mode):
self.texture_mode = texture_mode
self.filename = None
if filename is not None:
self.filename = filename.replace("\\", '/').replace(":", "")
self.name = egg_safe_same(texture_name)
def check_texture(self):
if self.filename != EggTexture.EMPTY_TEXTURE and self.filename is not None:
if self.filename not in EggTexture.ALL_TEXTURES:
EggTexture.ALL_TEXTURES[self.filename] = self
return EggTexture.ALL_TEXTURES[self.filename].name
return None
def write(self):
lines = ["<Texture> %s {\n \"%s\" \n" % (self.name, self.filename)]
# poser transparency textures are separate file and exported as pure alpha in egg
if self.texture_mode == TextureMode.ALPHA:
lines += " <Scalar> format { alpha }\n"
lines += " <Scalar> envtype { %s }" % TextureMode.MODULATE
else:
lines += " <Scalar> envtype { %s }" % self.texture_mode
lines += " <Scalar> wrap { %s }" % 'REPEAT'
lines += "\n}\n"
return lines
class EggObject:
empty_texture = poser.ContentRootLocation()
SKIP_MORPHS = 'SKIP_MORPHS'
BAKE_MORPHS = 'BAKE_MORPHS'
EXPORT_MORPHS = 'EXPORT_MORPHS'
def __init__(self, figure):
self.options = {"morph": self.BAKE_MORPHS, "textures": True}
self.figure = figure
self.figure_name = fix_name(figure.Name())
def export(self):
# get geometry from poser
uniGeometry, self.uniActorList, self.uniActorVertexInfoList = self.figure.UnimeshInfo()
# collect materials/textures
self.materials, self.textures = self.collect_materials(self.figure)
# collect vertices
self.vertices, self.polygons, self.poser2egg = self.collect_vertices(self.uniActorList)
# collect joints
self.joints = self.collect_joints(self.figure.ParentActor(), 1)
# write egg content
return self.write()
def write(self):
lines = []
lines += "<CoordinateSystem> { Y-Up-Right }\n"
lines += write_comment('poser2egg - ' + self.figure_name, 0)
# write materials and textures
print 'Writing Materials ...'
lines + self.write_materials()
# write rig
print 'Writing Rig ...'
lines += "<Group> %s {\n <Dart> { 1 }\n" % (self.figure_name, )
# write joints
lines += self.write_joints(self.joints)
poser.Scene().ProcessSomeEvents()
# write vertex pool
print 'Writing vertices ...'
lines += self.write_vertex_pool()
poser.Scene().ProcessSomeEvents()
# write polygons
print 'Writing Polygons ...'
lines += self.write_polygons()
poser.Scene().ProcessSomeEvents()
lines += '} // End Group: %s \n' % (self.figure_name, )
return lines
def collect_joints(self, actor, level):
if not actor.IsBodyPart() or actor.Name() == 'BodyMorphs':
return
actorName = fix_name(actor.Name())
print indent_string('processing %s' % actorName, level)
#origin = actor.Origin()
#parentOrigin = actor.Parent().Origin()
if actor.Name() == self.figure.ParentActor().Name():
#matrix = get_matrix(origin)
matrix = actor.WorldMatrix() # get_matrix(origin)
else:
#matrix = get_matrix(vec_subtract(origin, parentOrigin))
matrix = actor.LocalMatrix()
vertex_refs = []
if actor.Geometry():
vertex_refs = self.poser2egg[self.get_actor_index(actor)]
child_joints = []
for child in actor.Children():
child_joint = self.collect_joints(child, level + 1)
if child_joint is not None:
child_joints += child_joint
return [(actorName, matrix, child_joints, vertex_refs, actor)]
def write_joints(self, joint, indent=1):
lines = []
for (joint_name, joint_matrix, child_joints, vertex_refs, actor) in joint:
#print joint_name
lines += indent_string(' <Joint> %s {\n' % joint_name, indent)
lines += write_transform(joint_matrix, indent + 1)
lines += indent_string('<VertexRef> {\n', indent + 1)
vx = [str(v) for v in vertex_refs]
lines.append(indent_string('%s\n' % (' '.join(vx)), indent + 2))
lines.append(indent_string('<Ref> { mesh }\n', indent + 2))
lines.append(indent_string('}\n', indent + 1))
lines += self.write_joints(child_joints, indent + 1)
lines += indent_string(' } // End joint %s \n' % joint_name, indent)
return lines
def get_actor_index(self, actor):
for i, a in enumerate(self.uniActorList):
if a.InternalName() == actor.InternalName():
return i
return None
def collect_materials(self, figure):
egg_materials = {}
for material in figure.Materials():
mat_name = material.Name()
if mat_name == 'Preview':
continue
egg_materials[mat_name] = EggMaterial(material)
return egg_materials, EggTexture.ALL_TEXTURES
def write_materials(self):
lines = []
for material in self.materials.values():
lines += material.write()
if self.options["textures"] == True:
for texture in self.textures.values():
lines += texture.write()
return lines
def collect_vertices(self, uniActorList):
bake_morph = self.options["morph"] == self.BAKE_MORPHS
print 'Collecting vertices ...'
egg_vertices = []
egg_polygons = []
poser2egg = {}
self.egg_uvs = {}
# egg vertex index is different from poser
vertex_index = 0
for actor in uniActorList:
print actor.Name()
actor_index = self.get_actor_index(actor)
poser2egg[actor_index] = {}
# get actor geom data
geom = actor.Geometry()
# check morph options
if bake_morph:
all_params = actor.Parameters()
# get morph targets
#morphs = [p for p in all_params if not p.Name().startswith('EMPTY') and not p.Name().startswith('V4') and p.Name() != '-' and p.IsMorphTarget() and (abs(p.Value()-0.0) > 0.001) and p.Hidden() != 1]
morphs = [p for p in all_params if p.IsMorphTarget() and not p.Name().startswith('EMPTY') and p.Name() != '-' and not p.Name().startswith('V4') and (abs(p.Value() - 0.0) > 0.1)]
#morphs = [p for p in all_params if p.IsMorphTarget() and p.IsValueParameter() and (abs(p.Value() - 0.0) > 0.1)]
# poser vertices/texture data
vertices, tex_vertices, normals = geom.Vertices(), geom.TexVertices(), geom.Normals()
# poser polygon/texture data (index to start in sets/tex_sets + number of vertices)
polygons, tex_polygons = geom.Polygons(), geom.TexPolygons()
# poser sets/texture sets containing vertices id for vertices/tex_vertices arrays
sets, tex_sets = geom.Sets(), geom.TexSets()
# collect all geom data for current actor and present as egg group
group_name = fix_name(actor.Name())
group_polygons = []
for polygon_index, polygon in enumerate(polygons):
poly_start = vertex_index
start = polygon.Start()
# get tex_polygon and tex_set for current polygon
tex_polygon = tex_polygons[polygon_index]
tex_set = tex_sets[tex_polygon.Start(): tex_polygon.Start() + tex_polygon.NumTexVertices()]
# get all polygon vertices
for k, v in enumerate(sets[start: start + polygon.NumVertices()]):
vertex = vertices[v]
self.egg_uvs[start + k] = tex_vertices[tex_set[k]]
x, y, z = vertex.X(), vertex.Y(), vertex.Z()
if bake_morph:
for morph in morphs:
dx, dy, dz = morph.MorphTargetDelta(v)
x += dx * morph.Value()
y += dy * morph.Value()
z += dz * morph.Value()
egg_vertices.append((vertex_index, (x, y, z), normals[v], tex_vertices[tex_set[k]]))
poser2egg[actor_index][vertex_index] = vertex_index
# increment egg vertex index
vertex_index += 1
# add egg polygon data to group polygons (poser polygon + start/length in egg_vertices list)
group_polygons.append((polygon, poly_start, vertex_index - poly_start))
egg_polygons.append((group_name, group_polygons))
poser.Scene().ProcessSomeEvents()
return egg_vertices, egg_polygons, poser2egg
def write_vertex_pool(self):
lines = []
lines += ' <VertexPool> mesh {\n'
for (i, v_tuple, n, t) in self.vertices:
lines.append(' <Vertex> %s { %f %f %f <Normal> { %f %f %f } <UV> { %f %f } }\n' %
(str(i), v_tuple[0], v_tuple[1], v_tuple[2],
n.X() != 'nan' or 0, n.Y() != 'nan' or 0, n.Z() != 'nan' or 0,
t.U(), t.V()))
lines += ' } // End VertexPool: mesh\n'
print '* 100 %'
return lines
def write_polygons(self):
lines = []
for (group_name, group_polys) in self.polygons:
lines += "<Group> %s {\n" % (group_name, )
for (polygon, start_index, num_vertices) in group_polys:
refs = ' '.join([str(j) for j in range(start_index, start_index + num_vertices)])
if self.options["textures"] == True:
polygon_trefs = ' '.join(
"<TRef> {%s}" % texture_name for texture_name in self.materials[polygon.MaterialName()].textures)
else:
polygon_trefs = ""
lines.append(
" <Polygon> {\n %s\n <MRef> { %s } \n <VertexRef> { %s <Ref> { mesh } } \n}\n" % (
polygon_trefs, polygon.MaterialName(), refs, ))
lines += "\n}\n"
print '* 100 %'
return lines
def collect_anims(self):
anims_data = {}
for frame in xrange(0, poser.Scene().NumFrames() - 1):
#for frame in xrange(0, 3):
poser.Scene().SetFrame(frame)
poser.Scene().DrawAll()
self.collect_anims2(self.joints, anims_data)
return anims_data
def collect_anims2(self, joint, anims):
for (joint_name, joint_matrix, child_joints, vertex_refs, actor) in joint:
#print "anims for %s" % joint_name
#get bone displacement
displacement = actor.LocalDisplacement()
origin = actor.Origin()
parentOrigin = actor.Parent().Origin()
if actor.Name() == self.figure.ParentActor().Name():
parentOrigin = origin
displacement = vec_add(vec_subtract(origin, parentOrigin), displacement)
displacement = vec_subtract(origin, parentOrigin)
# get rotation
quat_tuple = actor.LocalQuaternion()
quat = Quaternion(quat_tuple[0], quat_tuple[1], quat_tuple[2], quat_tuple[3])
hpr = radians_to_degrees(quat.get_euler())
#store displacement/rotation in anims data
if joint_name not in anims:
anims[joint_name] = []
anims[joint_name].append((displacement, hpr))
self.collect_anims2(child_joints, anims)
return anims
def write_animation(self):
print 'Writing animation ...'
anims_data = self.collect_anims()
#print anims_data
#return
lines = []
lines += '<Table> {\n'
lines += indent_string('<Bundle> %s {\n' % self.figure_name, 1)
lines += indent_string('<Table> "<skeleton>" {\n', 2)
lines += self.write_animation_table(self.joints, anims_data, 3)
lines += indent_string('}\n', 2)
lines += indent_string('}\n', 1)
lines += '}'
return lines
def write_animation_table(self, joint, anims_data, indent=1):
lines = []
for (joint_name, joint_matrix, child_joints, vertex_refs, actor) in joint:
#print joint_name
lines += indent_string('<Table> %s {\n' % joint_name, indent)
lines += indent_string('<Xfm$Anim> xform {\n', indent + 1)
lines += indent_string('<Scalar> order { sprht }\n', indent + 2)
lines += indent_string('<Scalar> contents { prhxyz }\n', indent + 2)
#lines += indent_string('<Scalar> contents { ijkprhxyz }\n', indent + 2)
lines += indent_string('<Scalar> fps { %u }\n' % 2, indent + 2)
lines += indent_string('<V> {\n', indent + 2)
for frame in xrange(0, poser.Scene().NumFrames() - 1):
displacement, hpr = anims_data[joint_name][frame]
#lines += indent_string("%s %s %s %s %s %s %s %s %s\n" %
lines += indent_string("%s %s %s %s %s %s\n" %
(
hpr[2], hpr[1], hpr[0],
displacement[0], displacement[1], displacement[2]
),
indent + 3)
lines += indent_string('}\n', indent + 2)
lines += indent_string('}\n', indent + 1)
lines += self.write_animation_table(child_joints, anims_data, indent + 2)
lines += indent_string('} // End table %s \n' % joint_name, indent)
return lines