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>2019-09-26 17:35:44 +0300
committerJulien Duroure <julien.duroure@gmail.com>2019-09-26 17:36:19 +0300
commit06bb353c848921a3f68f928aea154d471555e2dc (patch)
treecdc7b31572513f298a0217797354d07a45b4738c /io_scene_gltf2/blender/imp
parenta89261a31c6c109b735d06c025ab15a950b14c40 (diff)
glTF importer: big perf improvement
Diffstat (limited to 'io_scene_gltf2/blender/imp')
-rw-r--r--io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py11
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_gltf.py31
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_mesh.py285
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_primitive.py348
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_scene.py4
-rwxr-xr-xio_scene_gltf2/blender/imp/gltf2_blender_skin.py62
6 files changed, 341 insertions, 400 deletions
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
index baa0d95e..3c861451 100644
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
@@ -70,11 +70,8 @@ class BlenderWeightAnim():
values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
# retrieve number of targets
- nb_targets = 0
- for prim in gltf.data.meshes[gltf.data.nodes[node_idx].mesh].primitives:
- if prim.targets:
- if len(prim.targets) > nb_targets:
- nb_targets = len(prim.targets)
+ pymesh = gltf.data.meshes[gltf.data.nodes[node_idx].mesh]
+ nb_targets = len(pymesh.shapekey_names)
if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
offset = nb_targets
@@ -92,8 +89,8 @@ class BlenderWeightAnim():
group = action.groups[group_name]
for sk in range(nb_targets):
- if gltf.shapekeys[sk] is not None: # Do not animate shapekeys not created
- kb_name = obj.data.shape_keys.key_blocks[gltf.shapekeys[sk]].name
+ if pymesh.shapekey_names[sk] is not None: # Do not animate shapekeys not created
+ kb_name = pymesh.shapekey_names[sk]
data_path = "key_blocks[" + json.dumps(kb_name) + "].value"
fcurve = action.fcurves.new(data_path=data_path)
fcurve.group = group
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py b/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py
index 0f603bf3..c0507c03 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py
@@ -109,10 +109,6 @@ class BlenderGlTF():
# Init is to False, and will be set to True during creation
gltf.animation_object = False
- # Store shapekeys equivalent between target & shapekey index
- # For example when no POSITION on target
- gltf.shapekeys = {}
-
# Blender material
if gltf.data.materials:
for material in gltf.data.materials:
@@ -281,6 +277,33 @@ class BlenderGlTF():
mesh.blender_name = None
mesh.is_weight_animated = False
+ # Calculate names for each mesh's shapekeys
+ for mesh in gltf.data.meshes:
+ mesh.shapekey_names = []
+ used_names = set()
+
+ for sk, target in enumerate(mesh.primitives[0].targets or []):
+ if 'POSITION' not in target:
+ mesh.shapekey_names.append(None)
+ continue
+
+ # Check if glTF file has some extras with targetNames. Otherwise
+ # use the name of the POSITION accessor on the first primitive.
+ shapekey_name = None
+ if mesh.extras is not None:
+ if 'targetNames' in mesh.extras and sk < len(mesh.extras['targetNames']):
+ shapekey_name = mesh.extras['targetNames'][sk]
+ if shapekey_name is None:
+ if gltf.data.accessors[target['POSITION']].name is not None:
+ shapekey_name = gltf.data.accessors[target['POSITION']].name
+ if shapekey_name is None:
+ shapekey_name = "target_" + str(sk)
+
+ shapekey_name = BlenderGlTF.find_unused_name(used_names, shapekey_name)
+ used_names.add(shapekey_name)
+
+ mesh.shapekey_names.append(shapekey_name)
+
@staticmethod
def find_unused_name(haystack, desired_name):
"""Finds a name not in haystack and <= 63 UTF-8 bytes.
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py b/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
index 69aebd13..ba22d0cc 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
@@ -14,10 +14,11 @@
import bpy
import bmesh
+from mathutils import Vector
+from .gltf2_blender_material import BlenderMaterial
from .gltf2_blender_primitive import BlenderPrimitive
from ...io.imp.gltf2_io_binary import BinaryData
-from ...io.com.gltf2_io_color_management import color_linear_to_srgb
from ..com.gltf2_blender_conversion import loc_gltf_to_blender
@@ -31,21 +32,48 @@ class BlenderMesh():
"""Mesh creation."""
pymesh = gltf.data.meshes[mesh_idx]
- # Geometry
- if pymesh.name:
- mesh_name = pymesh.name
- else:
- mesh_name = "Mesh_" + str(mesh_idx)
+ # Create one bmesh, add all primitives to it, and then convert it to a
+ # mesh.
+ bme = bmesh.new()
- mesh = bpy.data.meshes.new(mesh_name)
- verts = []
- edges = []
- faces = []
- for prim in pymesh.primitives:
- verts, edges, faces = BlenderPrimitive.create(gltf, prim, verts, edges, faces)
+ # List of all the materials this mesh will use. The material each
+ # primitive uses is set by giving an index into this list.
+ materials = []
- mesh.from_pydata(verts, edges, faces)
- mesh.validate()
+ # Process all primitives
+ for prim in pymesh.primitives:
+ prim.blender_texcoord = {}
+
+ if prim.material is None:
+ material_idx = None
+ else:
+ pymaterial = gltf.data.materials[prim.material]
+
+ vertex_color = None
+ if 'COLOR_0' in prim.attributes:
+ vertex_color = 'COLOR_0'
+
+ # Create Blender material if needed
+ if vertex_color not in pymaterial.blender_material:
+ BlenderMaterial.create(gltf, prim.material, vertex_color)
+ material_name = pymaterial.blender_material[vertex_color]
+ material = bpy.data.materials[material_name]
+
+ try:
+ material_idx = materials.index(material)
+ except ValueError:
+ materials.append(material)
+ material_idx = len(materials) - 1
+
+ BlenderPrimitive.add_primitive_to_bmesh(gltf, bme, pymesh, prim, material_idx)
+
+ name = pymesh.name or 'Mesh_' + str(mesh_idx)
+ mesh = bpy.data.meshes.new(name)
+ BlenderMesh.bmesh_to_mesh(gltf, pymesh, bme, mesh)
+ bme.free()
+ for material in materials:
+ mesh.materials.append(material)
+ mesh.update()
pymesh.blender_name = mesh.name
@@ -53,31 +81,7 @@ class BlenderMesh():
@staticmethod
def set_mesh(gltf, pymesh, mesh, obj):
- """Set all data after mesh creation."""
- # Normals
- offset = 0
- custom_normals = [[0.0, 0.0, 0.0]] * len(mesh.vertices)
-
- if gltf.import_settings['import_shading'] == "NORMALS":
- mesh.create_normals_split()
-
- for prim in pymesh.primitives:
- offset = BlenderPrimitive.set_normals(gltf, prim, mesh, offset, custom_normals)
-
- mesh.update()
-
- # manage UV
- offset = 0
- for prim in pymesh.primitives:
- offset = BlenderPrimitive.set_UV(gltf, prim, obj, mesh, offset)
-
- mesh.update()
-
- # Normals, now that every update is done
- if gltf.import_settings['import_shading'] == "NORMALS":
- mesh.normals_split_custom_set_from_vertices(custom_normals)
- mesh.use_auto_smooth = True
-
+ """Sets mesh data after creation."""
# Object and UV are now created, we can set UVMap into material
for prim in pymesh.primitives:
vertex_color = None
@@ -85,139 +89,88 @@ class BlenderMesh():
vertex_color = 'COLOR_0'
BlenderPrimitive.set_UV_in_mat(gltf, prim, obj, vertex_color)
- # Assign materials to mesh
- offset = 0
- cpt_index_mat = 0
- bm = bmesh.new()
- bm.from_mesh(obj.data)
- bm.faces.ensure_lookup_table()
- for prim in pymesh.primitives:
- offset, cpt_index_mat = BlenderPrimitive.assign_material(gltf, prim, obj, bm, offset, cpt_index_mat)
-
- bm.to_mesh(obj.data)
- bm.free()
-
- # Create shapekeys if needed
- max_shape_to_create = 0
- for prim in pymesh.primitives:
- if prim.targets:
- if len(prim.targets) > max_shape_to_create:
- max_shape_to_create = len(prim.targets)
-
- # Create basis shape key
- if max_shape_to_create > 0:
- obj.shape_key_add(name="Basis")
-
- current_shapekey_index = 0
- for sk in range(max_shape_to_create):
-
- # Check if this target has POSITION
- if 'POSITION' not in prim.targets[sk].keys():
- gltf.shapekeys[sk] = None
- continue
-
- # Check if glTF file has some extras with targetNames
- shapekey_name = None
- if pymesh.extras is not None:
- if 'targetNames' in pymesh.extras.keys() and sk < len(pymesh.extras['targetNames']):
- shapekey_name = pymesh.extras['targetNames'][sk]
-
- if shapekey_name is None:
- shapekey_name = "target_" + str(sk)
-
- obj.shape_key_add(name=shapekey_name)
- current_shapekey_index += 1
-
- offset_idx = 0
- for prim in pymesh.primitives:
- if prim.targets is None:
- continue
- if sk >= len(prim.targets):
+ # set default weights for shape keys, and names, if not set by convention on extras data
+ if pymesh.weights is not None:
+ for i in range(len(pymesh.weights)):
+ if pymesh.shapekey_names[i] is None: # No default value if shapekeys was not created
continue
+ obj.data.shape_keys.key_blocks[pymesh.shapekey_names[i]].value = pymesh.weights[i]
- bm = bmesh.new()
- bm.from_mesh(mesh)
-
- shape_layer = bm.verts.layers.shape[current_shapekey_index]
- gltf.shapekeys[sk] = current_shapekey_index
-
- original_pos = BinaryData.get_data_from_accessor(gltf, prim.targets[sk]['POSITION'])
-
- tmp_indices = {}
- tmp_idx = 0
- pos = []
- for i in prim.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- pos.append(original_pos[i[0]])
-
- for vert in bm.verts:
- if vert.index not in range(offset_idx, offset_idx + prim.vertices_length):
- continue
-
- shape = vert[shape_layer]
+ @staticmethod
+ def bmesh_to_mesh(gltf, pymesh, bme, mesh):
+ bme.to_mesh(mesh)
+
+ # Unfortunately need to do shapekeys/normals/smoothing ourselves.
+
+ # Shapekeys
+ if len(bme.verts.layers.shape) != 0:
+ # The only way I could find to create a shape key was to temporarily
+ # parent mesh to an object and use obj.shape_key_add.
+ tmp_ob = None
+ try:
+ tmp_ob = bpy.data.objects.new('##gltf-import:tmp-object##', mesh)
+ tmp_ob.shape_key_add(name='Basis')
+ mesh.shape_keys.name = mesh.name
+ for layer_name in bme.verts.layers.shape.keys():
+ tmp_ob.shape_key_add(name=layer_name)
+ key_block = mesh.shape_keys.key_blocks[layer_name]
+ layer = bme.verts.layers.shape[layer_name]
+
+ for i, v in enumerate(bme.verts):
+ key_block.data[i].co = v[layer]
+ finally:
+ if tmp_ob:
+ bpy.data.objects.remove(tmp_ob)
- co = loc_gltf_to_blender(list(pos[vert.index - offset_idx]))
- shape.x = obj.data.vertices[vert.index].co.x + co[0]
- shape.y = obj.data.vertices[vert.index].co.y + co[1]
- shape.z = obj.data.vertices[vert.index].co.z + co[2]
+ # Normals
+ mesh.update()
- bm.to_mesh(obj.data)
- bm.free()
- offset_idx += prim.vertices_length
+ if gltf.import_settings['import_shading'] == "NORMALS":
+ mesh.create_normals_split()
- # set default weights for shape keys, and names, if not set by convention on extras data
- if pymesh.weights is not None:
- for i in range(max_shape_to_create):
- if i < len(pymesh.weights):
- if gltf.shapekeys[i] is None: # No default value if shapekeys was not created
- continue
- obj.data.shape_keys.key_blocks[gltf.shapekeys[i]].value = pymesh.weights[i]
- if shapekey_name is None: # No names set for now
- if gltf.data.accessors[pymesh.primitives[0].targets[i]['POSITION']].name is not None:
- obj.data.shape_keys.key_blocks[gltf.shapekeys[i]].name = \
- gltf.data.accessors[pymesh.primitives[0].targets[i]['POSITION']].name
-
- # Apply vertex color.
- vertex_color = None
- offset = 0
+ # use_smooth for faces
+ face_idx = 0
for prim in pymesh.primitives:
- if 'COLOR_0' in prim.attributes.keys():
- # Create vertex color, once only per object
- if vertex_color is None:
- vertex_color = obj.data.vertex_colors.new(name="COLOR_0")
-
- original_color_data = BinaryData.get_data_from_accessor(gltf, prim.attributes['COLOR_0'])
-
- tmp_indices = {}
- tmp_idx = 0
- color_data = []
- for i in prim.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- color_data.append(original_color_data[i[0]])
-
- for poly in mesh.polygons:
+ if 'NORMAL' not in prim.attributes:
+ face_idx += prim.num_faces
+ continue
+
+ if gltf.import_settings['import_shading'] == "FLAT":
+ for fi in range(face_idx, face_idx + prim.num_faces):
+ mesh.polygons[fi].use_smooth = False
+ elif gltf.import_settings['import_shading'] == "SMOOTH":
+ for fi in range(face_idx, face_idx + prim.num_faces):
+ mesh.polygons[fi].use_smooth = True
+ elif gltf.import_settings['import_shading'] == "NORMALS":
+ for fi in range(face_idx, face_idx + prim.num_faces):
+ poly = mesh.polygons[fi]
+ calc_norm_vertices = []
for loop_idx in range(poly.loop_start, poly.loop_start + poly.loop_total):
vert_idx = mesh.loops[loop_idx].vertex_index
- if vert_idx in range(offset, offset + prim.vertices_length):
- cpt_idx = vert_idx - offset
- # Need to convert from linear (glTF to sRGB (blender))
- # check dimension, and add alpha if needed
- if len(color_data[cpt_idx]) == 3:
- srgb_color = [
- color_linear_to_srgb(color_data[cpt_idx][0]),
- color_linear_to_srgb(color_data[cpt_idx][1]),
- color_linear_to_srgb(color_data[cpt_idx][2]),
- 1.0]
- else:
- srgb_color = [
- color_linear_to_srgb(color_data[cpt_idx][0]),
- color_linear_to_srgb(color_data[cpt_idx][1]),
- color_linear_to_srgb(color_data[cpt_idx][2]),
- color_data[cpt_idx][3]]
- vertex_color.data[loop_idx].color = srgb_color
- offset = offset + prim.vertices_length
+ calc_norm_vertices.append(vert_idx)
+
+ if len(calc_norm_vertices) == 3:
+ # Calcul normal
+ vert0 = mesh.vertices[calc_norm_vertices[0]].co
+ vert1 = mesh.vertices[calc_norm_vertices[1]].co
+ vert2 = mesh.vertices[calc_norm_vertices[2]].co
+ calc_normal = (vert1 - vert0).cross(vert2 - vert0).normalized()
+
+ # Compare normal to vertex normal
+ for i in calc_norm_vertices:
+ vec = Vector(bme.verts[i].normal)
+ if not calc_normal.dot(vec) > 0.9999999:
+ poly.use_smooth = True
+ break
+ else:
+ # shouldn't happen
+ pass
+
+ face_idx += prim.num_faces
+
+ # Custom normals, now that every update is done
+ if gltf.import_settings['import_shading'] == "NORMALS":
+ custom_normals = [v.normal for v in bme.verts]
+ mesh.normals_split_custom_set_from_vertices(custom_normals)
+ mesh.use_auto_smooth = True
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py b/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
index 0696673d..23625769 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
@@ -18,70 +18,201 @@ from mathutils import Vector
from .gltf2_blender_material import BlenderMaterial
from ..com.gltf2_blender_conversion import loc_gltf_to_blender
from ...io.imp.gltf2_io_binary import BinaryData
+from ...io.com.gltf2_io_color_management import color_linear_to_srgb
+from ...io.com import gltf2_io_debug
+MAX_NUM_COLOR_SETS = 8
+MAX_NUM_TEXCOORD_SETS = 8
+
class BlenderPrimitive():
"""Blender Primitive."""
def __new__(cls, *args, **kwargs):
raise RuntimeError("%s should not be instantiated" % cls)
@staticmethod
- def create(gltf, pyprimitive, verts, edges, faces):
- """Primitive creation."""
- pyprimitive.blender_texcoord = {}
+ def get_layer(bme_layers, name):
+ if name not in bme_layers:
+ return bme_layers.new(name)
+ return bme_layers[name]
+
+ @staticmethod
+ def add_primitive_to_bmesh(gltf, bme, pymesh, pyprimitive, material_index):
+ attributes = pyprimitive.attributes
+
+ if 'POSITION' not in attributes:
+ pyprimitive.num_faces = 0
+ return
+
+ positions = BinaryData.get_data_from_accessor(gltf, attributes['POSITION'])
- current_length = len(verts)
- pos = BinaryData.get_data_from_accessor(gltf, pyprimitive.attributes['POSITION'])
if pyprimitive.indices is not None:
indices = BinaryData.get_data_from_accessor(gltf, pyprimitive.indices)
+ indices = [i[0] for i in indices]
else:
- indices = [(i,) for i in range(len(pos))]
-
- pyprimitive.tmp_indices = indices
-
- # Manage only vertices that are in indices tab
- indice_equivalents = {}
- new_pos = []
- new_pos_idx = 0
- for i in indices:
- if i[0] not in indice_equivalents.keys():
- indice_equivalents[i[0]] = new_pos_idx
- new_pos.append(pos[i[0]])
- new_pos_idx += 1
-
- prim_verts = [loc_gltf_to_blender(vert) for vert in new_pos]
-
- mode = 4 if pyprimitive.mode is None else pyprimitive.mode
- prim_edges, prim_faces = BlenderPrimitive.edges_and_faces(mode, indices)
-
- verts.extend(prim_verts)
- pyprimitive.vertices_length = len(prim_verts)
- edges.extend(
- tuple(indice_equivalents[y] + current_length for y in e)
- for e in prim_edges
- )
- faces.extend(
- tuple(indice_equivalents[y] + current_length for y in f)
- for f in prim_faces
- )
-
- # manage material of primitive
- if pyprimitive.material is not None:
-
- vertex_color = None
- if 'COLOR_0' in pyprimitive.attributes.keys():
- vertex_color = 'COLOR_0'
-
- # Create Blender material if needed
- if vertex_color is None:
- if None not in gltf.data.materials[pyprimitive.material].blender_material.keys():
- BlenderMaterial.create(gltf, pyprimitive.material, vertex_color)
- else:
- if vertex_color not in gltf.data.materials[pyprimitive.material].blender_material.keys():
- BlenderMaterial.create(gltf, pyprimitive.material, vertex_color)
-
-
- return verts, edges, faces
+ indices = list(range(len(positions)))
+
+ bme_verts = bme.verts
+ bme_edges = bme.edges
+ bme_faces = bme.faces
+
+ # Every vertex has an index into the primitive's attribute arrays and a
+ # *different* index into the BMesh's list of verts. Call the first one the
+ # pidx and the second the bidx. Need to keep them straight!
+
+ # The pidx of all the vertices that are actually used by the primitive (only
+ # indices that appear in the pyprimitive.indices list are actually used)
+ used_pidxs = set(indices)
+ # Contains a pair (bidx, pidx) for every vertex in the primitive
+ vert_idxs = []
+ # pidx_to_bidx[pidx] will be the bidx of the vertex with that pidx (or -1 if
+ # unused)
+ pidx_to_bidx = [-1] * len(positions)
+ bidx = len(bme_verts)
+ for pidx in range(0, len(positions)):
+ if pidx in used_pidxs:
+ bme_verts.new(positions[pidx])
+ vert_idxs.append((bidx, pidx))
+ pidx_to_bidx[pidx] = bidx
+ bidx += 1
+ bme_verts.ensure_lookup_table()
+
+ # Add edges/faces to bmesh
+ mode = pyprimitive.mode or 4
+ edges, faces = BlenderPrimitive.edges_and_faces(mode, indices)
+ # NOTE: edges and vertices are in terms of pidxs!
+ for edge in edges:
+ try:
+ bme_edges.new((
+ bme_verts[pidx_to_bidx[edge[0]]],
+ bme_verts[pidx_to_bidx[edge[1]]],
+ ))
+ except ValueError:
+ # Ignores duplicate/degenerate edges
+ pass
+ pyprimitive.num_faces = 0
+ for face in faces:
+ try:
+ face = bme_faces.new(tuple(
+ bme_verts[pidx_to_bidx[i]]
+ for i in face
+ ))
+
+ if material_index is not None:
+ face.material_index = material_index
+
+ pyprimitive.num_faces += 1
+
+ except ValueError:
+ # Ignores duplicate/degenerate faces
+ pass
+
+ # Set normals
+ if 'NORMAL' in attributes:
+ normals = BinaryData.get_data_from_accessor(gltf, attributes['NORMAL'])
+ for bidx, pidx in vert_idxs:
+ bme_verts[bidx].normal = normals[pidx]
+
+ # Set vertex colors. Add them in the order COLOR_0, COLOR_1, etc.
+ set_num = 0
+ while 'COLOR_%d' % set_num in attributes:
+ if set_num >= MAX_NUM_COLOR_SETS:
+ gltf2_io_debug.print_console("WARNING",
+ "too many color sets; COLOR_%d will be ignored" % set_num
+ )
+ break
+
+ layer_name = 'COLOR_%d' % set_num
+ layer = BlenderPrimitive.get_layer(bme.loops.layers.color, layer_name)
+
+ colors = BinaryData.get_data_from_accessor(gltf, attributes[layer_name])
+
+ # Check whether Blender takes RGB or RGBA colors (old versions only take RGB)
+ num_components = len(colors[0])
+ blender_num_components = len(bme_verts[0].link_loops[0][layer])
+ if num_components == 3 and blender_num_components == 4:
+ # RGB -> RGBA
+ colors = [color+(1,) for color in colors]
+ if num_components == 4 and blender_num_components == 3:
+ # RGBA -> RGB
+ colors = [color[:3] for color in colors]
+ gltf2_io_debug.print_console("WARNING",
+ "this Blender doesn't support RGBA vertex colors; dropping A"
+ )
+
+ for bidx, pidx in vert_idxs:
+ for loop in bme_verts[bidx].link_loops:
+ loop[layer] = tuple(
+ color_linear_to_srgb(c)
+ for c in colors[pidx]
+ )
+
+ set_num += 1
+
+ # Set texcoords
+ set_num = 0
+ while 'TEXCOORD_%d' % set_num in attributes:
+ if set_num >= MAX_NUM_TEXCOORD_SETS:
+ gltf2_io_debug.print_console("WARNING",
+ "too many UV sets; TEXCOORD_%d will be ignored" % set_num
+ )
+ break
+
+ layer_name = 'TEXCOORD_%d' % set_num
+ layer = BlenderPrimitive.get_layer(bme.loops.layers.uv, layer_name)
+
+ pyprimitive.blender_texcoord[set_num] = layer_name
+
+ uvs = BinaryData.get_data_from_accessor(gltf, attributes[layer_name])
+
+ for bidx, pidx in vert_idxs:
+ # UV transform
+ u, v = uvs[pidx]
+ uv = (u, 1 - v)
+
+ for loop in bme_verts[bidx].link_loops:
+ loop[layer].uv = uv
+
+ set_num += 1
+
+ # Set joints/weights for skinning (multiple sets allow > 4 influences)
+ joint_sets = []
+ weight_sets = []
+ set_num = 0
+ while 'JOINTS_%d' % set_num in attributes and 'WEIGHTS_%d' % set_num in attributes:
+ joint_data = BinaryData.get_data_from_accessor(gltf, attributes['JOINTS_%d' % set_num])
+ weight_data = BinaryData.get_data_from_accessor(gltf, attributes['WEIGHTS_%d' % set_num])
+ joint_sets.append(joint_data)
+ weight_sets.append(weight_data)
+
+ set_num += 1
+
+ if joint_sets:
+ layer = BlenderPrimitive.get_layer(bme.verts.layers.deform, 'Vertex Weights')
+
+ for joint_set, weight_set in zip(joint_sets, weight_sets):
+ for bidx, pidx in vert_idxs:
+ for j in range(0, 4):
+ weight = weight_set[pidx][j]
+ if weight != 0.0:
+ joint = joint_set[pidx][j]
+ bme_verts[bidx][layer][joint] = weight
+
+ # Set morph target positions (no normals/tangents)
+ for sk, target in enumerate(pyprimitive.targets or []):
+ if pymesh.shapekey_names[sk] is None:
+ continue
+
+ layer_name = pymesh.shapekey_names[sk]
+ layer = BlenderPrimitive.get_layer(bme.verts.layers.shape, layer_name)
+
+ morph_positions = BinaryData.get_data_from_accessor(gltf, target['POSITION'])
+
+ for bidx, pidx in vert_idxs:
+ bme_verts[bidx][layer] = (
+ Vector(positions[pidx]) +
+ Vector(morph_positions[pidx])
+ )
@staticmethod
def edges_and_faces(mode, indices):
@@ -100,7 +231,7 @@ class BlenderPrimitive():
# / /
# 0 2
es = [
- (indices[i][0], indices[i + 1][0])
+ (indices[i], indices[i + 1])
for i in range(0, len(indices), 2)
]
elif mode == 2:
@@ -109,17 +240,17 @@ class BlenderPrimitive():
# / \
# 0-------3
es = [
- (indices[i][0], indices[i + 1][0])
+ (indices[i], indices[i + 1])
for i in range(0, len(indices) - 1)
]
- es.append((indices[-1][0], indices[0][0]))
+ es.append((indices[-1], indices[0]))
elif mode == 3:
# LINE STRIP
# 1---2
# / \
# 0 3
es = [
- (indices[i][0], indices[i + 1][0])
+ (indices[i], indices[i + 1])
for i in range(0, len(indices) - 1)
]
elif mode == 4:
@@ -128,7 +259,7 @@ class BlenderPrimitive():
# / \ / \
# 0---1 4---5
fs = [
- (indices[i][0], indices[i + 1][0], indices[i + 2][0])
+ (indices[i], indices[i + 1], indices[i + 2])
for i in range(0, len(indices), 3)
]
elif mode == 5:
@@ -140,7 +271,7 @@ class BlenderPrimitive():
even = i % 2 == 0
return xs if even else (xs[0], xs[2], xs[1])
fs = [
- alternate(i, (indices[i][0], indices[i + 1][0], indices[i + 2][0]))
+ alternate(i, (indices[i], indices[i + 1], indices[i + 2]))
for i in range(0, len(indices) - 2)
]
elif mode == 6:
@@ -149,7 +280,7 @@ class BlenderPrimitive():
# / \ / \
# 4---0---1
fs = [
- (indices[0][0], indices[i][0], indices[i + 1][0])
+ (indices[0], indices[i], indices[i + 1])
for i in range(1, len(indices) - 1)
]
else:
@@ -157,86 +288,7 @@ class BlenderPrimitive():
return es, fs
- def set_normals(gltf, pyprimitive, mesh, offset, custom_normals):
- """Set Normal."""
- if 'NORMAL' in pyprimitive.attributes.keys():
- original_normal_data = BinaryData.get_data_from_accessor(gltf, pyprimitive.attributes['NORMAL'])
-
- tmp_indices = {}
- tmp_idx = 0
- normal_data = []
- for i in pyprimitive.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- normal_data.append(original_normal_data[i[0]])
-
- for poly in mesh.polygons:
- if gltf.import_settings['import_shading'] == "NORMALS":
- calc_norm_vertices = []
- for loop_idx in range(poly.loop_start, poly.loop_start + poly.loop_total):
- vert_idx = mesh.loops[loop_idx].vertex_index
- if vert_idx in range(offset, offset + pyprimitive.vertices_length):
- cpt_vert = vert_idx - offset
- mesh.vertices[vert_idx].normal = normal_data[cpt_vert]
- custom_normals[vert_idx] = list(normal_data[cpt_vert])
- calc_norm_vertices.append(vert_idx)
-
- if len(calc_norm_vertices) == 3:
- # Calcul normal
- vert0 = mesh.vertices[calc_norm_vertices[0]].co
- vert1 = mesh.vertices[calc_norm_vertices[1]].co
- vert2 = mesh.vertices[calc_norm_vertices[2]].co
- calc_normal = (vert1 - vert0).cross(vert2 - vert0).normalized()
-
- # Compare normal to vertex normal
- for i in calc_norm_vertices:
- cpt_vert = vert_idx - offset
- vec = Vector(
- (normal_data[cpt_vert][0], normal_data[cpt_vert][1], normal_data[cpt_vert][2])
- )
- if not calc_normal.dot(vec) > 0.9999999:
- poly.use_smooth = True
- break
- elif gltf.import_settings['import_shading'] == "FLAT":
- poly.use_smooth = False
- elif gltf.import_settings['import_shading'] == "SMOOTH":
- poly.use_smooth = True
- else:
- pass # Should not happen
-
- offset = offset + pyprimitive.vertices_length
- return offset
-
- def set_UV(gltf, pyprimitive, obj, mesh, offset):
- """Set UV Map."""
- for texcoord in [attr for attr in pyprimitive.attributes.keys() if attr[:9] == "TEXCOORD_"]:
- if texcoord not in mesh.uv_layers:
- mesh.uv_layers.new(name=texcoord)
- pyprimitive.blender_texcoord[int(texcoord[9:])] = texcoord
-
- original_texcoord_data = BinaryData.get_data_from_accessor(gltf, pyprimitive.attributes[texcoord])
-
-
- tmp_indices = {}
- tmp_idx = 0
- texcoord_data = []
- for i in pyprimitive.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- texcoord_data.append(original_texcoord_data[i[0]])
-
- for poly in mesh.polygons:
- for loop_idx in range(poly.loop_start, poly.loop_start + poly.loop_total):
- vert_idx = mesh.loops[loop_idx].vertex_index
- if vert_idx in range(offset, offset + pyprimitive.vertices_length):
- obj.data.uv_layers[texcoord].data[loop_idx].uv = \
- Vector((texcoord_data[vert_idx - offset][0], 1 - texcoord_data[vert_idx - offset][1]))
-
- offset = offset + pyprimitive.vertices_length
- return offset
-
+ @staticmethod
def set_UV_in_mat(gltf, pyprimitive, obj, vertex_color):
"""After nodetree creation, set UVMap in nodes."""
if pyprimitive.material is None:
@@ -267,21 +319,3 @@ class BlenderPrimitive():
[gltf.TEXTURE, gltf.TEXTURE_FACTOR]:
BlenderMaterial.set_uvmap(gltf, pyprimitive.material, pyprimitive, obj, vertex_color)
- def assign_material(gltf, pyprimitive, obj, bm, offset, cpt_index_mat):
- """Assign material to faces of primitives."""
- if pyprimitive.material is not None:
-
- vertex_color = None
- if 'COLOR_0' in pyprimitive.attributes.keys():
- vertex_color = 'COLOR_0'
-
- obj.data.materials.append(bpy.data.materials[gltf.data.materials[pyprimitive.material].blender_material[vertex_color]])
- for vert in bm.verts:
- if vert.index in range(offset, offset + pyprimitive.vertices_length):
- for loop in vert.link_loops:
- face = loop.face.index
- bm.faces[face].material_index = cpt_index_mat
- cpt_index_mat += 1
- offset = offset + pyprimitive.vertices_length
- return offset, cpt_index_mat
-
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
index aa9684c7..d2d35f64 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py
@@ -87,10 +87,6 @@ class BlenderScene():
for skin_id, skin in enumerate(gltf.data.skins):
if hasattr(skin, "node_ids"):
- BlenderSkin.assign_vertex_groups(gltf, skin_id)
-
- for skin_id, skin in enumerate(gltf.data.skins):
- if hasattr(skin, "node_ids"):
BlenderSkin.create_armature_modifiers(gltf, skin_id)
if gltf.data.animations:
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_skin.py b/io_scene_gltf2/blender/imp/gltf2_blender_skin.py
index e8c6170e..2758b348 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_skin.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_skin.py
@@ -145,68 +145,6 @@ class BlenderSkin():
obj.vertex_groups.new(name=gltf.data.nodes[bone].blender_bone_name)
@staticmethod
- def assign_vertex_groups(gltf, skin_id):
- """Assign vertex groups to vertices."""
- pyskin = gltf.data.skins[skin_id]
- for node_id in pyskin.node_ids:
- node = gltf.data.nodes[node_id]
- obj = bpy.data.objects[node.blender_object]
-
- offset = 0
- for prim in gltf.data.meshes[node.mesh].primitives:
- idx_already_done = {}
-
- if 'JOINTS_0' in prim.attributes.keys() and 'WEIGHTS_0' in prim.attributes.keys():
- original_joint_ = BinaryData.get_data_from_accessor(gltf, prim.attributes['JOINTS_0'])
- original_weight_ = BinaryData.get_data_from_accessor(gltf, prim.attributes['WEIGHTS_0'])
-
- tmp_indices = {}
- tmp_idx = 0
- weight_ = []
- for i in prim.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- weight_.append(original_weight_[i[0]])
-
- tmp_indices = {}
- tmp_idx = 0
- joint_ = []
- for i in prim.tmp_indices:
- if i[0] not in tmp_indices.keys():
- tmp_indices[i[0]] = tmp_idx
- tmp_idx += 1
- joint_.append(original_joint_[i[0]])
-
-
- for poly in obj.data.polygons:
- for loop_idx in range(poly.loop_start, poly.loop_start + poly.loop_total):
- vert_idx = obj.data.loops[loop_idx].vertex_index
-
- if vert_idx in idx_already_done.keys():
- continue
- idx_already_done[vert_idx] = True
-
- if vert_idx in range(offset, offset + prim.vertices_length):
-
- tab_index = vert_idx - offset
- cpt = 0
- for joint_idx in joint_[tab_index]:
- weight_val = weight_[tab_index][cpt]
- if weight_val != 0.0: # It can be a problem to assign weights of 0
- # for bone index 0, if there is always 4 indices in joint_
- # tuple
- group = obj.vertex_groups[gltf.data.nodes[
- pyskin.joints[joint_idx]
- ].blender_bone_name]
- group.add([vert_idx], weight_val, 'REPLACE')
- cpt += 1
- else:
- gltf.log.error("No Skinning ?????") # TODO
-
- offset = offset + prim.vertices_length
-
- @staticmethod
def create_armature_modifiers(gltf, skin_id):
"""Create Armature modifier."""
pyskin = gltf.data.skins[skin_id]