Bladeren bron

Merge pull request #6536 from tschw/Blender_extra_vertex_groups

Allows export of non-skinning Vertex Groups as BufferGeometry custom …
Ricardo Cabello 10 jaren geleden
bovenliggende
commit
61f529379b

+ 13 - 0
utils/exporters/blender/addons/io_three/__init__.py

@@ -305,6 +305,10 @@ def restore_export_settings(properties, settings):
         constants.APPLY_MODIFIERS,
         constants.EXPORT_OPTIONS[constants.APPLY_MODIFIERS])
 
+    properties.option_extra_vgroups = settings.get(
+        constants.EXTRA_VGROUPS,
+        constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
+
     properties.option_geometry_type = settings.get(
         constants.GEOMETRY_TYPE,
         constants.EXPORT_OPTIONS[constants.GEOMETRY_TYPE])
@@ -432,6 +436,7 @@ def set_settings(properties):
         constants.NORMALS: properties.option_normals,
         constants.SKINNING: properties.option_skinning,
         constants.BONES: properties.option_bones,
+        constants.EXTRA_VGROUPS: properties.option_extra_vgroups,
         constants.APPLY_MODIFIERS: properties.option_apply_modifiers,
         constants.GEOMETRY_TYPE: properties.option_geometry_type,
         constants.INDEX_TYPE: properties.option_index_type,
@@ -565,6 +570,11 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         description="Export bones",
         default=constants.EXPORT_OPTIONS[constants.BONES])
 
