Browse Source

Merge pull request #5556 from repsac/io_three

Allows up to 4 bone influences per mesh vertex
Mr.doob 10 years ago
parent
commit
e8a531f9e1

+ 72 - 22
utils/exporters/blender/addons/io_three/__init__.py

@@ -232,7 +232,8 @@ def save_settings_export(properties):
 
         constants.MORPH_TARGETS: properties.option_animation_morph,
         constants.ANIMATION: properties.option_animation_skeletal,
-        constants.FRAME_STEP: properties.option_frame_step
+        constants.FRAME_STEP: properties.option_frame_step,
+        constants.INFLUENCES_PER_VERTEX: properties.option_influences
     }
 
     fname = get_settings_fullpath()
@@ -253,16 +254,28 @@ def restore_settings_export(properties):
 
     ## Geometry {
     properties.option_vertices = settings.get(
-        constants.VERTICES, constants.EXPORT_OPTIONS[constants.VERTICES])
+        constants.VERTICES, 
+        constants.EXPORT_OPTIONS[constants.VERTICES])
+
     properties.option_faces = settings.get(
-        constants.FACES, constants.EXPORT_OPTIONS[constants.FACES])
+        constants.FACES, 
+        constants.EXPORT_OPTIONS[constants.FACES])
     properties.option_normals = settings.get(
-        constants.NORMALS, constants.EXPORT_OPTIONS[constants.NORMALS])
+        constants.NORMALS, 
+        constants.EXPORT_OPTIONS[constants.NORMALS])
 
     properties.option_skinning = settings.get(
-        constants.SKINNING, constants.EXPORT_OPTIONS[constants.SKINNING])
+        constants.SKINNING, 
+        constants.EXPORT_OPTIONS[constants.SKINNING])
+
     properties.option_bones = settings.get(
-        constants.BONES, constants.EXPORT_OPTIONS[constants.BONES])
+        constants.BONES, 
+        constants.EXPORT_OPTIONS[constants.BONES])
+
+    properties.option_influences = settings.get(
+        constants.INFLUENCES_PER_VERTEX,
+        constants.EXPORT_OPTIONS[constants.INFLUENCES_PER_VERTEX])
+
     properties.option_geometry_type = settings.get(
         constants.GEOMETRY_TYPE,
         constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
@@ -270,36 +283,55 @@ def restore_settings_export(properties):
 
     ## Materials {
     properties.option_materials = settings.get(
-        constants.MATERIALS, constants.EXPORT_OPTIONS[constants.MATERIALS])
+        constants.MATERIALS, 
+        constants.EXPORT_OPTIONS[constants.MATERIALS])
+
     properties.option_uv_coords = settings.get(
-        constants.UVS, constants.EXPORT_OPTIONS[constants.UVS])
+        constants.UVS, 
+        constants.EXPORT_OPTIONS[constants.UVS])
+
     properties.option_face_materials = settings.get(
         constants.FACE_MATERIALS, 
         constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
+
     properties.option_maps = settings.get(
-        constants.MAPS, constants.EXPORT_OPTIONS[constants.MAPS])
+        constants.MAPS, 
+        constants.EXPORT_OPTIONS[constants.MAPS])
+
     properties.option_colors = settings.get(
-        constants.COLORS, constants.EXPORT_OPTIONS[constants.COLORS])
+        constants.COLORS, 
+        constants.EXPORT_OPTIONS[constants.COLORS])
+
     properties.option_mix_colors = settings.get(
-        constants.MIX_COLORS, constants.EXPORT_OPTIONS[constants.MIX_COLORS])
+        constants.MIX_COLORS, 
+        constants.EXPORT_OPTIONS[constants.MIX_COLORS])
     ## }
 
     ## Settings {
     properties.option_scale = settings.get(
-        constants.SCALE, constants.EXPORT_OPTIONS[constants.SCALE])
+        constants.SCALE, 
+        constants.EXPORT_OPTIONS[constants.SCALE])
+
     properties.option_round_off = settings.get(
         constants.ENABLE_PRECISION, 
         constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
+
     properties.option_round_value = settings.get(
         constants.PRECISION, 
         constants.EXPORT_OPTIONS[constants.PRECISION])
+
     properties.option_logging = settings.get(
-        constants.LOGGING, constants.EXPORT_OPTIONS[constants.LOGGING])
+        constants.LOGGING, 
+        constants.EXPORT_OPTIONS[constants.LOGGING])
+
     properties.option_compression = settings.get(
-        constants.COMPRESSION, constants.NONE)
+        constants.COMPRESSION, 
+        constants.NONE)
+
     properties.option_copy_textures = settings.get(
         constants.COPY_TEXTURES, 
         constants.EXPORT_OPTIONS[constants.COPY_TEXTURES])
