From 06bb353c848921a3f68f928aea154d471555e2dc Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Thu, 26 Sep 2019 16:35:44 +0200 Subject: glTF importer: big perf improvement --- .../blender/imp/gltf2_blender_animation_weight.py | 11 +- io_scene_gltf2/blender/imp/gltf2_blender_gltf.py | 31 +- io_scene_gltf2/blender/imp/gltf2_blender_mesh.py | 285 +++++++---------- .../blender/imp/gltf2_blender_primitive.py | 348 +++++++++++---------- io_scene_gltf2/blender/imp/gltf2_blender_scene.py | 4 - io_scene_gltf2/blender/imp/gltf2_blender_skin.py | 62 ---- 6 files changed, 341 insertions(+), 400 deletions(-) (limited to 'io_scene_gltf2/blender/imp') 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 @@ -85,10 +85,6 @@ class BlenderScene(): if hasattr(skin, "node_ids"): BlenderSkin.create_vertex_groups(gltf, skin_id) - 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) 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 @@ -144,68 +144,6 @@ class BlenderSkin(): for bone in pyskin.joints: 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.""" -- cgit v1.2.3