Explorar o código

Blender 5.3-beta

- Exponential shadow maps
- Universal camera instead of Free
- Option to disable 64k vertices limit
- morph targets
Palmer-JC %!s(int64=8) %!d(string=hai) anos
pai
achega
56970325fe

BIN=BIN
Exporters/Blender/Blender2Babylon-5.3.zip


+ 3 - 1
Exporters/Blender/src/babylon-js/__init__.py

@@ -1,7 +1,7 @@
 bl_info = {
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (5, 2, 1),
+    'version': (5, 3, -1),
     'blender': (2, 76, 0),
     'location': 'File > Export > Babylon.js (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',
@@ -24,6 +24,7 @@ if "bpy" in locals():
     imp.reload(material)
     imp.reload(mesh)
     imp.reload(package_level)
+    imp.reload(shape_key_group)
     imp.reload(sound)
     imp.reload(world)
 else:
@@ -38,6 +39,7 @@ else:
     from . import material
     from . import mesh
     from . import package_level
+    from . import shape_key_group
     from . import sound
     from . import world
 

+ 5 - 5
Exporters/Blender/src/babylon-js/camera.py

@@ -11,7 +11,7 @@ import mathutils
 ARC_ROTATE_CAM = 'ArcRotateCamera'
 DEV_ORIENT_CAM = 'DeviceOrientationCamera'
 FOLLOW_CAM = 'FollowCamera'
-FREE_CAM = 'FreeCamera'
+UNIVERSAL_CAM = 'UniversalCamera'
 GAMEPAD_CAM = 'GamepadCamera'
 TOUCH_CAM = 'TouchCamera'
 V_JOYSTICKS_CAM = 'VirtualJoysticksCamera'
@@ -61,7 +61,7 @@ class Camera(FCurveAnimatable):
 
         if self.CameraType == ARC_ROTATE_CAM or self.CameraType == FOLLOW_CAM:
             if not hasattr(self, 'lockedTargetId'):
-                Logger.warn('Camera type with manditory target specified, but no target to track set.  Ignored', 2)
+                Logger.warn('Camera type with mandatory target specified, but no target to track set.  Ignored', 2)
                 self.fatalProblem = True
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     def update_for_target_attributes(self, meshesAndNodes):
@@ -146,14 +146,14 @@ bpy.types.Camera.CameraType = bpy.props.EnumProperty(
              (V_JOYSTICKS_CAM        , 'Virtual Joysticks'       , 'Use Virtual Joysticks Camera'),
              (TOUCH_CAM              , 'Touch'                   , 'Use Touch Camera'),
              (GAMEPAD_CAM            , 'Gamepad'                 , 'Use Gamepad Camera'),
-             (FREE_CAM               , 'Free'                    , 'Use Free Camera'),
+             (UNIVERSAL_CAM          , 'Universal'               , 'Use Universal Camera'),
              (FOLLOW_CAM             , 'Follow'                  , 'Use Follow Camera'),
              (DEV_ORIENT_CAM         , 'Device Orientation'      , 'Use Device Orientation Camera'),
              (ARC_ROTATE_CAM         , 'Arc Rotate'              , 'Use Arc Rotate Camera'),
              (VR_DEV_ORIENT_FREE_CAM , 'VR Dev Orientation Free' , 'Use VR Dev Orientation Free Camera'),
              (WEB_VR_FREE_CAM        , 'Web VR Free'             , 'Use Web VR Free Camera')
             ),
-    default = FREE_CAM
+    default = UNIVERSAL_CAM
 )
 bpy.types.Camera.checkCollisions = bpy.props.BoolProperty(
     name='Check Collisions',
@@ -175,7 +175,7 @@ bpy.types.Camera.Camera3DRig = bpy.props.EnumProperty(
     description='',
     items = (
              (RIG_MODE_NONE                             , 'None'                  , 'No 3D effects'),
-             (RIG_MODE_STEREOSCOPIC_ANAGLYPH            , 'Anaaglph'              , 'Stereoscopic Anagylph'),
+             (RIG_MODE_STEREOSCOPIC_ANAGLYPH            , 'Anaglyph'              , 'Stereoscopic Anagylph'),
              (RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL , 'side-by-side Parallel' , 'Stereoscopic side-by-side parallel'),
              (RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED, 'side-by-side crosseyed', 'Stereoscopic side-by-side crosseyed'),
              (RIG_MODE_STEREOSCOPIC_OVERUNDER           , 'over-under'            , 'Stereoscopic over-under'),

+ 6 - 0
Exporters/Blender/src/babylon-js/exporter_settings_panel.py

@@ -18,6 +18,11 @@ class ExporterSettingsPanel(bpy.types.Panel):
         description='Use face normals on all meshes.  Increases vertices.',
         default = False,
         )
+    bpy.types.Scene.force64Kmeshes = bpy.props.BoolProperty(
+        name='Force 64k per Mesh Vertex Limit',
+        description='When true, break up meshes with > 64k vertices for older\nhardware.  No effect when no qualifying meshes.',
+        default = True,
+        )
     bpy.types.Scene.attachedSound = bpy.props.StringProperty(
         name='Sound',
         description='',
@@ -55,6 +60,7 @@ class ExporterSettingsPanel(bpy.types.Panel):
         scene = context.scene
         layout.prop(scene, 'export_onlySelectedLayer')
         layout.prop(scene, 'export_flatshadeScene')
+        layout.prop(scene, 'force64Kmeshes')
         layout.prop(scene, 'ignoreIKBones')
 
         box = layout.box()

+ 2 - 3
Exporters/Blender/src/babylon-js/json_exporter.py

@@ -30,7 +30,7 @@ class JsonExporter:
             if bpy.ops.object.mode_set.poll():
                 bpy.ops.object.mode_set(mode = 'OBJECT')
 
-            # assign texture location, purely temporary if inlining
+            # assign texture location, purely temporary if in-lining
             self.textureDir = path.dirname(filepath)
             if not scene.inlineTextures:
                 self.textureDir = path.join(self.textureDir, scene.textureDir)
@@ -45,7 +45,6 @@ class JsonExporter:
             Logger.log('inline textures:  ' + format_bool(scene.inlineTextures), 2)
             if not scene.inlineTextures:
                 Logger.log('texture directory:  ' + self.textureDir, 2)
-                
             self.world = World(scene)
 
             bpy.ops.screen.animation_cancel()
@@ -99,7 +98,7 @@ class JsonExporter:
                     while True and self.isInSelectedLayer(object, scene):
                         mesh = Mesh(object, scene, nextStartFace, forcedParent, nameID, self)
                         if mesh.hasUnappliedTransforms and hasattr(mesh, 'skeletonWeights'):
-                            self.fatalError = 'Mesh: ' + mesh.name + ' has unapplied transformations.  This will never work for a mesh with an armature.  Export cancelled'
+                            self.fatalError = 'Mesh: ' + mesh.name + ' has un-applied transformations.  This will never work for a mesh with an armature.  Export cancelled'
                             Logger.log(self.fatalError)
                             return
 

+ 31 - 19
Exporters/Blender/src/babylon-js/light_shadow.py

@@ -16,8 +16,8 @@ HEMI_LIGHT = 3
 NO_SHADOWS = 'NONE'
 STD_SHADOWS = 'STD'
 POISSON_SHADOWS = 'POISSON'
-VARIANCE_SHADOWS = 'VARIANCE'
-BLUR_VARIANCE_SHADOWS = 'BLUR_VARIANCE'
+ESM_SHADOWS = 'ESM'
+BLUR_ESM_SHADOWS = 'BLUR_ESM'
 #===============================================================================
 class Light(FCurveAnimatable):
     def __init__(self, light, meshesAndNodes):
@@ -114,12 +114,12 @@ class ShadowGenerator:
         self.mapSize = lamp.data.shadowMapSize
         self.shadowBias = lamp.data.shadowBias
 
-        if lamp.data.shadowMap == VARIANCE_SHADOWS:
-            self.useVarianceShadowMap = True
+        if lamp.data.shadowMap == ESM_SHADOWS:
+            self.useExponentialShadowMap = True
         elif lamp.data.shadowMap == POISSON_SHADOWS:
             self.usePoissonSampling = True
-        elif lamp.data.shadowMap == BLUR_VARIANCE_SHADOWS:
-            self.useBlurVarianceShadowMap = True
+        elif lamp.data.shadowMap == BLUR_ESM_SHADOWS:
+            self.useBlurExponentialShadowMap = True
             self.shadowBlurScale = lamp.data.shadowBlurScale
             self.shadowBlurBoxOffset = lamp.data.shadowBlurBoxOffset
 
@@ -135,12 +135,12 @@ class ShadowGenerator:
         write_string(file_handler, 'lightId', self.lightId)
         write_float(file_handler, 'bias', self.shadowBias)
 
-        if hasattr(self, 'useVarianceShadowMap') :
-            write_bool(file_handler, 'useVarianceShadowMap', self.useVarianceShadowMap)
+        if hasattr(self, 'useExponentialShadowMap') :
+            write_bool(file_handler, 'useExponentialShadowMap', self.useExponentialShadowMap)
         elif hasattr(self, 'usePoissonSampling'):
             write_bool(file_handler, 'usePoissonSampling', self.usePoissonSampling)
-        elif hasattr(self, 'useBlurVarianceShadowMap'):
-            write_bool(file_handler, 'useBlurVarianceShadowMap', self.useBlurVarianceShadowMap)
+        elif hasattr(self, 'useBlurExponentialShadowMap'):
+            write_bool(file_handler, 'useBlurExponentialShadowMap', self.useBlurExponentialShadowMap)
             write_int(file_handler, 'blurScale', self.shadowBlurScale)
             write_int(file_handler, 'blurBoxOffset', self.shadowBlurBoxOffset)
 
@@ -167,8 +167,8 @@ bpy.types.Lamp.shadowMap = bpy.props.EnumProperty(
     items = ((NO_SHADOWS           , 'None'         , 'No Shadow Maps'),
              (STD_SHADOWS          , 'Standard'     , 'Use Standard Shadow Maps'),
              (POISSON_SHADOWS      , 'Poisson'      , 'Use Poisson Sampling'),
-             (VARIANCE_SHADOWS     , 'Variance'     , 'Use Variance Shadow Maps'),
-             (BLUR_VARIANCE_SHADOWS, 'Blur Variance', 'Use Blur Variance Shadow Maps')
+             (ESM_SHADOWS          , 'ESM'          , 'Use Exponential Shadow Maps'),
+             (BLUR_ESM_SHADOWS     , 'Blur ESM'     , 'Use Blur Exponential Shadow Maps')
             ),
     default = NO_SHADOWS
 )
@@ -186,13 +186,13 @@ bpy.types.Lamp.shadowBias = bpy.props.FloatProperty(
 
 bpy.types.Lamp.shadowBlurScale = bpy.props.IntProperty(
     name='Blur Scale',
-    description='',
+    description='Setting when using a Blur Variance shadow map',
     default = 2
 )
 
 bpy.types.Lamp.shadowBlurBoxOffset = bpy.props.IntProperty(
     name='Blur Box Offset',
-    description='',
+    description='Setting when using a Blur Variance shadow map',
     default = 0
 )
 #===============================================================================
@@ -211,12 +211,24 @@ class LightPanel(bpy.types.Panel):
         ob = context.object
         layout = self.layout
         layout.prop(ob.data, 'shadowMap')
-        layout.prop(ob.data, 'shadowMapSize')
-        layout.prop(ob.data, 'shadowBias')
+
+        usingShadows =  ob.data.shadowMap != NO_SHADOWS
+        row = layout.row()
+        row.enabled = usingShadows
+        row.prop(ob.data, 'shadowMapSize')
+        
+        row = layout.row()
+        row.enabled = usingShadows
+        row.prop(ob.data, 'shadowBias')
 
         box = layout.box()
-        box.label(text="Blur Variance Shadows")
-        box.prop(ob.data, 'shadowBlurScale')
-        box.prop(ob.data, 'shadowBlurBoxOffset')
+        box.label(text="Blur ESM Shadows")
+        usingBlur = ob.data.shadowMap == BLUR_ESM_SHADOWS
+        row = box.row()
+        row.enabled = usingBlur
+        row.prop(ob.data, 'shadowBlurScale')
+        row = box.row()
+        row.enabled = usingBlur
+        row.prop(ob.data, 'shadowBlurBoxOffset')
 
         layout.prop(ob.data, 'autoAnimate')

+ 1 - 0
Exporters/Blender/src/babylon-js/logger.py

@@ -53,4 +53,5 @@ class Logger:
             Logger.instance.log_handler.write('\t')
 
         Logger.instance.log_handler.write(msg)
+        print(msg) # for debugging / running Blender fron console
         if not noNewLine: Logger.instance.log_handler.write('\n')

+ 96 - 4
Exporters/Blender/src/babylon-js/mesh.py

@@ -4,6 +4,7 @@ from .package_level import *
 from .f_curve_animatable import *
 from .armature import *
 from .material import *
+from .shape_key_group import *
 
 import bpy
 import math
@@ -13,7 +14,7 @@ import shutil
 # output related constants
 MAX_VERTEX_ELEMENTS = 65535
 MAX_VERTEX_ELEMENTS_32Bit = 16777216
-COMPRESS_MATRIX_INDICES = True # this is True for .babylon exporter & False for TOB
+COMPRESS_MATRIX_INDICES = True
 
 # used in Mesh & Node constructors, defined in BABYLON.AbstractMesh
 BILLBOARDMODE_NONE = 0
@@ -31,6 +32,8 @@ CAPSULE_IMPOSTER = 5
 CONE_IMPOSTER = 6
 CYLINDER_IMPOSTER = 7
 CONVEX_HULL_IMPOSTER = 8
+
+SHAPE_KEY_GROUPS_ALLOWED = False
 #===============================================================================
 class Mesh(FCurveAnimatable):
     def __init__(self, object, scene, startFace, forcedParent, nameID, exporter):
@@ -141,7 +144,7 @@ class Mesh(FCurveAnimatable):
             self.physicsRestitution = object.rigid_body.restitution
 
         # process all of the materials required
-        maxVerts = MAX_VERTEX_ELEMENTS # change for multi-materials
+        maxVerts = MAX_VERTEX_ELEMENTS if scene.force64Kmeshes else MAX_VERTEX_ELEMENTS_32Bit # change for multi-materials or shapekeys
         recipe = BakingRecipe(object)
         self.billboardMode = BILLBOARDMODE_ALL if recipe.isBillboard else BILLBOARDMODE_NONE
 
@@ -212,6 +215,19 @@ class Mesh(FCurveAnimatable):
             totalInfluencers = 0
             highestInfluenceObserved = 0
 
+        hasShapeKeys = False
+        if object.data.shape_keys:
+            for block in object.data.shape_keys.key_blocks:
+                if (block.name == 'Basis'):
+                    hasShapeKeys = True
+                    keyOrderMap = []
+                    basis = block
+                    maxVerts = MAX_VERTEX_ELEMENTS_32Bit
+                    break
+
+            if not hasShapeKeys:
+                Logger.warn('Basis key missing, shape-key processing NOT performed', 2)
+
         # used tracking of vertices as they are received
         alreadySavedVertices = []
         vertices_Normals = []
@@ -370,6 +386,9 @@ class Mesh(FCurveAnimatable):
                             weightsPerVertex.append(matricesWeights)
                             indicesPerVertex.append(matricesIndices)
 
+                        if hasShapeKeys:
+                            keyOrderMap.append([vertex_index, len(self.positions)]) # use len positions before it is append to convert from 1 to 0 origin
+
                         vertices_indices[vertex_index].append(index)
 
                         self.positions.append(position)
@@ -381,7 +400,7 @@ class Mesh(FCurveAnimatable):
             self.subMeshes.append(SubMesh(materialIndex, subMeshVerticesStart, subMeshIndexStart, verticesCount - subMeshVerticesStart, indicesCount - subMeshIndexStart))
 
         if verticesCount > MAX_VERTEX_ELEMENTS:
-            Logger.warn('Due to multi-materials / Shapekeys & this meshes size, 32bit indices must be used.  This may not run on all hardware.', 2)
+            Logger.warn('Due to multi-materials, Shapekeys, or exporter settings & this meshes size, 32bit indices must be used.  This may not run on all hardware.', 2)
 
         BakedMaterial.meshBakingClean(object)
 
@@ -411,11 +430,56 @@ class Mesh(FCurveAnimatable):
         numZeroAreaFaces = self.find_zero_area_faces()
         if numZeroAreaFaces > 0:
             Logger.warn('# of 0 area faces found:  ' + str(numZeroAreaFaces), 2)
+
+        # shape keys for mesh
+        if hasShapeKeys:
+            Mesh.sort(keyOrderMap)
+            self.rawShapeKeys = []
+            groupNames = []
+            Logger.log('Shape Keys:', 2)
+
+            # process the keys in the .blend
+            for block in object.data.shape_keys.key_blocks:
+                # perform name format validation, before processing
+                keyName = block.name
+
+                # the Basis shape key is a member of all groups, processed in 2nd pass
+                if keyName == 'Basis': continue
+
+                if keyName.find('-') <= 0 and SHAPE_KEY_GROUPS_ALLOWED:
+                    if object.data.defaultShapeKeyGroup != DEFAULT_SHAPE_KEY_GROUP:
+                        keyName = object.data.defaultShapeKeyGroup + '-' + keyName
+                    else: continue
+                
+                group = None
+                state = keyName
+                if SHAPE_KEY_GROUPS_ALLOWED:
+                    temp = keyName.upper().partition('-')
+                    group = temp[0]
+                    state = temp[2]
+                self.rawShapeKeys.append(RawShapeKey(block, group, state, keyOrderMap, basis))
+
+                if SHAPE_KEY_GROUPS_ALLOWED:
+                    # check for a new group, add to groupNames if so
+                    newGroup = True
+                    for group in groupNames:
+                        if temp[0] == group:
+                            newGroup = False
+                            break
+                    if newGroup:
+                       groupNames.append(temp[0])
+
+            # process into ShapeKeyGroups, when rawShapeKeys found and groups allowed (implied)
+            if len(groupNames) > 0:
+                self.shapeKeyGroups = []
+                basis = RawShapeKey(basis, None, 'BASIS', keyOrderMap, basis)
+                for group in groupNames:
+                    self.shapeKeyGroups.append(ShapeKeyGroup(group,self.rawShapeKeys, basis.vertices))
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     def find_zero_area_faces(self):
         nFaces = int(len(self.indices) / 3)
         nZeroAreaFaces = 0
-        for f in range(0, nFaces):
+        for f in range(nFaces):
             faceOffset = f * 3
             p1 = self.positions[self.indices[faceOffset    ]]
             p2 = self.positions[self.indices[faceOffset + 1]]
@@ -426,6 +490,19 @@ class Mesh(FCurveAnimatable):
         return nZeroAreaFaces
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     @staticmethod
+    # ShapeKeyGroup depends on AffectedIndices being in asending order, so sort it, probably nothing to do
+    def sort(keyOrderMap):
+        notSorted = True
+        while(notSorted):
+            notSorted = False
+            for idx in range(1, len(keyOrderMap)):
+                if keyOrderMap[idx - 1][1] > keyOrderMap[idx][1]:
+                    tmp = keyOrderMap[idx]
+                    keyOrderMap[idx    ] = keyOrderMap[idx - 1]
+                    keyOrderMap[idx - 1] = tmp
+                    notSorted = True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
     def mesh_triangulate(mesh):
         try:
             import bmesh
@@ -596,6 +673,21 @@ class Mesh(FCurveAnimatable):
 
             first = False
         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(']}')
 
         # Close mesh
         file_handler.write('}\n')

+ 23 - 8
Exporters/Blender/src/babylon-js/package_level.py

@@ -19,7 +19,10 @@ def format_exporter_version(bl_info = None):
     if bl_info is None:
         bl_info = get_bl_info()
     exporterVersion = bl_info['version']
-    return str(exporterVersion[0]) + '.' + str(exporterVersion[1]) +  '.' + str(exporterVersion[2])
+    if exporterVersion[2] >= 0:
+        return str(exporterVersion[0]) + '.' + str(exporterVersion[1]) +  '.' + str(exporterVersion[2])
+    else:
+        return str(exporterVersion[0]) + '.' + str(exporterVersion[1]) +  '-beta'
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 def blenderMajorMinorVersion():
     # in form of '2.77 (sub 0)'
@@ -123,16 +126,18 @@ def format_matrix4(matrix):
 def format_array3(array):
     return format_f(array[0]) + ',' + format_f(array[1]) + ',' + format_f(array[2])
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-def format_array(array, indent = ''):
+def format_array(array, indent = '', beginIdx = 0, firstNotIncludedIdx = -1):
     ret = ''
     first = True
     nOnLine = 0
-    for element in array:
+    
+    endIdx = len(array) if firstNotIncludedIdx == -1 else firstNotIncludedIdx
+    for idx in range(beginIdx, endIdx):
         if (first != True):
             ret +=','
         first = False;
 
-        ret += format_f(element)
+        ret += format_f(array[idx])
         nOnLine += 1
 
         if nOnLine >= VERTEX_OUTPUT_PER_LINE:
@@ -147,7 +152,7 @@ def format_color(color):
 def format_vector(vector, switchYZ = True):
     return format_f(vector.x) + ',' + format_f(vector.z) + ',' + format_f(vector.y) if switchYZ else format_f(vector.x) + ',' + format_f(vector.y) + ',' + format_f(vector.z)
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-def format_vector_array(vectorArray, indent = ''):
+def format_vector_array(vectorArray, indent = '', switchYZ = True):
     ret = ''
     first = True
     nOnLine = 0
@@ -156,7 +161,7 @@ def format_vector_array(vectorArray, indent = ''):
             ret +=','
         first = False;
 
-        ret += format_vector(vector)
+        ret += format_vector(vector, switchYZ)
         nOnLine += 3
 
         if nOnLine >= VERTEX_OUTPUT_PER_LINE:
@@ -216,6 +221,16 @@ def same_vertex(vertA, vertB):
 
     return True
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def similar_vertex(vertA, vertB, tolerance = 0.00015):
+    if vertA is None or vertB is None: return False
+
+    if (abs(vertA.x - vertB.x) > tolerance or
+        abs(vertA.y - vertB.y) > tolerance or
+        abs(vertA.z - vertB.z) > tolerance ):
+        return False
+
+    return True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 def same_array(arrayA, arrayB):
     if(arrayA is None or arrayB is None): return False
     if len(arrayA) != len(arrayB): return False
@@ -241,8 +256,8 @@ def write_color(file_handler, name, color):
 def write_vector(file_handler, name, vector, switchYZ = True):
     file_handler.write(',"' + name + '":[' + format_vector(vector, switchYZ) + ']')
 
-def write_vector_array(file_handler, name, vectorArray):
-    file_handler.write('\n,"' + name + '":[' + format_vector_array(vectorArray) + ']')
+def write_vector_array(file_handler, name, vectorArray, switchYZ = True):
+    file_handler.write('\n,"' + name + '":[' + format_vector_array(vectorArray, '', switchYZ) + ']')
 
 def write_quaternion(file_handler, name, quaternion):
     file_handler.write(',"' + name  +'":[' + format_quaternion(quaternion) + ']')

+ 1 - 1
Tools/Gulp/gulpfile.js

@@ -398,7 +398,7 @@ gulp.task('run', ['watch', 'webserver'], function () {
 
 gulp.task("zip-blender" , function() {
     return gulp.src('../../Exporters/Blender/src/**')
-    .pipe(zip('Blender2Babylon-5.2.zip'))
+    .pipe(zip('Blender2Babylon-5.3.zip'))
     .pipe(gulp.dest('../../Exporters/Blender'));
 });