Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Duroure <julien.duroure@gmail.com>2020-07-21 22:18:35 +0300
committerJulien Duroure <julien.duroure@gmail.com>2020-07-21 22:18:35 +0300
commitc7eda7cb49f706040cb04048b24c6db57501889e (patch)
treeea6c66a2340d2bd1ed678324d44b061369b74c9f
parent9313b3a155bbe5b84dca81431ca9167cda94035d (diff)
glTF importer: add option to glue pieces of a mesh together
Thanks scurest!
-rwxr-xr-xio_scene_gltf2/__init__.py15
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_mesh.py97
2 files changed, 111 insertions, 1 deletions
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@v1,m2@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