From 01ffe6cf89ee0ca32222f6993a2f8e3c872ce0b5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 9 Oct 2014 19:44:27 -0300 Subject: [PATCH] -Rasterizer supports meshes with both skeletons and blend shapes -Collada exporter supports Blend Shapes (even on actions via set driven keys) --- core/ustring.cpp | 36 +++ core/ustring.h | 1 + drivers/gles2/rasterizer_gles2.cpp | 138 +++++++-- drivers/gles2/rasterizer_gles2.h | 2 +- platform/windows/detect.py | 3 + tools/collada/collada.cpp | 7 +- tools/collada/collada.h | 24 +- .../io_plugins/editor_import_collada.cpp | 11 + .../export/blender25/io_scene_dae/__init__.py | 8 +- .../blender25/io_scene_dae/export_dae.py | 276 ++++++++++++++---- 10 files changed, 406 insertions(+), 100 deletions(-) diff --git a/core/ustring.cpp b/core/ustring.cpp index cd33c276a8..d75c21d16e 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -555,6 +555,42 @@ String String::get_slice(String p_splitter, int p_slice) const { } + +Vector String::split_spaces() const { + + Vector ret; + int from=0; + int i=0; + int len = length(); + bool inside=false; + + while(true) { + + bool empty=operator[](i)<33; + + if (i==0) + inside=!empty; + + if (!empty && !inside) { + inside=true; + from=i; + } + + if (empty && inside) { + + ret.push_back(substr(from,i-from)); + inside=false; + } + + if (i==len) + break; + i++; + } + + return ret; + +} + Vector String::split(const String &p_splitter,bool p_allow_empty) const { Vector ret; diff --git a/core/ustring.h b/core/ustring.h index 4831341866..8fe3a95463 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -150,6 +150,7 @@ public: String get_slice(String p_splitter,int p_slice) const; Vector split(const String &p_splitter,bool p_allow_empty=true) const; + Vector split_spaces() const; Vector split_floats(const String &p_splitter,bool p_allow_empty=true) const; Vector split_floats_mk(const Vector &p_splitters,bool p_allow_empty=true) const; Vector split_ints(const String &p_splitter,bool p_allow_empty=true) const; diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index f876b1acd3..95ec1c5544 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -5011,7 +5011,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) { } -template +template void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms) { uint32_t basesize = 3; @@ -5021,6 +5021,8 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str basesize+=4; uint32_t extra=(p_dst_stride-basesize*4); + const int dstvec_size=3+(USE_NORMAL?3:0)+(USE_TANGENT?4:0); + float dstcopy[dstvec_size]; for(int i=0;istride; - int dst_stride=surf->local_stride; + int dst_stride=skeleton_valid?surf->stride:surf->local_stride; int count = surf->array_len; + if (!skeleton_valid && i>=VS::ARRAY_MAX-3) + break; + + switch(i) { case VS::ARRAY_VERTEX: @@ -5193,7 +5217,21 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia dst[0]= src[0]*coef; dst[1]= src[1]*coef; dst[2]= src[2]*coef; - } break; + }; + + } break; + case VS::ARRAY_COLOR: { + + for(int k=0;karray_local[ofs+k*src_stride]; + uint8_t *dst = (uint8_t*)&base[ofs+k*dst_stride]; + + dst[0]= (src[0]*coeffp)>>8; + dst[1]= (src[1]*coeffp)>>8; + dst[2]= (src[2]*coeffp)>>8; + dst[3]= (src[3]*coeffp)>>8; + } } break; case VS::ARRAY_TEX_UV: @@ -5206,16 +5244,32 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia dst[0]= src[0]*coef; dst[1]= src[1]*coef; - } break; + } } break; + case VS::ARRAY_BONES: + case VS::ARRAY_WEIGHTS: { + + for(int k=0;karray_local[ofs+k*src_stride]; + float *dst = (float*)&base[ofs+k*dst_stride]; + + dst[0]= src[0]; + dst[1]= src[1]; + dst[2]= src[2]; + dst[3]= src[3]; + } + + } break; + } } for(int j=0;jmorph_target_count;j++) { - for(int i=0;iarray[i]; if (ad.size==0) @@ -5223,10 +5277,12 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia int ofs = ad.ofs; - int dst_stride=surf->local_stride; + int src_stride=surf->local_stride; + int dst_stride=skeleton_valid?surf->stride:surf->local_stride; int count = surf->array_len; const uint8_t *morph=surf->morph_targets_local[j].array; float w = p_morphs[j]; + int16_t wfp = CLAMP(w*255,0,255); switch(i) { @@ -5237,13 +5293,26 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia for(int k=0;k>8; + dst[1]= (src[1]*wfp)>>8; + dst[2]= (src[2]*wfp)>>8; + dst[3]= (src[3]*wfp)>>8; + } } break; case VS::ARRAY_TEX_UV: @@ -5251,18 +5320,43 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia for(int k=0;karray_local[surf->array[VS::ARRAY_WEIGHTS].ofs]; + const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs]; + const Skeleton::Bone *skeleton = &p_skeleton->bones[0]; + + + if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT) + _skeleton_xform(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton); + else if (surf->format&(VS::ARRAY_FORMAT_NORMAL)) + _skeleton_xform(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton); + else if (surf->format&(VS::ARRAY_FORMAT_TANGENT)) + _skeleton_xform(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton); + else + _skeleton_xform(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton); + + } + + stride=skeleton_valid?surf->stride:surf->local_stride; + + #if 0 { //in-place skeleton tansformation, only used for morphs, slow. @@ -5356,14 +5450,14 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs]; const Skeleton::Bone *skeleton = &p_skeleton->bones[0]; - if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT) - _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); + if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT) + _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); else if (surf->format&(VS::ARRAY_FORMAT_NORMAL)) - _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); + _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); else if (surf->format&(VS::ARRAY_FORMAT_TANGENT)) - _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); + _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); else - _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); + _skeleton_xform(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton); stride=dst_stride; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 4b56775b88..dc2e22d240 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -608,7 +608,7 @@ class RasterizerGLES2 : public Rasterizer { mutable SelfList::List _skeleton_dirty_list; - template + template void _skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms); struct Light { diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 744891b8e5..63fb5a47a5 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -64,6 +64,7 @@ def get_flags(): return [ ('freetype','builtin'), #use builtin freetype ('openssl','builtin'), #use builtin openssl + ('theora','no'), #use builtin openssl ] @@ -137,6 +138,8 @@ def configure(env): #build using mingw if (os.name=="nt"): env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes + else: + env["PROGSUFFIX"]=env["PROGSUFFIX"]+".exe" mingw_prefix="" diff --git a/tools/collada/collada.cpp b/tools/collada/collada.cpp index 16b15426df..f2e3a0e813 100644 --- a/tools/collada/collada.cpp +++ b/tools/collada/collada.cpp @@ -443,7 +443,10 @@ Vector Collada::_read_string_array(XMLParser& parser) { if (parser.get_node_type() == XMLParser::NODE_TEXT) { // parse String data String str = parser.get_node_data(); - array=str.split(" ",false); + array=str.split_spaces(); + for(int i=0;i& p_mesh,const Map& p_mesh,const Mapstride?vertex_src->stride:3) * vertex_index; @@ -1670,15 +1673,20 @@ void ColladaImport::_fix_param_animation_tracks() { source=skin.base; } else if (collada.state.morph_controller_data_map.has(source)) { + print_line("has morph"); const Collada::MorphControllerData& morph = collada.state.morph_controller_data_map[source]; + if (morph.targets.has("MORPH_WEIGHT") && morph.targets.has("MORPH_TARGET")) { + print_line("weight and target"); String weights = morph.targets["MORPH_WEIGHT"]; String targets = morph.targets["MORPH_TARGET"]; + //fails here if (morph.sources.has(targets) && morph.sources.has(weights)) { const Collada::MorphControllerData::Source &weight_src=morph.sources[weights]; const Collada::MorphControllerData::Source &target_src=morph.sources[targets]; + print_line("sources OK"); ERR_FAIL_COND(weight_src.array.size() != target_src.sarray.size()); @@ -1687,6 +1695,8 @@ void ColladaImport::_fix_param_animation_tracks() { String track_name = weights+"("+itos(i)+")"; String mesh_name = target_src.sarray[i]; if (collada.state.mesh_name_map.has(mesh_name) && collada.state.referenced_tracks.has(track_name)) { + print_line("refe tracks"); + const Vector&rt = collada.state.referenced_tracks[track_name]; @@ -1731,6 +1741,7 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) { for(int i=0;i bl_info = { - "name": "Khronos Collada format", + "name": "Better Collada Exporter", "author": "Juan Linietsky", "blender": (2, 5, 8), "api": 38691, "location": "File > Import-Export", - "description": ("Export DAE Scenes"), + "description": ("Export DAE Scenes, This plugin actually works better! otherwise contact me."), "warning": "", - "wiki_url": ("None"), + "wiki_url": ("http://www.godotengine.org"), "tracker_url": "", "support": 'OFFICIAL', "category": "Import-Export"} @@ -171,7 +171,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper): def menu_func(self, context): - self.layout.operator(ExportDAE.bl_idname, text="Khronos Collada (.dae)") + self.layout.operator(ExportDAE.bl_idname, text="Better Collada (.dae)") def register(): diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index 801eb7ae4c..9c104901f5 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -123,6 +123,11 @@ class DaeExporter: tup = (self.vertex.x,self.vertex.y,self.vertex.z,self.normal.x,self.normal.y,self.normal.z) for t in self.uv: tup = tup + (t.x,t.y) + #for t in self.bones: + # tup = tup + (t) + #for t in self.weights: + # tup = tup + (t) + return tup def __init__(self): @@ -315,13 +320,127 @@ class DaeExporter: return matid - def export_mesh(self,node,armature=None,shapename=None): + def export_mesh(self,node,armature=None,skeyindex=-1,skel_source=None): mesh = node.data - if (node.data in self.mesh_cache) and shapename==None: + + + if (node.data in self.mesh_cache): return self.mesh_cache[mesh] - if (len(node.modifiers) and self.config["use_mesh_modifiers"]) or shapename!=None: + if (skeyindex==-1 and mesh.shape_keys!=None and len(mesh.shape_keys.key_blocks)): + values=[] + morph_targets=[] + md=None + for k in range(0,len(mesh.shape_keys.key_blocks)): + shape = node.data.shape_keys.key_blocks[k] + values+=[shape.value] #save value + shape.value=0 + + mid = self.new_id("morph") + + for k in range(0,len(mesh.shape_keys.key_blocks)): + + shape = node.data.shape_keys.key_blocks[k] + node.show_only_shape_key=True + node.active_shape_key_index = k + shape.value = 1.0 + mesh.update() + """ + oldval = shape.value + shape.value = 1.0 + + """ + p = node.data + v = node.to_mesh(bpy.context.scene, True, "RENDER") + node.data = v +# self.export_node(node,il,shape.name) + node.data.update() + if (armature and k==0): + md=self.export_mesh(node,armature,k,mid) + else: + md=self.export_mesh(node,None,k) + + node.data = p + node.data.update() + shape.value = 0.0 + morph_targets.append(md) + + """ + shape.value = oldval + """ + node.show_only_shape_key=False + node.active_shape_key_index = 0 + + + self.writel(S_CONT,1,'') + #if ("skin_id" in morph_targets[0]): + # self.writel(S_CONT,2,'') + #else: + self.writel(S_CONT,2,'') + + self.writel(S_CONT,3,'') + self.writel(S_CONT,4,'') + marr="" + warr="" + for i in range(len(morph_targets)): + if (i==0): + continue + elif (i>1): + marr+=" " + + if ("skin_id" in morph_targets[i]): + marr+=morph_targets[i]["skin_id"] + else: + marr+=morph_targets[i]["id"] + + warr+=" 0" + + self.writel(S_CONT,5,marr) + self.writel(S_CONT,4,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,5,'') + self.writel(S_CONT,6,'') + self.writel(S_CONT,5,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,3,'') + + self.writel(S_CONT,3,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,5,warr) + self.writel(S_CONT,4,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,5,'') + self.writel(S_CONT,6,'') + self.writel(S_CONT,5,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,3,'') + + self.writel(S_CONT,3,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,4,'') + self.writel(S_CONT,3,'') + self.writel(S_CONT,2,'') + self.writel(S_CONT,1,'') + if (armature!=None): + + self.armature_for_morph[node]=armature + + meshdata={} + if (armature): + meshdata = morph_targets[0] + meshdata["morph_id"]=mid + else: + meshdata["id"]=morph_targets[0]["id"] + meshdata["morph_id"]=mid + meshdata["material_assign"]=morph_targets[0]["material_assign"] + + + + self.mesh_cache[node.data]=meshdata + return meshdata + + if (len(node.modifiers) and self.config["use_mesh_modifiers"]): mesh=node.to_mesh(self.scene,True,"RENDER") #is this allright? else: mesh=node.data @@ -349,7 +468,6 @@ class DaeExporter: for fi in range(len(mesh.tessfaces)): f=mesh.tessfaces[fi] - if (not (f.material_index in surface_indices)): surface_indices[f.material_index]=[] print("Type: "+str(type(f.material_index))) @@ -419,7 +537,7 @@ class DaeExporter: tup = v.get_tup() idx = 0 - if (tup in vertex_map): + if (skeyindex==-1 and tup in vertex_map): #do not optmize if using shapekeys idx = vertex_map[tup] else: idx = len(vertices) @@ -428,12 +546,9 @@ class DaeExporter: indices.append(idx) - if shapename != None: - meshid = self.new_id("mesh_"+shapename) - self.writel(S_GEOM,1,'') - else: - meshid = self.new_id("mesh") - self.writel(S_GEOM,1,'') + + meshid = self.new_id("mesh") + self.writel(S_GEOM,1,'') self.writel(S_GEOM,2,'') @@ -526,20 +641,26 @@ class DaeExporter: self.writel(S_GEOM,2,'') self.writel(S_GEOM,1,'') + meshdata={} meshdata["id"]=meshid meshdata["material_assign"]=mat_assign - self.mesh_cache[node.data]=meshdata + if (skeyindex==-1): + self.mesh_cache[node.data]=meshdata # Export armature data (if armature exists) - if (armature!=None): + if (armature!=None and (skel_source!=None or skeyindex==-1)): contid = self.new_id("controller") self.writel(S_CONT,1,'') - self.writel(S_CONT,2,'') + if (skel_source!=None): + self.writel(S_CONT,2,'') + else: + self.writel(S_CONT,2,'') + self.writel(S_CONT,3,''+strmtx(node.matrix_world)+'') #Joint Names self.writel(S_CONT,3,'') @@ -614,7 +735,7 @@ class DaeExporter: return meshdata - def export_mesh_node(self,node,il,shapename=None): + def export_mesh_node(self,node,il): if (node.data==None): return @@ -624,14 +745,19 @@ class DaeExporter: if (node.parent.type=="ARMATURE"): armature=node.parent - meshdata = self.export_mesh(node,armature,shapename) + meshdata = self.export_mesh(node,armature) + close_controller=False - if (armature==None): - self.writel(S_NODES,il,'') - else: + if ("skin_id" in meshdata): + close_controller=True self.writel(S_NODES,il,'') for sn in self.skeleton_info[armature]["skeleton_nodes"]: self.writel(S_NODES,il+1,'#'+sn+'') + elif ("morph_id" in meshdata): + self.writel(S_NODES,il,'') + close_controller=True + elif (armature==None): + self.writel(S_NODES,il,'') if (len(meshdata["material_assign"])>0): @@ -644,17 +770,17 @@ class DaeExporter: self.writel(S_NODES,il+2,'') self.writel(S_NODES,il+1,'') - if (armature==None): - self.writel(S_NODES,il,'') - else: + if (close_controller): self.writel(S_NODES,il,'') + else: + self.writel(S_NODES,il,'') def export_armature_bone(self,bone,il,si): boneid = self.new_id("bone") boneidx = si["bone_count"] si["bone_count"]+=1 - bonesid = si["name"]+"-"+str(boneidx) + bonesid = si["id"]+"-"+str(boneidx) si["bone_index"][bone.name]=boneidx si["bone_ids"][bone]=boneid si["bone_names"].append(bonesid) @@ -683,7 +809,7 @@ class DaeExporter: self.skeletons.append(node) armature = node.data - self.skeleton_info[node]={ "bone_count":0, "name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world } + self.skeleton_info[node]={ "bone_count":0, "id":self.new_id("skelbones"),"name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world } @@ -912,21 +1038,18 @@ class DaeExporter: - def export_node(self,node,il,shapename=None): + def export_node(self,node,il): if (not self.is_node_valid(node)): return bpy.context.scene.objects.active = node - if shapename != None: - self.writel(S_NODES,il,'') - else: - self.writel(S_NODES,il,'') + self.writel(S_NODES,il,'') il+=1 self.writel(S_NODES,il,''+strmtx(node.matrix_local)+'') print("NODE TYPE: "+node.type+" NAME: "+node.name) if (node.type=="MESH"): - self.export_mesh_node(node,il,shapename) + self.export_mesh_node(node,il) elif (node.type=="CURVE"): self.export_curve_node(node,il) elif (node.type=="ARMATURE"): @@ -937,22 +1060,9 @@ class DaeExporter: self.export_lamp_node(node,il) self.valid_nodes.append(node) - if shapename==None: - for x in node.children: - self.export_node(x,il) - if node.type=="MESH" and self.config["export_shapekeys"]: - for k in range(0,len(node.data.shape_keys.key_blocks)): - shape = node.data.shape_keys.key_blocks[k] - oldval = shape.value - shape.value = 1.0 - node.active_shape_key_index = k - p = node.data - v = node.to_mesh(bpy.context.scene, True, "RENDER") - node.data = v - self.export_node(node,il,shape.name) - node.data = p - node.data.update() - shape.value = oldval + for x in node.children: + self.export_node(x,il) + il-=1 self.writel(S_NODES,il,'') @@ -1003,18 +1113,22 @@ class DaeExporter: self.writel(S_ASSET,0,'') - def export_animation_transform_channel(self,target,transform_keys): + def export_animation_transform_channel(self,target,keys,matrices=True): - frame_total=len(transform_keys) + frame_total=len(keys) anim_id=self.new_id("anim") self.writel(S_ANIM,1,'') source_frames = "" source_transforms = "" source_interps = "" - for k in transform_keys: + for k in keys: source_frames += " "+str(k[0]) - source_transforms += " "+strmtx(k[1]) + if (matrices): + source_transforms += " "+strmtx(k[1]) + else: + source_transforms += " "+str(k[1]) + source_interps +=" LINEAR" @@ -1028,15 +1142,26 @@ class DaeExporter: self.writel(S_ANIM,3,'') self.writel(S_ANIM,2,'') - # Transform Source - self.writel(S_ANIM,2,'') - self.writel(S_ANIM,3,''+source_transforms+'') - self.writel(S_ANIM,3,'') - self.writel(S_ANIM,4,'') - self.writel(S_ANIM,5,'') - self.writel(S_ANIM,4,'') - self.writel(S_ANIM,3,'') - self.writel(S_ANIM,2,'') + if (matrices): + # Transform Source + self.writel(S_ANIM,2,'') + self.writel(S_ANIM,3,''+source_transforms+'') + self.writel(S_ANIM,3,'') + self.writel(S_ANIM,4,'') + self.writel(S_ANIM,5,'') + self.writel(S_ANIM,4,'') + self.writel(S_ANIM,3,'') + self.writel(S_ANIM,2,'') + else: + # Value Source + self.writel(S_ANIM,2,'') + self.writel(S_ANIM,3,''+source_transforms+'') + self.writel(S_ANIM,3,'') + self.writel(S_ANIM,4,'') + self.writel(S_ANIM,5,'') + self.writel(S_ANIM,4,'') + self.writel(S_ANIM,3,'') + self.writel(S_ANIM,2,'') # Interpolation Source self.writel(S_ANIM,2,'') @@ -1053,7 +1178,10 @@ class DaeExporter: self.writel(S_ANIM,3,'') self.writel(S_ANIM,3,'') self.writel(S_ANIM,2,'') - self.writel(S_ANIM,2,'') + if (matrices): + self.writel(S_ANIM,2,'') + else: + self.writel(S_ANIM,2,'') self.writel(S_ANIM,1,'') return [anim_id] @@ -1075,6 +1203,7 @@ class DaeExporter: tcn = [] xform_cache={} + blend_cache={} # Change frames first, export objects last # This improves performance enormously @@ -1089,9 +1218,26 @@ class DaeExporter: if (not node in self.valid_nodes): continue if (allowed!=None and not (node in allowed)): - continue + if (node.type=="MESH" and node.data!=None and (node in self.armature_for_morph) and (self.armature_for_morph[node] in allowed)): + pass #all good you pass with flying colors for morphs inside of action + else: + continue + if (node.type=="MESH" and node.data!=None and node.data.shape_keys!=None and (node.data in self.mesh_cache) and len(node.data.shape_keys.key_blocks)): + target = self.mesh_cache[node.data]["morph_id"] + for i in range(len(node.data.shape_keys.key_blocks)): + + if (i==0): + continue + + name=target+"-morph-weights("+str(i-1)+")" + if (not (name in blend_cache)): + blend_cache[name]=[] + + blend_cache[name].append( (key,node.data.shape_keys.key_blocks[i].value) ) + if (node.type=="MESH" and node.parent and node.parent.type=="ARMATURE"): + continue #In Collada, nodes that have skin modifier must not export animation, animate the skin instead. if (len(node.constraints)>0 or node.animation_data!=None): @@ -1108,6 +1254,7 @@ class DaeExporter: if (node.type=="ARMATURE"): #All bones exported for now + for bone in node.data.bones: bone_name=self.skeleton_info[node]["bone_ids"][bone] @@ -1138,7 +1285,9 @@ class DaeExporter: #export animation xml for nid in xform_cache: - tcn+=self.export_animation_transform_channel(nid,xform_cache[nid]) + tcn+=self.export_animation_transform_channel(nid,xform_cache[nid],True) + for nid in blend_cache: + tcn+=self.export_animation_transform_channel(nid,blend_cache[nid],False) return tcn @@ -1197,7 +1346,7 @@ class DaeExporter: print("Export anim: "+x.name) self.writel(S_ANIM_CLIPS,1,'') for z in tcn: - self.writel(S_ANIM_CLIPS,2,'') + self.writel(S_ANIM_CLIPS,2,'') self.writel(S_ANIM_CLIPS,1,'') @@ -1276,6 +1425,7 @@ class DaeExporter: self.skeleton_info={} self.config=kwargs self.valid_nodes=[] + self.armature_for_morph={}