+
     properties.option_embed_animation = settings.get(
         constants.EMBED_ANIMATION, 
         constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
@@ -307,26 +339,34 @@ def restore_settings_export(properties):
 
     ## Scene {
     properties.option_export_scene = settings.get(
-        constants.SCENE, constants.EXPORT_OPTIONS[constants.SCENE])
+        constants.SCENE, 
+        constants.EXPORT_OPTIONS[constants.SCENE])
+
     properties.option_embed_geometry = settings.get(
         constants.EMBED_GEOMETRY, 
         constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
+
     properties.option_lights = settings.get(
-        constants.LIGHTS, constants.EXPORT_OPTIONS[constants.LIGHTS])
+        constants.LIGHTS, 
+        constants.EXPORT_OPTIONS[constants.LIGHTS])
+
     properties.option_cameras = settings.get(
-        constants.CAMERAS, constants.EXPORT_OPTIONS[constants.CAMERAS])
+        constants.CAMERAS, 
+        constants.EXPORT_OPTIONS[constants.CAMERAS])
     ## }
 
     ## Animation {
     properties.option_animation_morph = settings.get(
-        constants.MORPH_TARGETS, constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
+        constants.MORPH_TARGETS, 
+        constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
+
     properties.option_animation_skeletal = settings.get(
-        constants.ANIMATION, constants.EXPORT_OPTIONS[constants.ANIMATION])
-    #properties.option_frame_index_as_time = settings.get(
-    #    'option_frame_index_as_time', False)
+        constants.ANIMATION, 
+        constants.EXPORT_OPTIONS[constants.ANIMATION])
 
     properties.option_frame_step = settings.get(
-        constants.FRAME_STEP, constants.EXPORT_OPTIONS[constants.FRAME_STEP])
+        constants.FRAME_STEP, 
+        constants.EXPORT_OPTIONS[constants.FRAME_STEP])
     ## }
 
 def compression_types():
@@ -498,6 +538,13 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         items=compression_types(), 
         default=constants.NONE)
 
+    option_influences = IntProperty(
+        name='Influences',
+        description='Maximum number of bone influences',
+        min=1,
+        max=4,
+        default=2)
+
     def invoke(self, context, event):
         restore_settings_export(self.properties)
         return ExportHelper.invoke(self, context, event)
@@ -544,6 +591,9 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         row = layout.row()
         row.prop(self.properties, 'option_geometry_type')
+
+        row = layout.row()
+        row.prop(self.properties, 'option_influences')
         ## }
 
         layout.separator()

+ 4 - 2
utils/exporters/blender/addons/io_three/constants.py

@@ -43,7 +43,6 @@ VERTICES = 'vertices'
 FACES = 'faces'
 NORMALS = 'normals'
 BONES = 'bones'
-BONE_MAP = 'boneMap'
 UVS = 'uvs'
 COLORS = 'colors'
 MIX_COLORS = 'mixColors'
@@ -83,6 +82,8 @@ MSGPACK = 'msgpack'
 
 PACK = 'pack'
 
