[Bf-extensions-cvs] [c7eda7cb] master: glTF importer: add option to glue pieces of a mesh together

Julien Duroure noreply at git.blender.org
Tue Jul 21 21:20:41 CEST 2020


Commit: c7eda7cb49f706040cb04048b24c6db57501889e
Author: Julien Duroure
Date:   Tue Jul 21 21:18:35 2020 +0200
Branches: master
https://developer.blender.org/rBAc7eda7cb49f706040cb04048b24c6db57501889e

glTF importer: add option to glue pieces of a mesh together

Thanks scurest!

===================================================================

M	io_scene_gltf2/__init__.py
M	io_scene_gltf2/blender/imp/gltf2_blender_mesh.py

===================================================================

diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 57bdf3d5..ba7b3848 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -15,7 +15,7 @@
 bl_info = {
     'name': 'glTF 2.0 format',
     'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
-    "version": (1, 3, 39),
+    "version": (1, 3, 40),
     'blender': (2, 90, 0),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
@@ -862,6 +862,18 @@ class ImportGLTF2(Operator, ImportHelper):
         default=True
     )
 
+    merge_vertices: BoolProperty(
+        name='Merge Vertices',
+        description=(
+            'The glTF format requires discontinuous normals, UVs, and '
+            'other vertex attributes to be stored as separate vertices, '
+            'as required for rendering on typical graphics hardware.\n'
+            'This option attempts to combine co-located vertices where possible.\n'
+            'Currently cannot combine verts with different normals'
+        ),
+        default=False,
+    )
+
     import_shading: EnumProperty(
         name="Shading",
         items=(("NORMALS", "Use Normal Data", ""),
@@ -906,6 +918,7 @@ class ImportGLTF2(Operator, ImportHelper):
         layout.use_property_decorate = False  # No animation.
 
         layout.prop(self, 'import_pack_images')
+        layout.prop(self, 'merge_vertices')
         layout.prop(self, 'import_shading')
         layout.prop(self, 'guess_original_bind_pose')
         layout.prop(self, 'bone_heuristic')
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py b/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
index 33578de8..175bc920 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
@@ -217,6 +217,14 @@ def do_primitives(gltf, mesh_idx, skin_idx, mesh, ob):
     # the cache now that all prims are done.
     gltf.decode_accessor_cache = {}
 
+    if gltf.import_settings['merge_vertices']:
+        vert_locs, vert_normals, vert_joints, vert_weights, \
+        sk_vert_locs, loop_vidxs, edge_vidxs = \
+            merge_duplicate_verts(
+                vert_locs, vert_normals, vert_joints, vert_weights, \
+                sk_vert_locs, loop_vidxs, edge_vidxs\
+            )
+
     # ---------------
     # Convert all the arrays glTF -> Blender
 
@@ -537,3 +545,92 @@ def skin_into_bind_pose(gltf, skin_idx, vert_joints, vert_weights, locs, vert_no
 def mul_mats_vecs(mats, vecs):
     """Given [m1,m2,...] and [v1,v2,...], returns [m1 at v1,m2 at v2,...]. 3D only."""
     return np.matmul(mats, vecs.reshape(len(vecs), 3, 1)).reshape(len(vecs), 3)
+
+
+def merge_duplicate_verts(vert_locs, vert_normals, vert_joints, vert_weights, sk_vert_locs, loop_vidxs, edge_vidxs):
+    # This function attempts to invert the splitting done when exporting to
+    # glTF. Welds together verts with the same per-vert data (but possibly
+    # different per-loop data).
+    #
+    # Ideally normals would be treated as per-loop data, but that has problems,
+    # so we currently treat the normal as per-vert.
+    #
+    # Strategy is simple: put all the per-vert data into an array of structs
+    # ("dots"), dedupe with np.unique, then take all the data back out.
+
+    # Very often two verts that "morally" should be merged will have normals
+    # with very small differences. Round off the normals to smooth this over.
+    if len(vert_normals) != 0:
+        vert_normals *= 50000
+        vert_normals[:] = np.trunc(vert_normals)
+        vert_normals *= (1/50000)
+
+    dot_fields = [('x', np.float32), ('y', np.float32), ('z', np.float32)]
+    if len(vert_normals) != 0:
+        dot_fields += [('nx', np.float32), ('ny', np.float32), ('nz', np.float32)]
+    for i, _ in enumerate(vert_joints):
+        dot_fields += [
+            ('joint%dx' % i, np.uint32), ('joint%dy' % i, np.uint32),
+            ('joint%dz' % i, np.uint32), ('joint%dw' % i, np.uint32),
+            ('weight%dx' % i, np.float32), ('weight%dy' % i, np.float32),
+            ('weight%dz' % i, np.float32), ('weight%dw' % i, np.float32),
+        ]
+    for i, _ in enumerate(sk_vert_locs):
+        dot_fields += [
+            ('sk%dx' % i, np.float32), ('sk%dy' % i, np.float32), ('sk%dz' % i, np.float32),
+        ]
+    dots = np.empty(len(vert_locs), dtype=np.dtype(dot_fields))
+
+    dots['x'] = vert_locs[:, 0]
+    dots['y'] = vert_locs[:, 1]
+    dots['z'] = vert_locs[:, 2]
+    if len(vert_normals) != 0:
+        dots['nx'] = vert_normals[:, 0]
+        dots['ny'] = vert_normals[:, 1]
+        dots['nz'] = vert_normals[:, 2]
+    for i, (joints, weights) in enumerate(zip(vert_joints, vert_weights)):
+        dots['joint%dx' % i] = joints[:, 0]
+        dots['joint%dy' % i] = joints[:, 1]
+        dots['joint%dz' % i] = joints[:, 2]
+        dots['joint%dw' % i] = joints[:, 3]
+        dots['weight%dx' % i] = weights[:, 0]
+        dots['weight%dy' % i] = weights[:, 1]
+        dots['weight%dz' % i] = weights[:, 2]
+        dots['weight%dw' % i] = weights[:, 3]
+    for i, locs in enumerate(sk_vert_locs):
+        dots['sk%dx' % i] = locs[:, 0]
+        dots['sk%dy' % i] = locs[:, 1]
+        dots['sk%dz' % i] = locs[:, 2]
+
+    unique_dots, inv_indices = np.unique(dots, return_inverse=True)
+
+    loop_vidxs = inv_indices[loop_vidxs]
+    edge_vidxs = inv_indices[edge_vidxs]
+
+    vert_locs = np.empty((len(unique_dots), 3), dtype=np.float32)
+    vert_locs[:, 0] = unique_dots['x']
+    vert_locs[:, 1] = unique_dots['y']
+    vert_locs[:, 2] = unique_dots['z']
+    if len(vert_normals) != 0:
+        vert_normals = np.empty((len(unique_dots), 3), dtype=np.float32)
+        vert_normals[:, 0] = unique_dots['nx']
+        vert_normals[:, 1] = unique_dots['ny']
+        vert_normals[:, 2] = unique_dots['nz']
+    for i in range(len(vert_joints)):
+        vert_joints[i] = np.empty((len(unique_dots), 4), dtype=np.uint32)
+        vert_joints[i][:, 0] = unique_dots['joint%dx' % i]
+        vert_joints[i][:, 1] = unique_dots['joint%dy' % i]
+        vert_joints[i][:, 2] = unique_dots['joint%dz' % i]
+        vert_joints[i][:, 3] = unique_dots['joint%dw' % i]
+        vert_weights[i] = np.empty((len(unique_dots), 4), dtype=np.float32)
+        vert_weights[i][:, 0] = unique_dots['weight%dx' % i]
+        vert_weights[i][:, 1] = unique_dots['weight%dy' % i]
+        vert_weights[i][:, 2] = unique_dots['weight%dz' % i]
+        vert_weights[i][:, 3] = unique_dots['weight%dw' % i]
+    for i in range(len(sk_vert_locs)):
+        sk_vert_locs[i] = np.empty((len(unique_dots), 3), dtype=np.float32)
+        sk_vert_locs[i][:, 0] = unique_dots['sk%dx' % i]
+        sk_vert_locs[i][:, 1] = unique_dots['sk%dy' % i]
+        sk_vert_locs[i][:, 2] = unique_dots['sk%dz' % i]
+
+    return vert_locs, vert_normals, vert_joints, vert_weights, sk_vert_locs, loop_vidxs, edge_vidxs



More information about the Bf-extensions-cvs mailing list