+    option_extra_vgroups = StringProperty(
+        name="Extra Vertex Groups",
+        description="Non-skinning vertex groups to export (comma-separated, w/ star wildcard, BufferGeometry only).",
+        default=constants.EXPORT_OPTIONS[constants.EXTRA_VGROUPS])
+
     option_apply_modifiers = BoolProperty(
         name="Apply Modifiers",
         description="Apply Modifiers to mesh objects",
@@ -778,6 +788,9 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         row.prop(self.properties, 'option_bones')
         row.prop(self.properties, 'option_skinning')
 
+        row = layout.row()
+        row.prop(self.properties, 'option_extra_vgroups')
+
         row = layout.row()
         row.prop(self.properties, 'option_apply_modifiers')
 

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

@@ -47,6 +47,7 @@ UVS = 'uvs'
 APPLY_MODIFIERS = 'applyModifiers'
 COLORS = 'colors'
 MIX_COLORS = 'mixColors'
+EXTRA_VGROUPS = 'extraVertexGroups'
 INDEX = 'index'
 DRAW_CALLS = 'offsets'
 DC_START = 'start'
@@ -108,6 +109,7 @@ EXPORT_OPTIONS = {
     UVS: True,
     APPLY_MODIFIERS: True,
     COLORS: False,
+    EXTRA_VGROUPS: '',
     INDEX_TYPE: UINT_16,
     MATERIALS: False,
     FACE_MATERIALS: False,

+ 92 - 0
utils/exporters/blender/addons/io_three/exporter/api/mesh.py

@@ -5,6 +5,7 @@ morph targets) with the geometry nodes.
 """
 
 import operator
+import re
 from bpy import data, types, context
 from . import material, texture, animation
 from . import object as object_
@@ -177,6 +178,97 @@ def buffer_uv(mesh):
     return uvs_
 
 
+@_mesh
+def extra_vertex_groups(mesh, patterns_string):
+    """
+    Returns (name,index) tuples for the extra (non-skinning) vertex groups
+    matching the given patterns.
+    The patterns are comma-separated where the star character can be used
+    as a wildcard character sequence.
+
+    :param mesh:
+    :param patterns_string:
+    :rtype: []
+
+    """
+    logger.debug("mesh._extra_vertex_groups(%s)", mesh)
+    pattern_re = None
+    extra_vgroups = []
+    if not patterns_string.strip():
+        return extra_vgroups
+    armature = _armature(mesh)
+    obj = object_.objects_using_mesh(mesh)[0]
+    for vgroup_index, vgroup in enumerate(obj.vertex_groups):
+        # Skip bone weights:
+        vgroup_name = vgroup.name
+        if armature:
+            is_bone_weight=False
+            for bone in armature.pose.bones:
+                if bone.name == vgroup_name:
+                    is_bone_weight=True
+                    break
+            if (is_bone_weight):
+                continue
+
+        if pattern_re is None:
+            # Translate user-friendly patterns to a regular expression:
+            # Join the whitespace-stripped, initially comma-separated
+            # entries to alternatives. Escape all characters except
+            # the star and replace that one with '.*?'.
+            pattern_re = '^(?:' + '|'.join(
+                map(lambda entry:
+                    '.*?'.join(map(re.escape, entry.strip().split('*'))),
+                patterns_string.split(',')) ) + ')$'
+
+        if not re.match(pattern_re, vgroup_name):
+            continue
+
+        extra_vgroups.append( (vgroup_name, vgroup_index) )
+    return extra_vgroups
+
+
+@_mesh
+def vertex_group_data(mesh, index):
+    """
+    Return vertex group data for each vertex. Vertices not in the group
+    get a zero value.
+
+    :param mesh:
+    :param index:
+
+    """
+    data = []
+    for vertex in mesh.vertices:
+        weight = None
+        for group in vertex.groups:
+            if group.group == index:
+                weight = group.weight
+        data.append(weight or 0.0)
+    return data
+
+
+@_mesh
+def buffer_vertex_group_data(mesh, index):
+    """
+    Return vertex group data for each deindexed vertex. Vertices not in the
+    group get a zero value.
+
+    :param mesh:
+    :param index:
+
+    """
+    data = []
+    for face in mesh.tessfaces:
+        for vertex_index in face.vertices:
+            vertex = mesh.vertices[vertex_index]
+            weight = None
+            for group in vertex.groups:
+                if group.group == index:
+                    weight = group.weight
+            data.append(weight or 0.0)
+    return data
+
+
 @_mesh
 def faces(mesh, options, materials=None):
     """

+ 34 - 0
utils/exporters/blender/addons/io_three/exporter/geometry.py

@@ -261,6 +261,12 @@ class Geometry(base_classes.BaseNode):
             else:
                 logger.info("No animation data found for %s", self.node)
 
+        option_extra_vgroups = self.options.get(constants.EXTRA_VGROUPS)
+
+        for name, index in api.mesh.extra_vertex_groups(self.node,
+                                                        option_extra_vgroups):
+            components.append(name);
+
         for component in components:
             try:
                 data[component] = self[component]
@@ -371,6 +377,7 @@ class Geometry(base_classes.BaseNode):
         options_vertices = self.options.get(constants.VERTICES)
         option_normals = self.options.get(constants.NORMALS)
         option_uvs = self.options.get(constants.UVS)
+        option_extra_vgroups = self.options.get(constants.EXTRA_VGROUPS)
         option_index_type = self.options.get(constants.INDEX_TYPE)
 
         pos_tuple = (constants.POSITION, options_vertices,
@@ -397,6 +404,22 @@ class Geometry(base_classes.BaseNode):
                 constants.ARRAY: array
             }
 
+        for name, index in api.mesh.extra_vertex_groups(self.node,
+                                                        option_extra_vgroups):
+
+            logger.info("Exporting extra vertex group %s", name)
+
+            array = api.mesh.buffer_vertex_group_data(self.node, index)
+            if not array:
+                logger.warning("No array could be made for %s", name)
+                continue
+
+            self[constants.ATTRIBUTES][name] = {
+                constants.ITEM_SIZE: 1,
+                constants.TYPE: constants.FLOAT_32,
+                constants.ARRAY: array
+            }
+
         if option_index_type != constants.NONE:
 
             assert(not (self.get(constants.INDEX) or
@@ -539,3 +562,14 @@ class Geometry(base_classes.BaseNode):
             logger.info("Parsing %s", constants.MORPH_TARGETS)
             self[constants.MORPH_TARGETS] = api.mesh.morph_targets(
                 self.node, self.options) or []
+
+        # In the moment there is no way to add extra data to a Geomtry in
+        # Three.js. In case there is some day, here is the code:
+        #
+        # option_extra_vgroups = self.options.get(constants.EXTRA_VGROUPS)
+        #
+        # for name, index in api.mesh.extra_vertex_groups(self.node,
+        #                                                 option_extra_vgroups):
+        #
+        #         logger.info("Exporting extra vertex group %s", name)
+        #         self[name] = api.mesh.vertex_group_data(self.node, index)