#!BPY """ Name: 'XVR AAM format (.AAM)...' Blender: 248 Group: 'Export' Tooltip: 'Save an XVR AAM File' """ __author__ = "Davide Vercelli" __url__ = ["VRMedia main site, http://www.vrmedia.it", "XVR Wiki, http://wiki.vrmedia.it", "XVR forums, http://forums.vrmedia.it"] __version__ = "0.07a.20081215" __bpydoc__ = """\ This script is an exporter to the XVR AAM file format. Usage: Run this script from "File->Export" menu to export all meshes. New: preliminary avatar support. PLEASE NOTE: this script does not currently support many features of both Blender and XVR, notably: AAM - animation (keyframes) Blender - some material features, etc. The AAM file format has been developed by Marcello Carrozzino. """ import Blender from Blender import Object, Draw, Mesh, Scene, Material, World, Image, Texture, sys, Window, Modifier import BPyMesh def radians(angle): "let's avoid importing the math module just for this..." return angle * 3.1415926535897931 / 180.0 DEBUG = False DEBUG_FILE = False SHOW_ADVANCED_OPTIONS = False scn = Scene.GetCurrent() class outfile: '''this class wraps the output file adding some nice methods such as indent and dedent''' def __init__(self, filename): self.valid = False self.exists = sys.exists(filename) self.curtab = 0 self.file = None # XXX: should also check for permissions, writeability, etc. ? if self.exists and Draw.PupMenu("File already exists. Overwrite?%t|No|Yes") != 2: self.valid = False else: self.file = open(filename, "w") self.valid = True def __del__(self): self.close() def close(self): if self.file != None: self.file.close() def out(self, text = ""): self.file.write("\t" * self.curtab + text + "\n") def indent(self): self.curtab += 1 def dedent(self): self.curtab -= 1 def is_valid(self): return self.valid class debugfile: def __init__(self, debug, debug_file): self.file = None if not debug: self.log = self.write_pass else: if debug_file: import time self.log = self.write_file out_dir = "c:\\src\\blender\\output\\new\\" out_file = "prova" + time.strftime("%Y%m%d%H%M%S") + ".txt" self.file = open(out_dir + out_file, "w") else: self.log = self.write_console def __del__(self): self.close() def close(self): if self.file != None: self.file.close() def write_console(self, txt): print txt def write_file(self, txt): self.file.write(txt + "\n") def write_pass(self, txt): pass class config: def __init__(self, n_meshes): self.valid = True # get options from pup menu EXPORT_WHITE_MATERIAL_IF_TEXTURIZED = Draw.Create(True) EXPORT_WORLD_COORDINATES = Draw.Create(False) FORCE_JPEG_AND_PNG_EXTENSION = Draw.Create(True) FORCE_DDS_EXTENSION = Draw.Create(False) EXPORT_ANIMATION = Draw.Create(False) MAX_EXPORTED_FRAMES = Draw.Create(10) EXPORT_CHARACTER = Draw.Create(False) EXPORT_AVATAR = Draw.Create(False) EXPORT_SHAPES = Draw.Create(False) EXPORT_COLORS = Draw.Create(False) EXPORT_SH_ATTRS = Draw.Create(False) pup_block = [\ ('Mesh Options...'),\ ('World coords', EXPORT_WORLD_COORDINATES, 'Export selected meshes as transformed in the 3d view'),\ ('As character', EXPORT_CHARACTER, 'Export selected meshes as a character hierarchy'),\ ('As avatar', EXPORT_AVATAR, 'Export selected meshes as skinned avatars'),\ ('Animation Options...'),\ ('Export animated', EXPORT_ANIMATION, 'Export animated frames'),\ ('Max frame', MAX_EXPORTED_FRAMES, 1, 250, 'Maximum frame exported'),\ ('Texture Options...'),\ ('White material', EXPORT_WHITE_MATERIAL_IF_TEXTURIZED, 'Keep in mind that XVR blends the texture with the underlying material color'),\ ('Force jpg & png', FORCE_JPEG_AND_PNG_EXTENSION, 'Change texture extensions to supported formats (files must still be converted)'),\ ('Force dds', FORCE_DDS_EXTENSION, 'Change all texture extensions to dds compressed format (overrides preceding)'),\ ] if SHOW_ADVANCED_OPTIONS: pup_block += [\ ('Advanced...'),\ ('Export shapes', EXPORT_SHAPES, 'Export shape keys as vertex attributes'),\ ('Export colors', EXPORT_COLORS, 'Export vertex colors as attributes'),\ ('Export SH attribs', EXPORT_SH_ATTRS, 'Export SH coefficients as vertex attributes if available') ] if not Draw.PupBlock('Export selected...', pup_block): self.valid = False return self.EXPORT_WHITE_MATERIAL_IF_TEXTURIZED = EXPORT_WHITE_MATERIAL_IF_TEXTURIZED.val self.EXPORT_WORLD_COORDINATES = EXPORT_WORLD_COORDINATES.val self.FORCE_JPEG_AND_PNG_EXTENSION = FORCE_JPEG_AND_PNG_EXTENSION.val self.FORCE_DDS_EXTENSION = FORCE_DDS_EXTENSION.val self.EXPORT_ANIMATION = EXPORT_ANIMATION.val self.MAX_EXPORTED_FRAMES = MAX_EXPORTED_FRAMES.val self.EXPORT_CHARACTER = EXPORT_CHARACTER.val self.EXPORT_AVATAR = EXPORT_AVATAR.val self.EXPORT_SHAPES = EXPORT_SHAPES.val self.EXPORT_COLORS = EXPORT_COLORS.val self.EXPORT_SH_ATTRS = EXPORT_SH_ATTRS.val # XXX: the option shouldn't even be shown in that case... or not? if self.EXPORT_AVATAR and n_meshes > 1: Draw.PupMenu("Sorry, can only export one avatar at a time.") self.valid = False return if self.EXPORT_AVATAR and self.EXPORT_CHARACTER: Draw.PupMenu("Sorry, avatar and character are mutually exclusive options") self.valid = False return if self.EXPORT_SHAPES and self.EXPORT_COLORS: Draw.PupMenu("Sorry, currently you cannot export both shapes and colors") self.valid = False return def is_valid(self): return self.valid def get_face_context(f, mo, m): """ Given a face "f", a mesh object "mo" and its corresponding mesh "m", it returns a 2-tuple "face context" object in the form: material_name, image_name where both fields can be None if not applicable. """ mat = None if f.mat < len(m.materials): if mo.colbits >> f.mat & 1: if len(mo.getMaterials()): mat = mo.getMaterials()[f.mat] else: mat = m.materials[f.mat] if not mat: return None, None if m.faceUV and mat.mode & Material.Modes.TEXFACE and f.image: return mat.name, f.image.name return mat.name, None def get_worldamb(): world = World.GetCurrent() if world: return world.getAmb() else: return 0, 0, 0 def validate_selection(): """checks that the selection set contains at least one mesh""" meshes = [x for x in scn.objects.context if x.type == "Mesh"] if len(meshes) < 1: Draw.PupMenu("No meshes selected. Exiting") return False if DEBUG: # DEBUG: show mesh names mesh_names = "|".join([x.name for x in meshes]) Draw.PupMenu("Exported meshes%t|" + mesh_names) return True def write_aam(filename): aam = outfile(filename) if not aam.is_valid(): return d = debugfile(DEBUG, DEBUG_FILE) try: do_write_aam(aam, d) finally: # needed otherwise the reference to f is kept by the stack trace... # (just in case of errors) d.close() aam.close() def im_name(a): if a.image: return a.image.name else: return None def do_write_aam(aam, d): """ Writes out the AAM file from the current selection. """ meshes = [x for x in scn.objects.context if x.type == "Mesh"] d.log("*** Selected Meshes\n") [d.log(x.name) for x in meshes] conf = config(len(meshes)) if not conf.is_valid(): return Window.WaitCursor(1) # materials part materials = {} mat_idx = [] multis = {} totmats = 0 if conf.EXPORT_AVATAR: aam.out("SkelType:H-AnimLOA3") aam.out("MATERIALS") d.log("***Contexts") do_apply = True if conf.EXPORT_AVATAR: do_apply = False # XXX : this is because we don't want to apply the armature for mo in meshes: # TODO: temp-mesh m = BPyMesh.getMeshFromObject(mo, container_mesh=None, apply_modifiers=do_apply, vgroups=False, scn=scn) # XXX: awful workaround # (vorrebbe cage=1 in getfromobject... mah! m.materials = mo.getData(mesh = True).materials d.log("**" + mo.name) faces = [ f for f in m.faces ] if m.faceUV: faces.sort(lambda a,b: cmp((a.mat, im_name(a)), (b.mat, im_name(b)))) else: faces.sort(lambda a,b: cmp(a.mat, b.mat)) totcontexts = 0 tmpdict = {} for f in faces: context = get_face_context(f, mo, m) # debug.write(str(context) + "\n") if context[0] and not tmpdict.has_key(context): tmpdict[context] = totcontexts totcontexts += 1 if len(tmpdict) > 1: # this is a MULTI material multis[mo.name] = tmpdict d.log("-> MULTIS " + mo.name + " * " + str(len(tmpdict))) else: # normal material # Please note: it's a loop but should iterate only once for mats in tmpdict.keys(): d.log("-> mats" + str(mats) + " * " + str(totmats)) if not materials.has_key(mats): materials[mats] = totmats mat_idx.append(mats) totmats += 1 d.log(" -> written") aam.out("MatCount: %i" % (totmats + len(multis))) worldamb = get_worldamb() material_to_uv_channel = {} # material -> channel mesh_needs_secondary_uv = {} # material -> channel def write_mtl(mat_name, img_name, active_uv_layer): mat = Material.Get(mat_name) has_texture1 = False has_texture2 = False texname = "" aam.out("{") aam.indent() aam.out("Name: %s_%s" % (mat_name, img_name)) if img_name: has_texture1 = True img = Image.Get(img_name) texname1 = sys.basename(sys.expandpath(img.filename)) material_to_uv_channel[mat_name, img_name] = active_uv_layer # aam.out("Name: %s" % mat_name) mtex = mat.getTextures() for ti, t in enumerate(mtex): if not t or not t.tex or not t.tex.image: continue if not t.mapto & Texture.MapTo.COL: print "AAM: warning, material %s, texture %s: texture not affecting color: ignored" % (mat_name, str(ti)) continue if not t.texco & Texture.TexCo.UV: print "AAM: warning, material %s, texture %s: only uv texture mapping is supported" % (mat_name, str(ti)) continue if not has_texture1: has_texture1 = True texname1 = t.tex.image.filename material_to_uv_channel[mat_name, img_name] = t.uvlayer else: has_texture2 = True texname2 = t.tex.image.filename mesh_needs_secondary_uv[mat_name, img_name] = t.uvlayer break # TODO: more checks to perform # print other warnings about effects not obtainable in XVR # TODO: warn about more textures affecting diffuse colour aam.out("Class: Blender Material") # TODO: meaningless, could be MULTI aam.out("Am: %.4f %.4f %.4f" % tuple([c * mat.amb for c in worldamb])) if (has_texture1 or has_texture2) and conf.EXPORT_WHITE_MATERIAL_IF_TEXTURIZED: aam.out("Di: 1.0000 1.0000 1.0000") else: aam.out("Di: %.4f %.4f %.4f" % tuple([c * mat.ref for c in mat.rgbCol])) aam.out("Sp: %.4f %.4f %.4f" % tuple([c * mat.spec for c in mat.specCol])) aam.out("Tr: %0.4f" % (1.0 - mat.alpha)) aam.out("Sh: %0.4f" % (mat.hard / 512.0)) def write_tex(ch_name, texname): aam.out("%s: Y" % ch_name) aam.out("{") aam.indent() texname = sys.basename(texname) if conf.FORCE_DDS_EXTENSION: name, ext = sys.splitext(texname) texname = name + '.dds' elif conf.FORCE_JPEG_AND_PNG_EXTENSION: name, ext = sys.splitext(texname) if ext != '.jpg' and ext != '.jpeg' and ext != '.png': # XXX: check for alpha channel texname = name + '.jpg' aam.out("FN: %s" % texname) aam.out("Fi: PYRAMIDAL") if ch_name == "TS": # XXX: TODO aam.out("Ch: 1") aam.out("In: 1.0000") aam.out("UA: 0.0000") aam.out("VA: 0.0000") aam.out("WA: 0.0000") aam.out("UO: 0.0000") aam.out("VO: 0.0000") aam.out("UT: 1.0000") aam.out("VT: 1.0000") aam.dedent() aam.out("}") if not has_texture1: aam.out("Tx: N") else: write_tex("Tx", texname1) if not has_texture2: aam.out("TS: N") else: write_tex("TS", texname2) aam.dedent() aam.out("}") # material index idx = 0 d.log("***Materials") # print "normal" materials for mat_name, img_name in mat_idx: if not mat_name: continue aam.out("Mat# %i" % idx) d.log("Mat# %i - %s - %s" % (idx, str(mat_name), str(img_name))) idx += 1 write_mtl(mat_name, img_name, m.activeUVLayer) # print MULTI materials for meshname in multis.keys(): aam.out("Mat# %i" % idx) d.log("MULTI Mat# %i - %s" % (idx, meshname)) idx += 1 aam.out("{") aam.indent() aam.out("Name: %s_multi" % meshname) aam.out("Class: Multi") aam.out("NSubs: %i" % len(multis[meshname])) subidx = 0 tmplist = [(v, k) for k, v in multis[meshname].items()] tmplist.sort() for index, tup in tmplist: mat_name, img_name = tup if not mat_name: continue aam.out("Sub %i" % subidx) subidx += 1 # print one-tab shifted write_mtl(mat_name, img_name, m.activeUVLayer) aam.dedent() aam.out("}") aam.out("ENDMATERIALS") # calculate parental information... indices = {} parents = {} for i, mo in enumerate(meshes): indices[mo.name] = i for mo in meshes: if mo.parent and indices.has_key(mo.parent.name): parents[mo.name] = indices[mo.parent.name] else: parents[mo.name] = -1 roots = parents.values().count(-1) del indices if not conf.EXPORT_SH_ATTRS and not conf.EXPORT_COLORS and not conf.EXPORT_SHAPES: aam.out("GEOMETRY SmGEnabled") # TODO: better smoothing groups else: aam.out("GEOMETRY SmGNOTEnabled") armature = None group_names, weight_dict = [], [] bdict = {} if conf.EXPORT_AVATAR: mo = meshes[0] group_names, weight_dict = BPyMesh.meshWeight2Dict(mo.getData(mesh=True)) for mod in mo.modifiers: if mod.type == Modifier.Types.ARMATURE: armature = mod[Modifier.Settings.OBJECT].getData() if armature == None: # XXX: andrebbe checkato prima Draw.PupMenu("Mesh must have an armature modifier") return aam.out("NObj: %i" % (1 + len(armature.bones.items()))) bdict = dict([(b, a + 1) for a, b in enumerate(armature.bones.keys())]) else: aam.out("NObj: %i" % len(meshes)) anim_mode = "None" max_frame_no = 1 out_frame_no = 1 if conf.EXPORT_AVATAR: anim_mode = "Keyframe" elif conf.EXPORT_CHARACTER: anim_mode = "Keyframe" # "The frame tag for a character is ALWAYS 0" (hence 1 here) if conf.EXPORT_ANIMATION: out_frame_no = conf.MAX_EXPORTED_FRAMES elif conf.EXPORT_ANIMATION: # multiframe mesh anim_mode = "Full" max_frame_no = conf.MAX_EXPORTED_FRAMES out_frame_no = conf.MAX_EXPORTED_FRAMES aam.out("NFrames: %i" % out_frame_no) aam.out("Animation_mode: %s" % anim_mode) frame_no = 0 saved_frame = Blender.Get("curframe") for frame_no in range(max_frame_no): d.log("- - - frame # %i - - -\n" % frame_no) d.log("***MESHES") if conf.EXPORT_ANIMATION and not conf.EXPORT_CHARACTER: Blender.Set("curframe", frame_no + 1) aam.out("Frame: %i" % frame_no) aam.out("{") aam.indent() id = 0 first_time = True for mo in meshes: if first_time: first_time = False else: aam.out() aam.out("Obj: %i %s" % (id, mo.name)) # TODO: only if character? if conf.EXPORT_CHARACTER: aam.out("Par: %d" % parents[mo.name]) else: aam.out("Par: -1") aam.out("{") # curmesh = m.getData(mesh=True) # TODO: temp-mesh # XXX: occhio ai vgroups, ci vogliono almeno per avatar m = BPyMesh.getMeshFromObject(mo, container_mesh=None, apply_modifiers=do_apply, vgroups=True, scn=scn) # XXX: awful workaround m.materials = mo.getData(mesh = True).materials oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) quadcount = 0 for f in m.faces: if len(f) == 4: f.sel = True quadcount += 1 else: f.sel = False if quadcount: tempob = Object.New('Mesh') tempob.link(m) scn.objects.link(tempob) m.quadToTriangle(0) scn.objects.unlink(tempob) Mesh.Mode(oldmode) if conf.EXPORT_CHARACTER: # TODO: pivot orientation?!? aam.out("Piv:" + " %.4f" * 7 % (mo.LocX, mo.LocY, mo.LocZ, 0, 0, 0, 0)) # TODO: mirroring... aam.out("Mir: 0") r = mo.matrixLocal.rotationPart() t = mo.matrixLocal.translationPart() if not conf.EXPORT_WORLD_COORDINATES and not conf.EXPORT_ANIMATION and roots == 1 and parents[mo.name] == -1: # if there is only one root, we may want to move it in the world center t = 0, 0, 0 s = mo.matrixLocal.scalePart() tm = tuple(r[0]) + tuple(r[1]) + tuple(r[2]) + tuple(t) + tuple(s) aam.out("TM:" + " %.4f" * 15 % tm) if conf.EXPORT_AVATAR: r = mo.matrixLocal.rotationPart() t = mo.matrixLocal.translationPart() #if not EXPORT_WORLD_COORDINATES and not EXPORT_KEYFRAMES and roots == 1 and parents[mo.name] == -1: # if there is only one root, we may want to move it in the world center # t = 0, 0, 0 s = mo.matrixLocal.scalePart() tm = tuple(r[0]) + tuple(r[1]) + tuple(r[2]) + tuple(t) + tuple(s) aam.out("TM:" + " %.4f" * 15 % tm) faces = [ f for f in m.faces ] if m.faceUV: faces.sort(lambda a,b: cmp((a.mat, im_name(a)), (b.mat, im_name(b)))) else: faces.sort(lambda a,b: cmp(a.mat, b.mat)) multi_mat = False if multis.has_key(mo.name): multi_mat = True matidx = totmats + multis.keys().index(mo.name) else: matidx = -1 if len(faces): mat_name, img_name = get_face_context(faces[0], mo, m) if mat_name: matidx = materials[mat_name, img_name] aam.out("MatID: %i" % matidx) d.log(mo.name + " - " + str(matidx)) aam.out("V_List: %i" % len(m.verts)) aam.indent() if conf.EXPORT_WORLD_COORDINATES: m.transform(mo.matrix) for v in m.verts: aam.out("%.4f %.4f %.4f" % tuple(map(lambda x: round(x,4), (v.co.x, v.co.y, v.co.z)))) aam.dedent() if conf.EXPORT_AVATAR: aam.out("SKIN: Y") aam.indent() for i, v in enumerate(m.verts): # XXX: bisogno di rinormalizzare? influences = weight_dict[i] # print i, v, len(influences) influences = influences.copy() # tolgo i vertex group non relativi alle ossa dell'armatura for bname in influences.keys(): #NB: volutamente non un iteratore if not bdict.has_key(bname) or influences[bname] < 0.001: del influences[bname] s = "%d %d " % (i, len(influences)) sum = 0 for i in influences.itervalues(): sum += i for bname, binf in influences.iteritems(): s += "%d %.4f " % (bdict[bname], binf / sum) aam.out(s) aam.dedent() globalUVcoords = {} totuvco = 0 if m.faceUV: prev_chan = m.activeUVLayer for l in m.getUVLayerNames(): m.activeUVLayer = l for f in faces: for uvKey in f.uv: uvKey = tuple(map(lambda x: round(x, 4), uvKey)) if not globalUVcoords.has_key(uvKey): globalUVcoords[uvKey] = totuvco totuvco += 1 m.activeUVLayer = prev_chan if frame_no == 0: if conf.EXPORT_SHAPES: k = mo.getData(mesh = True).key if k and len(k.blocks) > 1: aam.out("C_List: 0") aam.out("VA_List: %i" % (len(k.blocks) - 1)) aam.indent() for i, b in enumerate(k.blocks): if i == 0: continue for v in b.data: # I hope in the same order... aam.out("%.4f %.4f %.4f" % tuple([round(x,4) for x in (v.co.x, v.co.y, v.co.z)])) aam.dedent() elif conf.EXPORT_COLORS: k = m.getColorLayerNames() if len(k) > 0: vertices = {} for f in m.faces: for i, v in enumerate(f.verts): vertices[v.index] = (f.index, i) aam.out("C_List: 0") aam.out("VA_List: %i" % len(k)) aam.indent() for l in k: m.activeColorLayer = l for v in m.verts: fi, fj = vertices[v.index] col = m.faces[fi].col[fj] # XXX: who asked for this awkard calculation? # aam.out("%.4f %.4f %.4f" % tuple([round(x * 8.0 / 255.0 - 4.0,4) for x in (col.r, col.g, col.b)])) aam.out("%.4f %.4f %.4f" % (col.r, col.g, col.b)) aam.dedent() elif conf.EXPORT_SH_ATTRS: try: sh = mo.getData(mesh = True).properties['sh'] except KeyError: pass else: tot_sh = len(sh) try: for i in xrange(tot_sh): if len(sh[str(i)]) != len(m.verts): Draw.PupMenu("Warning, incorrect SH coefficients properties") res = False break else: res = True except KeyError: res = False if res and tot_sh > 0: groups = (tot_sh - 1)/ 4 + 1 last_group = tot_sh % 4 if last_group == 0: last_group = 4 aam.out("C_List: 0") aam.out("VA_List: per_vertex %i" % groups) aam.indent() for gi in xrange(groups): if gi != groups - 1: aam.out("Desc: %s %d" % ("lev" + str(gi), 4)) else: aam.out("Desc: %s %d" % ("lev" + str(gi), last_group)) # TODO: "per_layer" option would be more useful when implemented XVR-wise for vi in xrange(len(m.verts)): c = 0 for gi in xrange(groups - 1): aam.out("%.4f %.4f %.4f %.4f" % (sh[str(c)][vi], sh[str(c + 1)][vi], sh[str(c + 2)][vi], sh[str(c + 3)][vi])) c += 4 if last_group == 1: aam.out("%.4f" % sh[str(c)][vi]) elif last_group == 2: aam.out("%.4f %.4f" % (sh[str(c)][vi], sh[str(c + 1)][vi])) elif last_group == 3: aam.out("%.4f %.4f %.4f" % (sh[str(c)][vi], sh[str(c + 1)][vi], sh[str(c + 2)][vi])) elif last_group == 4: aam.out("%.4f %.4f %.4f %.4f" % (sh[str(c)][vi], sh[str(c + 1)][vi], sh[str(c + 2)][vi], sh[str(c + 3)][vi])) aam.dedent() aam.out("TV_List: %i" % totuvco) aam.indent() # print uvs in the same order as when they were inserted tmplist = [(v, k) for k, v in globalUVcoords.items()] tmplist.sort() for idx, uv in tmplist: aam.out("%.4f %.4f" % uv) aam.dedent() aam.out("I_List: %i %i" % (len(m.faces), multi_mat and len(multis[mo.name]) or 1)) aam.indent() groupidx = 0 context = None smg = 1 for f in faces: # XXX: are we sure it is the same order? fcontext = get_face_context(f, mo, m) if fcontext != context: context = fcontext d.log(str(context)) if groupidx != 0: aam.out("ENDGROUP") aam.out("NEWGROUP: %i" % groupidx) groupidx += 1 # TODO: this solution for smoothing groups is a bit "hackish" and doesn't work # it's much better to use edge-split smooth = f.smooth if not f.smooth: smg += 1 smooth = smg aam.out("I: %i %i %i %i" % (f.v[0].index, f.v[1].index, f.v[2].index, smooth)) # if m.faceUV: if material_to_uv_channel.has_key(fcontext) and m.faceUV: prev_chan = m.activeUVLayer uvchannel = material_to_uv_channel[fcontext] if len(uvchannel) == 0: uvchannel = m.renderUVLayer m.activeUVLayer = uvchannel uv0idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[0]))] uv1idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[1]))] uv2idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[2]))] aam.out("TI: %i %i %i" % (uv0idx, uv1idx, uv2idx)) if mesh_needs_secondary_uv.has_key(fcontext): uvchannel = mesh_needs_secondary_uv[fcontext] if len(uvchannel) == 0: uvchannel = m.renderUVLayer m.activeUVLayer = uvchannel uv0idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[0]))] uv1idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[1]))] uv2idx = globalUVcoords[tuple(map(lambda x: round(x, 4), f.uv[2]))] aam.out("TI: %i %i %i" % (uv0idx, uv1idx, uv2idx)) m.activeUVLayer = prev_chan aam.out("ENDGROUP") aam.dedent() if conf.EXPORT_AVATAR: aam.out("Anim_Ctrl: Y") elif conf.EXPORT_CHARACTER: if not conf.EXPORT_ANIMATION: aam.out("Anim_Ctrl: N") else: aam.out("Anim_Ctrl: Y") aam.indent() if True: # anim_ctrl_mode == PS_SAM: old_frame = Blender.Get("curframe") aam.out("PsSam: %i" % conf.MAX_EXPORTED_FRAMES) aam.indent() for i in range(conf.MAX_EXPORTED_FRAMES): Blender.Set("curframe", i + 1) o = Object.Get(mo.name) t = o.matrixLocal.translationPart() aam.out("%d" % i + " %.4f" * 3 % tuple(t)) aam.dedent() aam.out("RtSam: %i" % conf.MAX_EXPORTED_FRAMES) aam.indent() for i in range(conf.MAX_EXPORTED_FRAMES): Blender.Set("curframe", i + 1) o = Object.Get(mo.name) q = o.matrixLocal.rotationPart().toQuat() q = tuple(q.axis) + (-radians(q.angle),) aam.out("%d" % i + " %.4f" * 4 % q) aam.dedent() aam.out("ScSam: %i" % conf.MAX_EXPORTED_FRAMES) aam.indent() for i in range(conf.MAX_EXPORTED_FRAMES): Blender.Set("curframe", i + 1) o = Object.Get(mo.name) q = o.matrixLocal.rotationPart().toQuat() s = o.matrixLocal.scalePart() aam.out("%d" % i + " %.4f" * 7 % (tuple(q) + tuple(s))) aam.dedent() Blender.Set("curframe", old_frame) aam.dedent() id+=1 aam.out("}") if conf.EXPORT_AVATAR: for g in armature.bones.keys(): # aam.out("%s" % armature.bones[g]) cur_bone = armature.bones[g] aam.out("") aam.out("Obj: %i %s" % (id, g)) # TODO: only if character? if cur_bone.parent != None: aam.out("Par: %d" % bdict[cur_bone.parent.name]) else: aam.out("Par: -1") aam.out("{") # curmesh = m.getData(mesh=True) # TODO: pivot orientation?!? # aam.out("Piv:" + " %.4f" * 7 % (mo.LocX, mo.LocY, mo.LocZ, 0, 0, 0, 0)) # TODO: mirroring... # aam.out("Mir: 0") r = cur_bone.matrix['BONESPACE'].rotationPart() t = cur_bone.head['BONESPACE'].copy() if cur_bone.parent != None: # TODO: maybe precalculate for bones with multiple children p = cur_bone.parent t += (p.tail['BONESPACE'] - p.head['BONESPACE']) * p.matrix['BONESPACE'].copy().invert() # if not EXPORT_WORLD_COORDINATES and not conf.EXPORT_ANIMATION and roots == 1 and parents[mo.name] == -1: # if there is only one root, we may want to move it in the world center # t = 0, 0, 0 s = cur_bone.matrix['BONESPACE'].scalePart() tm = tuple(r[0]) + tuple(r[1]) + tuple(r[2]) + tuple(t) + tuple(s) aam.out("TM:" + " %.4f" * 15 % tm) aam.out("MatID: -1") aam.out("V_List: %i" % 2) aam.indent() # if EXPORT_WORLD_COORDINATES: # m.transform(mo.matrix) aam.out("%.4f %.4f %.4f" % tuple(cur_bone.head['BONESPACE'])) aam.out("%.4f %.4f %.4f" % tuple(cur_bone.tail['BONESPACE'])) aam.dedent() aam.out("SKIN: N") aam.out("TV_List: 0") aam.out("I_List: 1 1") aam.indent() aam.out("NEWGROUP: 1") aam.out("I: 0 1 1 1") aam.out("TA: ") aam.out("ENDGROUP") aam.dedent() aam.out("Anim_Ctrl: N") id+=1 aam.out("}") aam.dedent() aam.out("}") aam.out("ENDGEOMETRY") Blender.Set("curframe", saved_frame) Window.WaitCursor(0) if __name__ == '__main__': filename = sys.makename(ext='.aam') if validate_selection(): Window.FileSelector(write_aam, 'Export XVR AAM file', filename)