浏览代码

Merge pull request #2130 from Palmer-JC/master

Blender 5.3
David Catuhe 8 年之前
父节点
当前提交
9490be2fe5

二进制
Exporters/Blender/Blender2Babylon-5.3.zip


+ 14 - 0
Exporters/Blender/src/babylon-js/json_exporter.py

@@ -62,6 +62,7 @@ class JsonExporter:
             self.skeletons = []
             skeletonId = 0
             self.meshesAndNodes = []
+            self.morphTargetMngrs = []
             self.materials = []
             self.multiMaterials = []
             self.sounds = []
@@ -106,6 +107,8 @@ class JsonExporter:
                         
                         if hasattr(mesh, 'instances'):
                             self.meshesAndNodes.append(mesh)
+                            if hasattr(mesh, 'morphTargetManagerId'):
+                                self.morphTargetMngrs.append(mesh)
                         else:
                             break
 
@@ -209,6 +212,17 @@ class JsonExporter:
             mesh.to_scene_file(file_handler)
         file_handler.write(']')
 
+        # Morph targets
+        file_handler.write(',\n"morphTargetManagers":[')
+        first = True
+        for mesh in self.morphTargetMngrs:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            mesh.write_morphing_file(file_handler)
+        file_handler.write(']')
+
         # Cameras
         file_handler.write(',\n"cameras":[')
         first = True

+ 1 - 1
Exporters/Blender/src/babylon-js/material.py

@@ -187,7 +187,7 @@ class BakingRecipe:
 
         # accumulators set by Blender Game
         self.backFaceCulling = True  # used only when baking
-        self.isBillboard = len(mesh.material_slots) == 1 and mesh.material_slots[0].material.game_settings.face_orientation == 'BILLBOARD'
+        self.isBillboard = len(mesh.material_slots) == 1 and mesh.material_slots[0] is not None and mesh.material_slots[0].material.game_settings.face_orientation == 'BILLBOARD'
 
         # Cycles specific, need to get the node trees of each material
         self.nodeTrees = []

+ 18 - 13
Exporters/Blender/src/babylon-js/mesh.py

@@ -9,6 +9,7 @@ from .shape_key_group import *
 import bpy
 import math
 from mathutils import Vector
+from random import randint
 import shutil
 
 # output related constants
@@ -435,6 +436,7 @@ class Mesh(FCurveAnimatable):
         if hasShapeKeys:
             Mesh.sort(keyOrderMap)
             self.rawShapeKeys = []
+            self.morphTargetManagerId = randint(0, 1000000) # not used for TOB implementation
             groupNames = []
             Logger.log('Shape Keys:', 2)
 
@@ -675,24 +677,27 @@ class Mesh(FCurveAnimatable):
         file_handler.write(']')
         
         # Shape Keys
-        if hasattr(self, 'rawShapeKeys'):
-            first = True
-            file_handler.write('\n,"MorphTargetManager":{')
-            write_string(file_handler, 'id', self.name, True)
-            file_handler.write('\n,"targets":[')
-            for key in self.rawShapeKeys:
-                if first == False:
-                    file_handler.write(',')
-
-                key.to_scene_file(file_handler)
-
-                first = False
-            file_handler.write(']}')
+        if hasattr(self, 'morphTargetManagerId'):
+            write_int(file_handler, 'morphTargetManagerId', self.morphTargetManagerId)
 
         # Close mesh
         file_handler.write('}\n')
         self.alreadyExported = True
 #===============================================================================
+    def write_morphing_file(self, file_handler):
+        first = True
+        file_handler.write('{')
+        write_int(file_handler, 'id', self.morphTargetManagerId, True)
+        file_handler.write('\n,"targets":[')
+        for key in self.rawShapeKeys:
+            if first == False:
+                file_handler.write(',')
+
+            key.to_scene_file(file_handler)
+
+            first = False
+        file_handler.write(']}')
+#===============================================================================
 class MeshInstance:
      def __init__(self, instancedMesh, rotation, rotationQuaternion):
         self.name = instancedMesh.name