+INFLUENCES_PER_VERTEX = 'influencesPerVertex'
+
 EXPORT_OPTIONS = {
     FACES: True,
     VERTICES: True,
@@ -109,7 +110,8 @@ EXPORT_OPTIONS = {
     PRECISION: DEFAULT_PRECISION,
     EMBED_GEOMETRY: True,
     EMBED_ANIMATION: True,
-    GEOMETRY_TYPE: GEOMETRY
+    GEOMETRY_TYPE: GEOMETRY,
+    INFLUENCES_PER_VERTEX: 2
 }
 
 

+ 1 - 2
utils/exporters/blender/addons/io_three/exporter/api/camera.py

@@ -1,6 +1,5 @@
-import math
 from bpy import data, types, context
-from .. import constants, logger
+from .. import logger
 
 
 def _camera(func):

+ 2 - 2
utils/exporters/blender/addons/io_three/exporter/api/light.py

@@ -1,5 +1,5 @@
-from bpy import data, types, context
-from .. import constants, utilities, logger
+from bpy import data, types 
+from .. import utilities, logger
 
 
 def _lamp(func):

+ 13 - 15
utils/exporters/blender/addons/io_three/exporter/api/mesh.py

@@ -3,7 +3,7 @@ import mathutils
 from bpy import data, types, context
 from . import material, texture
 from . import object as object_
-from .. import constants, utilities, logger
+from .. import constants, utilities, logger, exceptions
 
 
 def _mesh(func):
@@ -51,7 +51,7 @@ def bones(mesh):
             index = 0
             for parent in armature.data.bones:
                 if parent.name == bone.parent.name:
-                    bone_index = index
+                    bone_index = bone_map.get(index)
                 index += 1
 
         bone_world_pos = armature.matrix_world * bone_pos
@@ -60,7 +60,8 @@ def bones(mesh):
         z_axis = -bone_world_pos.y
 
         if bone.use_deform:
-            logger.debug('Adding bone %s at: %s, %s', bone.name, bone_index, bone_index_rel)
+            logger.debug('Adding bone %s at: %s, %s', 
+                bone.name, bone_index, bone_index_rel)
             bone_map[bone_count] = bone_index_rel
             bone_index_rel += 1
             bones.append({
@@ -70,14 +71,12 @@ def bones(mesh):
                 constants.ROTQ: (0,0,0,1)
             })
         else:
-            logger.debug('Ignoring bone %s at: %s, %s', bone.name, bone_index, bone_index_rel)
+            logger.debug('Ignoring bone %s at: %s, %s', 
+                bone.name, bone_index, bone_index_rel)
 
         bone_count += 1
 
-    return {
-        constants.BONES: bones,
-        constants.BONE_MAP: bone_map
-    }
+    return (bones, bone_map)
 
 
 @_mesh
@@ -170,7 +169,6 @@ def faces(mesh, options):
     vertex_normals = _normals(mesh, options) if opt_normals else None
     vertex_colours = vertex_colors(mesh) if opt_colours else None
 
-    MASK = constants.MASK
     face_data = []
 
     logger.info('Parsing %d faces', len(mesh.tessfaces))
@@ -377,15 +375,15 @@ def normals(mesh, options):
 
 
 @_mesh
-def skin_weights(mesh, bone_map):
+def skin_weights(mesh, bone_map, influences):
     logger.debug('mesh.skin_weights(%s)', mesh)
-    return _skinning_data(mesh, bone_map, 1)
+    return _skinning_data(mesh, bone_map, influences, 1)
 
 
 @_mesh
-def skin_indices(mesh, bone_map):
+def skin_indices(mesh, bone_map, influences):
     logger.debug('mesh.skin_indices(%s)', mesh)
-    return _skinning_data(mesh, bone_map, 0)
+    return _skinning_data(mesh, bone_map, influences, 0)
 
 
 @_mesh
@@ -630,7 +628,7 @@ def _armature(mesh):
     return armature
 
 
-def _skinning_data(mesh, bone_map, array_index):
+def _skinning_data(mesh, bone_map, influences, array_index):
     armature = _armature(mesh)
     if not armature: return
 
@@ -645,7 +643,7 @@ def _skinning_data(mesh, bone_map, array_index):
 
         bone_array.sort(key=operator.itemgetter(1), reverse=True)
 
-        for index in range(2):
+        for index in range(influences):
             if index >= len(bone_array):
                 manifest.append(0)
                 continue

+ 1 - 5
utils/exporters/blender/addons/io_three/exporter/api/object.py

@@ -2,7 +2,7 @@ import math
 import mathutils
 import bpy
 from bpy import data, context, types
-from .. import constants, logger, utilities
+from .. import constants, logger, utilities, exceptions
 from .constants import (
     MESH,
     EMPTY,
@@ -13,8 +13,6 @@ from .constants import (
     POINT,
     HEMI,
     AREA,
-    PERSP,
-    ORTHO,
     CAMERA,
     PERSP,
     ORTHO,
@@ -50,7 +48,6 @@ def _object(func):
 
 def assemblies(valid_types):
     logger.debug('object.assemblies(%s)', valid_types)
-    nodes = []
     for obj in data.objects:
         if not obj.parent and obj.type in valid_types:
             yield obj.name
@@ -390,7 +387,6 @@ def _matrix(obj):
 
 
 def _on_visible_layer(obj, visible_layers):
-    obj_layers = []
     visible = True
     for index, layer in enumerate(obj.layers):
         if layer and index not in visible_layers:

+ 0 - 1
utils/exporters/blender/addons/io_three/exporter/api/texture.py

@@ -1,4 +1,3 @@
-import bpy
 from bpy import data, types
 from .. import constants, logger
 from .constants import IMAGE, MAG_FILTER, MIN_FILTER, MAPPING

+ 20 - 9
utils/exporters/blender/addons/io_three/exporter/geometry.py

@@ -179,7 +179,8 @@ class Geometry(base_classes.BaseNode):
         components = [constants.VERTICES, constants.FACES, 
             constants.UVS, constants.COLORS, constants.NORMALS,
             constants.BONES, constants.SKIN_WEIGHTS, 
-            constants.SKIN_INDICES, constants.NAME]
+            constants.SKIN_INDICES, constants.NAME,
+            constants.INFLUENCES_PER_VERTEX]
 
         data = {}
         anim_components = [constants.MORPH_TARGETS, constants.ANIMATION]
@@ -229,7 +230,8 @@ class Geometry(base_classes.BaseNode):
     def __geometry_metadata(self, metadata): 
         skip = (constants.TYPE, constants.FACES, constants.UUID,
             constants.ANIMATION, constants.SKIN_INDICES,
-            constants.BONE_MAP, constants.SKIN_WEIGHTS, constants.NAME)
+            constants.SKIN_WEIGHTS, constants.NAME, 
+            constants.INFLUENCES_PER_VERTEX)
         vectors = (constants.VERTICES, constants.NORMALS)
 
         for key in self.keys():
@@ -330,24 +332,33 @@ class Geometry(base_classes.BaseNode):
 
         if self.options.get(constants.UVS):
             logger.info('Parsing %s', constants.UVS)
-            self[constants.UVS] = api.mesh.uvs(self.node, self.options)
+            self[constants.UVS] = api.mesh.uvs(
+                self.node, self.options)
 
         if self.options.get(constants.ANIMATION):
             logger.info('Parsing %s', constants.ANIMATION)
             self[constants.ANIMATION] = api.mesh.animation(
                 self.node, self.options)
 
+        #@TODO: considering making bones data implied when
+        #       querying skinning data
+
+        bone_map = {}
         if self.options.get(constants.BONES):
             logger.info('Parsing %s', constants.BONES)
-            bone_data = api.mesh.bones(self.node)
-            self[constants.BONES] = bone_data[constants.BONES]
-            self[constants.BONE_MAP] = bone_data[constants.BONE_MAP]
+            bones, bone_map = api.mesh.bones(self.node)
+            self[constants.BONES] = bones
 
         if self.options.get(constants.SKINNING):
             logger.info('Parsing %s', constants.SKINNING)
-            bone_map = self.get(constants.BONE_MAP) or {}
-            self[constants.SKIN_INDICES] = api.mesh.skin_indices(self.node, bone_map)
-            self[constants.SKIN_WEIGHTS] = api.mesh.skin_weights(self.node, bone_map)
+            influences = self.options.get(
+                constants.INFLUENCES_PER_VERTEX, 2)
+
+            self[constants.INFLUENCES_PER_VERTEX] = influences
+            self[constants.SKIN_INDICES] = api.mesh.skin_indices(
+                self.node, bone_map, influences)
+            self[constants.SKIN_WEIGHTS] = api.mesh.skin_weights(
+                self.node, bone_map, influences)
 
         if self.options.get(constants.MORPH_TARGETS):
             logger.info('Parsing %s', constants.MORPH_TARGETS)

+ 1 - 1
utils/exporters/blender/addons/io_three/exporter/io.py

@@ -1,6 +1,6 @@
 import shutil
 from .. import constants
-from . import _json, logger, exceptions 
+from . import _json, logger
 
 
 def copy_registered_textures(dest, registration):

+ 0 - 3
utils/exporters/blender/addons/io_three/exporter/scene.py

@@ -2,11 +2,9 @@ import os
 from .. import constants
 from . import (
     base_classes,
-    image,
     texture,
     material,
     geometry, 
-    exceptions,
     object,
     logger,
     io,
@@ -83,7 +81,6 @@ class Scene(base_classes.BaseScene):
         extension = constants.EXTENSIONS.get(compression, 
             constants.EXTENSIONS[constants.JSON])
 
-        #@TODO: test this new logic
         export_dir = os.path.dirname(self.filepath)
         for key, value in self.items():
             

BIN
utils/exporters/blender/modules/msgpack/__pycache__/__init__.cpython-34.pyc


BIN
utils/exporters/blender/modules/msgpack/__pycache__/_version.cpython-34.pyc


BIN
utils/exporters/blender/modules/msgpack/__pycache__/exceptions.cpython-34.pyc


BIN
utils/exporters/blender/modules/msgpack/__pycache__/fallback.cpython-34.pyc


+ 18 - 5
utils/exporters/blender/tests/scripts/js/review.js

@@ -75,20 +75,33 @@ function loadObject( data ) {
     var loader = new THREE.ObjectLoader();
     scene = loader.parse( data );
 
-
     var hasLights = false;
 
     var lights = ['AmbientLight', 'DirectionalLight', 'AreaLight',
         'PointLight', 'SpotLight', 'HemisphereLight']
 
-    for ( i = 0; i < data.object.children.length; i ++ ) {
+    var cameras = ['OrthographicCamera', 'PerspectiveCamera'];
+
+    for ( i = 0; i < scene.children.length; i ++ ) {
 
-        var index = lights.indexOf( data.object.children[ i ].type );
+        var lightIndex = lights.indexOf( scene.children[ i ].type );
 
-        if ( index > -1 ) {
+        if ( lightIndex > -1 ) {
 
             hasLights = true;
-            break;
+            continue;
+
+        }
+
+        var cameraIndex = cameras.indexOf( scene.children[ i ].type );
+
+        if ( cameraIndex > -1 ) {
+
+            camera = scene.children[ i ];
+            var container = document.getElementById( 'viewport' );
+            var aspect = container.offsetWidth / container.offsetHeight;
+            camera.aspect = aspect;
+            camera.updateProjectionMatrix();
 
         }
 

+ 9 - 0
utils/exporters/blender/tests/scripts/test_geometry_influences.bash

@@ -0,0 +1,9 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/setup_test_env.bash"
+
+blender --background $BLEND/anim.blend --python $PYSCRIPT -- \
+    $JSON --vertices --faces --animation --bones --skinning \
+    --embedAnimation --influencesPerVertex 4
+makereview $@ --tag $(tagname)