Index: collada.py =================================================================== --- collada.py (revision 20024) +++ collada.py (working copy) @@ -1821,6 +1821,7 @@ def SaveToXml(self, daeDocument): node = super(DaeControllerInstance,self).SaveToXml(daeDocument) for skeleton in self.skeletons: + skeleton = AdjustName(skeleton) #org AppendTextChild(node, DaeSyntax.SKELETON, "#"+skeleton) if not skeleton.startswith('#'): skeleton = "#"+skeleton AppendTextChild(node, DaeSyntax.SKELETON, skeleton) Index: cstartup.py =================================================================== --- cstartup.py (revision 20024) +++ cstartup.py (working copy) @@ -36,7 +36,7 @@ print "Error! Could not find Blender modules!" _ERROR = True -__version__ = '0.3.160' +__version__ = '0.3.161' # Show the wait cursor in blender Blender.Window.WaitCursor(1) @@ -256,9 +256,14 @@ toggleUseUV = None toggleSampleAnimation = None toggleOnlyMainScene = None +toggleApplyModifiers = None def LoadDefaultVals(): - global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, scriptsLocation, doImport, defaultFilename, fileButton, valsLoaded, togglePhysics, toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, toggleOnlyMainScene + global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, \ + toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, \ + scriptsLocation, doImport, defaultFilename, fileButton, valsLoaded, \ + togglePhysics, toggleExportCurrentScene, toggleExportRelativePaths, \ + toggleUseUV, toggleOnlyMainScene, toggleApplyModifiers if valsLoaded: return None @@ -310,10 +315,17 @@ toggleExportRelativePaths.val = colladaReg.get('exportRelativePaths', True) toggleSampleAnimation.val = colladaReg.get('sampleAnimation', False) toggleUseUV.val = colladaReg.get('useUV', False) + #TODO: "toggleOnlyMainScene" left out intentionally by the original plugin author? + toggleApplyModifiers.val = colladaReg.get('applyModifiers', True) valsLoaded = True def Gui(): - global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, scriptsLocation, doImport, defaultFilename, fileButton, togglePhysics, toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, toggleOnlyMainScene + global toggleLookAt, toggleBakeMatrix, toggleSampleAnimation, toggleNewScene, \ + toggleClearScene, toggleTriangles, togglePolygons, toggleExportSelection, \ + scriptsLocation, doImport, defaultFilename, fileButton, togglePhysics, \ + toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, \ + toggleOnlyMainScene, toggleApplyModifiers + Blender.BGL.glClearColor(0.898,0.910,0.808,1) # Set BG Color1 Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT) Blender.BGL.glColor3f(0.835,0.848,0.745) # BG Color 2 @@ -455,6 +467,7 @@ toggleUseUV = Blender.Draw.Toggle('Use UV Image Mats',15,45, yval, 150, 20, toggleUseUVVal, 'Use UV Image instead of the material textures. Use this if you did not use the Material Textures window. Note: If you reimport this file, they will have moved to the materials section!!') + ##yval = yval - 40 # Create Lookat Option if not (toggleLookAt is None): toggleLookAtVal = toggleLookAt.val @@ -462,6 +475,14 @@ toggleLookAtVal = 0 ##toggleLookAt = Blender.Draw.Toggle('Camera as Lookat',14,45, yval, 150, 20, toggleLookAtVal, 'Export the transformation of camera\'s as lookat') + + yval = yval - 40 + if not (toggleApplyModifiers is None): + toggleApplyModifiersVal = toggleApplyModifiers.val + else: + toggleApplyModifiersVal = 0 + + toggleApplyModifiers = Blender.Draw.Toggle('Apply modifiers',14,45, yval, 150, 20, toggleApplyModifiersVal, 'Apply modifiers, like mirroring, transformations, etc.') Blender.Draw.PushButton(importExportText, 12, 45+55+35+100+35, 10, 55, 20, importExportText) else: # IMPORT GUI @@ -507,7 +528,12 @@ pass def ButtonEvent(evt): - global toggleLookAt, toggleBakeMatrix, toggleExportSelection,toggleNewScene, toggleClearScene, toggleTriangles, togglePolygons, doImport, defaultFilename, fileSelectorShown, fileButton, valsLoaded, togglePhysics, toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, toggleSampleAnimation, toggleOnlyMainScene + global toggleLookAt, toggleBakeMatrix, toggleExportSelection,toggleNewScene, \ + toggleClearScene, toggleTriangles, togglePolygons, doImport, defaultFilename, \ + fileSelectorShown, fileButton, valsLoaded, togglePhysics, \ + toggleExportCurrentScene, toggleExportRelativePaths, toggleUseUV, \ + toggleSampleAnimation, toggleOnlyMainScene + checkImportButtons = False if evt == 1: toggle = 1 - toggle @@ -605,6 +631,11 @@ sampleAnimation = False else: sampleAnimation = bool(toggleSampleAnimation.val) + + if toggleApplyModifiers is None: + applyModifiers = False + else: + applyModifiers = bool(toggleApplyModifiers.val) d = Blender.Registry.GetKey('collada',True) @@ -627,6 +658,7 @@ d['exportRelativePaths'] = exportRelativePaths d['useUV'] = useUV d['sampleAnimation'] = sampleAnimation + d['applyModifiers'] = applyModifiers Blender.Registry.SetKey('collada',d, True) @@ -636,7 +668,12 @@ importExportText = "Export" try: - transl = translator.Translator(doImport,__version__,debug,fileName, useTriangles, usePolygons, bakeMatrices, exportSelection, newScene, clearScene, lookAt, usePhysics, exportCurrentScene, exportRelativePaths, useUV, sampleAnimation, onlyMainScene) + transl = translator.Translator(doImport,__version__,debug,fileName, \ + useTriangles, usePolygons, bakeMatrices,\ + exportSelection, newScene, clearScene, \ + lookAt, usePhysics, exportCurrentScene, \ + exportRelativePaths, useUV, sampleAnimation, \ + onlyMainScene, applyModifiers) # Redraw al 3D windows. Blender.Window.RedrawAll() Index: cutils.py =================================================================== --- cutils.py (revision 20024) +++ cutils.py (working copy) @@ -314,4 +314,11 @@ newMat = Matrix(matrix).transpose() print name,"loc: ", newMat.translationPart() print name,"euler: ", newMat.toEuler() - print name,"scale: ", newMat.scalePart() \ No newline at end of file + print name,"scale: ", newMat.scalePart() + +def AdjustName(adjustedName): + '''Adjust every name to fit to collada.py's StripString renaming (. -> _) and making + sure the name starts with a letter.''' + if len(adjustedName) > 0 and not adjustedName[0].isalpha(): + adjustedName = "i"+adjustedName + return adjustedName.replace('.', '_') \ No newline at end of file Index: translator.py =================================================================== --- translator.py (revision 20024) +++ translator.py (working copy) @@ -24,6 +24,12 @@ # -------------------------------------------------------------------------- # History +# 2009.04.16 by jan: +# - Added the possibility to export models with modifiers (mirrors, transformers, etc.). +# - Added helpful messages for users in case something goes wrong, so they know how and +# where to fix their model. +# - The patch from 2008.08.31, implementing the patch from Dmitri was incomplete. +# The joints were renamed (replace('.','_')), but not the vertex group names! # 2008.09.20 by migius: # - bugfix meshes with more than 16 materials: material index bigger than 15 replaced with 15. # 2008.08.31 by migius: @@ -44,14 +50,26 @@ import datetime from helperObjects import * +import BPyMesh +import BPyObject + debprn = 0 #--- print debug "print 'deb: ..." dmitri = 0 #switch for testing patch from Dmitri class Translator(object): isImporter = False - def __init__(self, isImporter, version, debugM, fileName, _useTriangles, _usePolygons, _bakeMatrices, _exportSelection, _createNewScene, _clearScene, _lookAt, _exportPhysics, _exportCurrentScene, _exportRelativePaths, _useUV, _sampleAnimation, _onlyMainScene): - global __version__, debugMode, usePhysics, useTriangles, usePolygons, bakeMatrices, exportSelection, createNewScene, clearScene, lookAt, replaceNames, exportPhysics, exportCurrentScene, useRelativePaths, useUV, sampleAnimation, onlyMainScene + def __init__(self, isImporter, version, debugM, fileName, _useTriangles, \ + _usePolygons, _bakeMatrices, _exportSelection, _createNewScene, \ + _clearScene, _lookAt, _exportPhysics, _exportCurrentScene, \ + _exportRelativePaths, _useUV, _sampleAnimation, _onlyMainScene, \ + _applyModifiers): + + global __version__, debugMode, usePhysics, useTriangles, usePolygons, \ + bakeMatrices, exportSelection, createNewScene, clearScene, lookAt, \ + replaceNames, exportPhysics, exportCurrentScene, useRelativePaths, \ + useUV, sampleAnimation, onlyMainScene, applyModifiers + #if debprn: print 'deb:class_Translator isImporter=', isImporter #deb--------- __version__ = version debugMode = debugM @@ -70,6 +88,7 @@ useUV = _useUV sampleAnimation = _sampleAnimation onlyMainScene= _onlyMainScene + applyModifiers= _applyModifiers replaceNames = clearScene @@ -351,10 +370,29 @@ daeScene = collada.DaeScene() + #---------- Copied from export OBJ ----------------------------- + # Get Container Mesh + # Remember: is this doesn't work, due to general problems, not especially + # COLLADA related, OBJ export fails also too! Keep this in sync, but remember + # that OBJ then still may use "NMesh", while this already uses "Mesh". + temp_mesh_name = '~tmp-mesh' + + # Get the container mesh. - used for applying modifiers and non mesh objects. + self.containerMesh = temp_mesh = None + for temp_mesh in Blender.Mesh.Get(): + if temp_mesh.name.startswith(temp_mesh_name): + if not temp_mesh.users: + self.containerMesh = temp_mesh + if not self.containerMesh: + self.containerMesh = Blender.Mesh.New(temp_mesh_name) + + del temp_mesh + #------------ [end] Copied from export OBJ ------------------------ + # Loop throug all scenes for bScene in Blender.Scene.Get(): if not exportCurrentScene or self.currentBScene == bScene: - self.fps = bScene.getRenderingContext( ).framesPerSec() + self.fps = bScene.getRenderingContext().framesPerSec() daeInstanceVisualScene = collada.DaeVisualSceneInstance() if usePhysics: daeInstancePhysicsScene = collada.DaePhysicsSceneInstance() @@ -503,7 +541,9 @@ if exportSelection: self.rootNodes = Blender.Object.GetSelected() self.childNodes = [] - else: # now loop trough all nodes in this scene and create a list with root nodes and children + else: + # Now loop trough all nodes in this scene and create a list with + # root nodes and children. for node in bScene.objects: pNode = node.parent if pNode is None: @@ -532,7 +572,8 @@ # Begin with the rootnodes for rootNode in self.rootNodes: sceneNode = SceneNode(self.document,self) - nodeResult = sceneNode.SaveSceneToDae(rootNode,self.childNodes,daePhysicsModel,daePhysicsModelInstance) + nodeResult = sceneNode.SaveSceneToDae(rootNode,self.childNodes, \ + daePhysicsModel,daePhysicsModelInstance,bScene) daeNode = nodeResult[0] daeVisualScene.nodes.append(daeNode) @@ -1022,9 +1063,13 @@ vGroups = dict() for vertexGroupName in bMesh.getVertGroupNames(): vwsdict = vGroups[vertexGroupName] = dict() - vws = bMesh.getVertsFromGroup(vertexGroupName,True) - for vw in vws: - vwsdict[vw[0]] = vw[1] + try: + vws = bMesh.getVertsFromGroup(vertexGroupName,True) + for vw in vws: + vwsdict[vw[0]] = vw[1] + except: + print("Vertex group '%s' couldn't be handled.\n" \ + "Maybe the group is empty.\n" % vertexGroupName) # Loop through each vertex group. for vertexGroupName in bMesh.getVertGroupNames(): @@ -1032,8 +1077,9 @@ if vertexGroupName in bArmature.bones.keys(): jointAccessor.count += 1 adjustedName = "" + vertexGroupName - if len(adjustedName) > 0 and not adjustedName[0].isalpha(): - adjustedName = "i"+adjustedName + # Jan: If we rename the bones/joints/armatures, we must rename the + # (corresponding) vertex groups also. + adjustedName = AdjustName(adjustedName) jointSourceArray.data.append(adjustedName) # Get the vertices in this vertexGroup verts = bMesh.getVertsFromGroup(vertexGroupName) @@ -1065,16 +1111,18 @@ vertTotalWeight = 0.0 jointVertexWeight = dict() + # Jan: Keep this bone/joints renaming always in snyc with the vertex group + # renaming! + #count up the number of joints to get an equal weight for vGroup in vGroups: if vert.index in vGroups[vGroup]: adjustedName = "" + vGroup - if len(adjustedName) > 0 and not adjustedName[0].isalpha(): - adjustedName = "i"+adjustedName + adjustedName = AdjustName(adjustedName) found = False weight = 0.0 try : - jointSourceArray.data.index(adjustedName.replace('.','_')) + jointSourceArray.data.index(adjustedName) vi = vGroups[vGroup] weight = vi[vert.index] found = True @@ -1083,7 +1131,7 @@ if found : jointCount += 1 vertJointCount[vert.index] = jointCount - jointVertexWeight[adjustedName.replace('.','_')] = weight + jointVertexWeight[adjustedName] = weight vertTotalWeight+= weight #now we know how many, so make an even weight: @@ -1092,19 +1140,18 @@ for vGroup in vGroups: if vert.index in vGroups[vGroup]: adjustedName = "" + vGroup - if len(adjustedName) > 0 and not adjustedName[0].isalpha(): - adjustedName = "i"+adjustedName + adjustedName = AdjustName(adjustedName) found = False try : - jointSourceArray.data.index(adjustedName.replace('.','_')) + jointSourceArray.data.index(adjustedName) found = True except: found = False if found : - daeSkin.vertexWeights.v.append(jointSourceArray.data.index(adjustedName.replace('.','_'))) + daeSkin.vertexWeights.v.append(jointSourceArray.data.index(adjustedName)) daeSkin.vertexWeights.v.append(weightIndex) if vertTotalWeight != 0.0: - jw = jointVertexWeight[adjustedName.replace('.','_')] + jw = jointVertexWeight[adjustedName] vw = jw / vertTotalWeight weightSourceArray.data.append(vw) #print "Joint ", adjustedName, " weight=", jw, "Total weight=",vertTotalWeight, " Final weight=", vw @@ -1977,8 +2024,9 @@ if debprn: print 'deb:class SceneNode_ObjectFromDae ---end---' #------------ return newObject - def SaveSceneToDae(self,bNode,childNodes,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance): - global bakeMatrices, exportSelection + def SaveSceneToDae(self, bNode, childNodes, daeGlobalPhysicsModel, \ + daeGlobalPhysicsModelInstance, bScene): + global bakeMatrices, exportSelection, applyModifiers, debprn daeNode = collada.DaeNode() daeNode.id = daeNode.name = self.document.CreateID(bNode.name,'-Node')# +'-node' @@ -2021,9 +2069,32 @@ daeGeometry = self.document.colladaDocument.geometriesLibrary.FindObject(bNode.getData(True)) meshNode = MeshNode(self.document) if daeGeometry is None: - daeGeometry = meshNode.SaveToDae(bNode.getData()) + # TODO: Maybe add a for-loop if multiple instance are made by + # a transformation. But so far even a double mirror + # (x and y axis) results only in _1_ instance. + derivedObject = BPyObject.getDerivedObjects(bNode)[0][0] + virtualMesh = BPyMesh.getMeshFromObject(derivedObject, \ + self.document.containerMesh, applyModifiers, False, bScene) + if debprn: + print("Virtual mesh: " + str(virtualMesh) ) + # + "; type: " + str(type(virtualMesh))) + if not virtualMesh: + # Fallback! + # Should never happen! + # (The "mesh=1" param on the getData() method ensures that + # it gets a "Mesh" instead of a "NMesh".) + print("Error while trying to save derived object / apply modifiers. Try saving " \ + + "more direct, all modifiers will be ignored.") + daeGeometry = meshNode.SaveToDae(bNode.getData(mesh=1)) + else: + # Apply original name from untransformed object + # to transformed object (name is later copied 1:1 to id). + virtualMesh.name = derivedObject.name + daeGeometry = meshNode.SaveToDae(virtualMesh) + meshID = daeGeometry.id - bindMaterials = meshNode.GetBindMaterials(bNode.getData(), daeGeometry.uvTextures, daeGeometry.uvIndex) + bindMaterials = meshNode.GetBindMaterials(bNode.getData(),\ + daeGeometry.uvTextures, daeGeometry.uvIndex) instance.object = daeGeometry instance.bindMaterials = bindMaterials @@ -2108,7 +2179,8 @@ for bNode in myChildNodes: sceneNode = SceneNode(self.document, self) - daeNode.nodes.append(sceneNode.SaveSceneToDae(bNode,childNodes,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance)[0]) + daeNode.nodes.append(sceneNode.SaveSceneToDae(bNode, childNodes, daeGlobalPhysicsModel, \ + daeGlobalPhysicsModelInstance, bScene)[0]) daePhysicsInstance = self.SavePhysicsToDae(bNode, meshID, daeNode,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance) return (daeNode, daePhysicsInstance) @@ -2366,7 +2438,11 @@ ##daeNodes.append(self.BoneToDae(rootBones[0], bPose, Matrix(bArmatureObject.matrix).transpose().invert(),poseMatrixRotInv, bArmatureObject)) if len(rootBones) > 1: - print "Please use only a single root for proper export" + print("Please use only a single root for proper export.\n" \ + "Nr. of root bones: %i.\n" \ + "List of root bones:" % len(rootBones)) + for rootBone in rootBones: + print("\t%s" % rootBone.__str__()) return daeNodes @@ -2760,7 +2836,7 @@ hasColor = False #Vertex colors: - if ( bMesh.hasVertexColours() ) : + if ( bMesh.vertexColors ) : hasColor = True daeSourceColors = collada.DaeSource() daeSourceColors.id = self.document.CreateID(daeGeometry.id , '-color')