+ 104 - 0
Exporters/Blender/src/babylon-js/shape_key_group.py

@@ -0,0 +1,104 @@
+from .logger import *
+from .package_level import *
+
+import bpy
+#===============================================================================
+# extract data in Mesh order, no optimization from group analysis yet; mapped into a copy of position
+# 
+class RawShapeKey:
+    def __init__(self, keyBlock, group, state, keyOrderMap, basis):
+        self.group = group
+        self.state = state
+        self.vertices = []
+
+        retSz = len(keyOrderMap)
+        for i in range(retSz):
+            self.vertices.append(None)
+
+        nDifferent = 0
+        for i in range(retSz):
+            pair = keyOrderMap[i]
+            value = keyBlock.data[pair[0]].co
+            self.vertices[pair[1]] = value
+            if not similar_vertex(value, basis.data[pair[0]].co):
+                nDifferent += 1
+
+        # only log when groups / allowVertReduction
+        if state != 'BASIS' and group is not None:
+            Logger.log('shape key "' + group + '-' + state + '":  n verts different from basis: ' + str(nDifferent), 3)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.state, True)
+        write_vector_array(file_handler, 'positions', self.vertices)
+        write_int(file_handler, 'influence', 0)
+        file_handler.write('}')
+#===============================================================================
+class ShapeKeyGroup:
+    def __init__(self, group, rawShapeKeys, basisVerts):
+        self.group = group
+        self.basisVerts = basisVerts
+        self.stateNames = []
+        self.stateVertices = []
+        self.affectedIndices = []
+
+        nRawKeys = len(rawShapeKeys)
+        nSize = len(self.basisVerts)
+
+        sameForAll = []
+        for i in range(nSize):
+            sameForAll.append(True)
+
+        # first pass to determine which vertices are not the same across all members of a group & also Basis
+        for i in range(nSize):
+            for key in rawShapeKeys:
+                # no need for more checking once 1 difference is found
+                if not sameForAll[i]:
+                    break;
+
+                # skip key if not member of the current group being processed
+                if group != key.group:
+                    continue;
+
+                # check vertex not different from Basis
+                if not similar_vertex(key.vertices[i],  self.basisVerts[i]):
+                    sameForAll[i] = False
+                    break;
+
+        affectedWholeVertices = []
+
+        # pass to convert sameForAll into self.affectedIndices, build 'BASIS' state at the same time
+        for i in range(nSize):
+            if not sameForAll[i]:
+                affectedWholeVertices.append(i)
+                self.affectedIndices.append(i * 3 + 0)
+                self.affectedIndices.append(i * 3 + 1)
+                self.affectedIndices.append(i * 3 + 2)
+
+        Logger.log('Shape-key group, ' + group + ', # of affected vertices: '+ str(len(affectedWholeVertices)) + ', out of ' + str(nSize), 2)
+
+        # pass to convert rawShapeKeys in this group, to stateVertices of only affected indices
+        for key in rawShapeKeys:
+            if group != key.group:
+                continue;
+
+            affectedVertices = []
+            for idx in affectedWholeVertices:
+                # clone vert, so key can be deleted in pass 1, and not affect pass2
+                # encode as a difference to basis, so more compact
+                vert = key.vertices[idx].copy()
+                vert.x -= self.basisVerts[idx].x
+                vert.y -= self.basisVerts[idx].y
+                vert.z -= self.basisVerts[idx].z
+                affectedVertices.append(vert)
+
+            self.stateNames.append(key.state)
+            self.stateVertices.append(affectedVertices)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_script_file(self, file_handler, var, indent):
+        writeInt32Array(file_handler, '_i', indent, self.affectedIndices, True)
+        file_handler.write(indent  + 'shapeKeyGroup = new QI.ShapeKeyGroup(' + var + ', "' + self.group + '", _i);\n')
+
+        for state_idx in range(len(self.stateVertices)):
+            writeFloat32Array(file_handler, '_i', indent, self.stateVertices[state_idx], True)
+            file_handler.write(indent  + 'shapeKeyGroup._addShapeKey("' + self.stateNames[state_idx] + '", true, _i);\n')