diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 3ea1ce11e05a761c9826860013b2d246ce7b1254..2e19cbeb8fd04aa9e6e01ea084881bd82a58ecd3 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, 28), + "version": (1, 3, 29), 'blender': (2, 90, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py index e2d224ce5a05c9f0be56f777b99c38db86ec55d2..5fe719ee3bc2bbcb7e42eaeab78a3edda9d161ff 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py @@ -18,40 +18,22 @@ from mathutils import Vector, Quaternion, Matrix from mathutils.geometry import tessellate_polygon -from operator import attrgetter from . import gltf2_blender_export_keys from ...io.com.gltf2_io_debug import print_console from ...io.com.gltf2_io_color_management import color_srgb_to_scene_linear from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins -# -# Globals -# - -INDICES_ID = 'indices' -MATERIAL_ID = 'material' -ATTRIBUTES_ID = 'attributes' - -COLOR_PREFIX = 'COLOR_' -MORPH_TANGENT_PREFIX = 'MORPH_TANGENT_' -MORPH_NORMAL_PREFIX = 'MORPH_NORMAL_' -MORPH_POSITION_PREFIX = 'MORPH_POSITION_' -TEXCOORD_PREFIX = 'TEXCOORD_' -WEIGHTS_PREFIX = 'WEIGHTS_' -JOINTS_PREFIX = 'JOINTS_' - -TANGENT_ATTRIBUTE = 'TANGENT' -NORMAL_ATTRIBUTE = 'NORMAL' -POSITION_ATTRIBUTE = 'POSITION' - -GLTF_MAX_COLORS = 2 - # # Classes # +class Prim: + def __init__(self): + self.verts = {} + self.indices = [] + class ShapeKey: def __init__(self, shape_key, vertex_normals, polygon_normals): self.shape_key = shape_key @@ -110,17 +92,17 @@ def convert_swizzle_tangent(tan, armature, blender_object, export_settings): if (not armature) or (not blender_object): # Classic case. Mesh is not skined, no need to apply armature transfoms on vertices / normals / tangents if export_settings[gltf2_blender_export_keys.YUP]: - return Vector((tan[0], tan[2], -tan[1], 1.0)) + return Vector((tan[0], tan[2], -tan[1])) else: - return Vector((tan[0], tan[1], tan[2], 1.0)) + return Vector((tan[0], tan[1], tan[2])) else: # Mesh is skined, we have to apply armature transforms on data apply_matrix = armature.matrix_world.inverted() @ blender_object.matrix_world - new_tan = apply_matrix.to_quaternion() @ tan + new_tan = apply_matrix.to_quaternion() @ Vector((tan[0], tan[1], tan[2])) if export_settings[gltf2_blender_export_keys.YUP]: - return Vector((new_tan[0], new_tan[2], -new_tan[1], 1.0)) + return Vector((new_tan[0], new_tan[2], -new_tan[1])) else: - return Vector((new_tan[0], new_tan[1], new_tan[2], 1.0)) + return Vector((new_tan[0], new_tan[1], new_tan[2])) def convert_swizzle_rotation(rot, export_settings): """ @@ -151,173 +133,129 @@ def decompose_transition(matrix, export_settings): def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vertex_groups, modifiers, export_settings): """ Extract primitives from a mesh. Polygons are triangulated and sorted by material. - - Furthermore, primitives are split up, if the indices range is exceeded. - Finally, triangles are also split up/duplicated, if face normals are used instead of vertex normals. + Vertices in multiple faces get split up as necessary. """ print_console('INFO', 'Extracting primitive: ' + blender_mesh.name) - if blender_mesh.has_custom_normals: - # Custom normals are all (0, 0, 0) until calling calc_normals_split() or calc_tangents(). - blender_mesh.calc_normals_split() - - use_tangents = False - if blender_mesh.uv_layers.active and len(blender_mesh.uv_layers) > 0: - try: - blender_mesh.calc_tangents() - use_tangents = True - except Exception: - print_console('WARNING', 'Could not calculate tangents. Please try to triangulate the mesh first.') - # - - material_map = {} - + # First, decide what attributes to gather (eg. how many COLOR_n, etc.) + # Also calculate normals/tangents now if necessary. # - # Gathering position, normal and tex_coords. - # - no_material_attributes = { - POSITION_ATTRIBUTE: [], - NORMAL_ATTRIBUTE: [] - } - - if use_tangents: - no_material_attributes[TANGENT_ATTRIBUTE] = [] - # - # Directory of materials with its primitive. - # - no_material_primitives = { - MATERIAL_ID: 0, - INDICES_ID: [], - ATTRIBUTES_ID: no_material_attributes - } + use_normals = export_settings[gltf2_blender_export_keys.NORMALS] + if use_normals: + if blender_mesh.has_custom_normals: + # Custom normals are all (0, 0, 0) until calling calc_normals_split() or calc_tangents(). + blender_mesh.calc_normals_split() - material_idx_to_primitives = {0: no_material_primitives} - - # - - vertex_index_to_new_indices = {} - - material_map[0] = vertex_index_to_new_indices - - # - # Create primitive for each material. - # - for (mat_idx, _) in enumerate(blender_mesh.materials): - attributes = { - POSITION_ATTRIBUTE: [], - NORMAL_ATTRIBUTE: [] - } - - if use_tangents: - attributes[TANGENT_ATTRIBUTE] = [] - - primitive = { - MATERIAL_ID: mat_idx, - INDICES_ID: [], - ATTRIBUTES_ID: attributes - } - - material_idx_to_primitives[mat_idx] = primitive - - # - - vertex_index_to_new_indices = {} - - material_map[mat_idx] = vertex_index_to_new_indices + use_tangents = False + if use_normals and export_settings[gltf2_blender_export_keys.TANGENTS]: + if blender_mesh.uv_layers.active and len(blender_mesh.uv_layers) > 0: + try: + blender_mesh.calc_tangents() + use_tangents = True + except Exception: + print_console('WARNING', 'Could not calculate tangents. Please try to triangulate the mesh first.') tex_coord_max = 0 - if blender_mesh.uv_layers.active: - tex_coord_max = len(blender_mesh.uv_layers) - - # - - vertex_colors = {} + if export_settings[gltf2_blender_export_keys.TEX_COORDS]: + if blender_mesh.uv_layers.active: + tex_coord_max = len(blender_mesh.uv_layers) - color_index = 0 - for vertex_color in blender_mesh.vertex_colors: - vertex_color_name = COLOR_PREFIX + str(color_index) - vertex_colors[vertex_color_name] = vertex_color + color_max = 0 + if export_settings[gltf2_blender_export_keys.COLORS]: + color_max = len(blender_mesh.vertex_colors) - color_index += 1 - if color_index >= GLTF_MAX_COLORS: - break - color_max = color_index - - # - - bone_max = 0 - for blender_polygon in blender_mesh.polygons: - for loop_index in blender_polygon.loop_indices: - vertex_index = blender_mesh.loops[loop_index].vertex_index - bones_count = len(blender_mesh.vertices[vertex_index].groups) - if bones_count > 0: - if bones_count % 4 == 0: - bones_count -= 1 - bone_max = max(bone_max, bones_count // 4 + 1) - - # - - morph_max = 0 - - blender_shape_keys = [] - - if blender_mesh.shape_keys is not None: + bone_max = 0 # number of JOINTS_n sets needed (1 set = 4 influences) + armature = None + if blender_vertex_groups and export_settings[gltf2_blender_export_keys.SKINS]: + if modifiers is not None: + modifiers_dict = {m.type: m for m in modifiers} + if "ARMATURE" in modifiers_dict: + modifier = modifiers_dict["ARMATURE"] + armature = modifier.object + + # Skin must be ignored if the object is parented to a bone of the armature + # (This creates an infinite recursive error) + # So ignoring skin in that case + is_child_of_arma = ( + armature and + blender_object and + blender_object.parent_type == "BONE" and + blender_object.parent.name == armature.name + ) + if is_child_of_arma: + armature = None + + if armature: + skin = gltf2_blender_gather_skins.gather_skin(armature, export_settings) + if not skin: + armature = None + else: + joint_name_to_index = {joint.name: index for index, joint in enumerate(skin.joints)} + group_to_joint = [joint_name_to_index.get(g.name) for g in blender_vertex_groups] + + # Find out max number of bone influences + for blender_polygon in blender_mesh.polygons: + for loop_index in blender_polygon.loop_indices: + vertex_index = blender_mesh.loops[loop_index].vertex_index + groups_count = len(blender_mesh.vertices[vertex_index].groups) + bones_count = (groups_count + 3) // 4 + bone_max = max(bone_max, bones_count) + + use_morph_normals = use_normals and export_settings[gltf2_blender_export_keys.MORPH_NORMAL] + use_morph_tangents = use_morph_normals and use_tangents and export_settings[gltf2_blender_export_keys.MORPH_TANGENT] + + shape_keys = [] + if blender_mesh.shape_keys and export_settings[gltf2_blender_export_keys.MORPH]: for blender_shape_key in blender_mesh.shape_keys.key_blocks: - if blender_shape_key != blender_shape_key.relative_key: - if blender_shape_key.mute is False: - morph_max += 1 - blender_shape_keys.append(ShapeKey( - blender_shape_key, - blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key - blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key - + if blender_shape_key == blender_shape_key.relative_key or blender_shape_key.mute: + continue + if use_morph_normals: + vertex_normals = blender_shape_key.normals_vertex_get() + polygon_normals = blender_shape_key.normals_polygon_get() + else: + vertex_normals = None + polygon_normals = None + shape_keys.append(ShapeKey( + blender_shape_key, + vertex_normals, + polygon_normals, + )) - armature = None - if modifiers is not None: - modifiers_dict = {m.type: m for m in modifiers} - if "ARMATURE" in modifiers_dict: - modifier = modifiers_dict["ARMATURE"] - armature = modifier.object + use_materials = export_settings[gltf2_blender_export_keys.MATERIALS] # - # Convert polygon to primitive indices and eliminate invalid ones. Assign to material. + # Gather the verts and indices for each primitive. # - for blender_polygon in blender_mesh.polygons: - export_color = True - # + prims = {} - if export_settings['gltf_materials'] is False: - primitive = material_idx_to_primitives[0] - vertex_index_to_new_indices = material_map[0] - elif not blender_polygon.material_index in material_idx_to_primitives: - primitive = material_idx_to_primitives[0] - vertex_index_to_new_indices = material_map[0] - else: - primitive = material_idx_to_primitives[blender_polygon.material_index] - vertex_index_to_new_indices = material_map[blender_polygon.material_index] - # - - attributes = primitive[ATTRIBUTES_ID] - - face_normal = blender_polygon.normal - face_tangent = Vector((0.0, 0.0, 0.0)) - face_bitangent = Vector((0.0, 0.0, 0.0)) - if use_tangents: - for loop_index in blender_polygon.loop_indices: - temp_vertex = blender_mesh.loops[loop_index] - face_tangent += temp_vertex.tangent - face_bitangent += temp_vertex.bitangent - - face_tangent.normalize() - face_bitangent.normalize() - - # - - indices = primitive[INDICES_ID] + for blender_polygon in blender_mesh.polygons: + material_idx = -1 + if use_materials: + material_idx = blender_polygon.material_index + + prim = prims.get(material_idx) + if not prim: + prim = Prim() + prims[material_idx] = prim + + if use_normals: + face_normal = None + if not (blender_polygon.use_smooth or blender_mesh.use_auto_smooth): + # Calc face normal/tangents + face_normal = blender_polygon.normal + if use_tangents: + face_tangent = Vector((0.0, 0.0, 0.0)) + face_bitangent = Vector((0.0, 0.0, 0.0)) + for loop_index in blender_polygon.loop_indices: + loop = blender_mesh.loops[loop_index] + face_tangent += loop.tangent + face_bitangent += loop.bitangent + face_tangent.normalize() + face_bitangent.normalize() loop_index_list = [] @@ -335,7 +273,6 @@ def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vert triangles = tessellate_polygon((polyline,)) for triangle in triangles: - for triangle_index in triangle: loop_index_list.append(blender_polygon.loop_indices[triangle_index]) else: @@ -343,366 +280,200 @@ def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vert for loop_index in loop_index_list: vertex_index = blender_mesh.loops[loop_index].vertex_index + vertex = blender_mesh.vertices[vertex_index] - if vertex_index_to_new_indices.get(vertex_index) is None: - vertex_index_to_new_indices[vertex_index] = [] - - # - - v = None - n = None - t = None - b = None - uvs = [] - colors = [] - joints = [] - weights = [] - - target_positions = [] - target_normals = [] - target_tangents = [] + # vert will be a tuple of all the vertex attributes. + # Used as cache key in prim.verts. + vert = (vertex_index,) - vertex = blender_mesh.vertices[vertex_index] + v = vertex.co + vert += ((v[0], v[1], v[2]),) - v = convert_swizzle_location(vertex.co, armature, blender_object, export_settings) - if blender_polygon.use_smooth or blender_mesh.use_auto_smooth: - if blender_mesh.has_custom_normals: - n = convert_swizzle_normal(blender_mesh.loops[loop_index].normal, armature, blender_object, export_settings) + if use_normals: + if face_normal is None: + if blender_mesh.has_custom_normals: + n = blender_mesh.loops[loop_index].normal + else: + n = vertex.normal + if use_tangents: + t = blender_mesh.loops[loop_index].tangent + b = blender_mesh.loops[loop_index].bitangent else: - n = convert_swizzle_normal(vertex.normal, armature, blender_object, export_settings) - if use_tangents: - t = convert_swizzle_tangent(blender_mesh.loops[loop_index].tangent, armature, blender_object, export_settings) - b = convert_swizzle_location(blender_mesh.loops[loop_index].bitangent, armature, blender_object, export_settings) - else: - n = convert_swizzle_normal(face_normal, armature, blender_object, export_settings) + n = face_normal + if use_tangents: + t = face_tangent + b = face_bitangent + vert += ((n[0], n[1], n[2]),) if use_tangents: - t = convert_swizzle_tangent(face_tangent, armature, blender_object, export_settings) - b = convert_swizzle_location(face_bitangent, armature, blender_object, export_settings) - - if use_tangents: - tv = Vector((t[0], t[1], t[2])) - bv = Vector((b[0], b[1], b[2])) - nv = Vector((n[0], n[1], n[2])) - - if (nv.cross(tv)).dot(bv) < 0.0: - t[3] = -1.0 - - if blender_mesh.uv_layers.active: - for tex_coord_index in range(0, tex_coord_max): - uv = blender_mesh.uv_layers[tex_coord_index].data[loop_index].uv - uvs.append([uv.x, 1.0 - uv.y]) - - # - - if color_max > 0 and export_color: - for color_index in range(0, color_max): - color_name = COLOR_PREFIX + str(color_index) - color = vertex_colors[color_name].data[loop_index].color - colors.append([ - color_srgb_to_scene_linear(color[0]), - color_srgb_to_scene_linear(color[1]), - color_srgb_to_scene_linear(color[2]), - color[3] - ]) - - # - - bone_count = 0 - - # Skin must be ignored if the object is parented to a bone of the armature - # (This creates an infinite recursive error) - # So ignoring skin in that case - if blender_object and blender_object.parent_type == "BONE" and blender_object.parent.name == armature.name: - bone_max = 0 # joints & weights will be ignored in following code - else: - # Manage joints & weights - if blender_vertex_groups is not None and vertex.groups is not None and len(vertex.groups) > 0 and export_settings[gltf2_blender_export_keys.SKINS]: - joint = [] - weight = [] - vertex_groups = vertex.groups - if not export_settings['gltf_all_vertex_influences']: - # sort groups by weight descending - vertex_groups = sorted(vertex.groups, key=attrgetter('weight'), reverse=True) - for group_element in vertex_groups: - - if len(joint) == 4: - bone_count += 1 - joints.append(joint) - weights.append(weight) - joint = [] - weight = [] - - # - - joint_weight = group_element.weight - if joint_weight <= 0.0: + vert += ((t[0], t[1], t[2]),) + vert += ((b[0], b[1], b[2]),) + # TODO: store just bitangent_sign in vert, not whole bitangent? + + for tex_coord_index in range(0, tex_coord_max): + uv = blender_mesh.uv_layers[tex_coord_index].data[loop_index].uv + uv = (uv.x, 1.0 - uv.y) + vert += (uv,) + + for color_index in range(0, color_max): + color = blender_mesh.vertex_colors[color_index].data[loop_index].color + col = ( + color_srgb_to_scene_linear(color[0]), + color_srgb_to_scene_linear(color[1]), + color_srgb_to_scene_linear(color[2]), + color[3], + ) + vert += (col,) + + if bone_max: + bones = [] + if vertex.groups: + for group_element in vertex.groups: + weight = group_element.weight + if weight <= 0.0: continue - - # - - vertex_group_index = group_element.group - - if vertex_group_index < 0 or vertex_group_index >= len(blender_vertex_groups): + try: + joint = group_to_joint[group_element.group] + except Exception: continue - vertex_group_name = blender_vertex_groups[vertex_group_index].name - - joint_index = None - - if armature: - skin = gltf2_blender_gather_skins.gather_skin(armature, export_settings) - for index, j in enumerate(skin.joints): - if j.name == vertex_group_name: - joint_index = index - break - - # - if joint_index is not None: - joint.append(joint_index) - weight.append(joint_weight) - - if len(joint) > 0: - bone_count += 1 - - for fill in range(0, 4 - len(joint)): - joint.append(0) - weight.append(0.0) - - joints.append(joint) - weights.append(weight) - - for fill in range(0, bone_max - bone_count): - joints.append([0, 0, 0, 0]) - weights.append([0.0, 0.0, 0.0, 0.0]) - - # - - if morph_max > 0 and export_settings[gltf2_blender_export_keys.MORPH]: - for morph_index in range(0, morph_max): - blender_shape_key = blender_shape_keys[morph_index] - - v_morph = convert_swizzle_location(blender_shape_key.shape_key.data[vertex_index].co, - armature, blender_object, - export_settings) - - # Store delta. - v_morph -= v - - target_positions.append(v_morph) - - # + if joint is None: + continue + bones.append((joint, weight)) + bones.sort(key=lambda x: x[1], reverse=True) + bones = tuple(bones) + vert += (bones,) - n_morph = None + for shape_key in shape_keys: + v_morph = shape_key.shape_key.data[vertex_index].co + v_morph = v_morph - v # store delta + vert += ((v_morph[0], v_morph[1], v_morph[2]),) + if use_morph_normals: if blender_polygon.use_smooth: - temp_normals = blender_shape_key.vertex_normals - n_morph = (temp_normals[vertex_index * 3 + 0], temp_normals[vertex_index * 3 + 1], - temp_normals[vertex_index * 3 + 2]) + normals = shape_key.vertex_normals + n_morph = Vector(( + normals[vertex_index * 3 + 0], + normals[vertex_index * 3 + 1], + normals[vertex_index * 3 + 2], + )) else: - temp_normals = blender_shape_key.polygon_normals - n_morph = ( - temp_normals[blender_polygon.index * 3 + 0], temp_normals[blender_polygon.index * 3 + 1], - temp_normals[blender_polygon.index * 3 + 2]) - - n_morph = convert_swizzle_normal(Vector(n_morph), armature, blender_object, export_settings) - - # Store delta. - n_morph -= n - - target_normals.append(n_morph) - - # - - if use_tangents: - rotation = n_morph.rotation_difference(n) - - t_morph = Vector((t[0], t[1], t[2])) + normals = shape_key.polygon_normals + n_morph = Vector(( + normals[blender_polygon.index * 3 + 0], + normals[blender_polygon.index * 3 + 1], + normals[blender_polygon.index * 3 + 2], + )) + n_morph = n_morph - n # store delta + vert += ((n_morph[0], n_morph[1], n_morph[2]),) + + vert_idx = prim.verts.setdefault(vert, len(prim.verts)) + prim.indices.append(vert_idx) - t_morph.rotate(rotation) - - target_tangents.append(t_morph) - - # - # - - create = True + # + # Put the verts into attribute arrays. + # - for current_new_index in vertex_index_to_new_indices[vertex_index]: - found = True + result_primitives = [] - for i in range(0, 3): - if attributes[POSITION_ATTRIBUTE][current_new_index * 3 + i] != v[i]: - found = False - break + for material_idx, prim in prims.items(): + if not prim.indices: + continue - if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 + i] != n[i]: - found = False - break + vs = [] + ns = [] + ts = [] + uvs = [[] for _ in range(tex_coord_max)] + cols = [[] for _ in range(color_max)] + joints = [[] for _ in range(bone_max)] + weights = [[] for _ in range(bone_max)] + vs_morph = [[] for _ in shape_keys] + ns_morph = [[] for _ in shape_keys] + ts_morph = [[] for _ in shape_keys] + + for vert in prim.verts.keys(): + i = 0 + + i += 1 # skip over Blender mesh index + + v = vert[i] + i += 1 + v = convert_swizzle_location(v, armature, blender_object, export_settings) + vs.extend(v) + + if use_normals: + n = vert[i] + i += 1 + n = convert_swizzle_normal(n, armature, blender_object, export_settings) + ns.extend(n) if use_tangents: - for i in range(0, 4): - if attributes[TANGENT_ATTRIBUTE][current_new_index * 4 + i] != t[i]: - found = False - break - - if not found: - continue - - for tex_coord_index in range(0, tex_coord_max): - uv = uvs[tex_coord_index] - - tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index) - for i in range(0, 2): - if attributes[tex_coord_id][current_new_index * 2 + i] != uv[i]: - found = False - break - - if export_color: - for color_index in range(0, color_max): - color = colors[color_index] - - color_id = COLOR_PREFIX + str(color_index) - for i in range(0, 3): - # Alpha is always 1.0 - see above. - current_color = attributes[color_id][current_new_index * 4 + i] - if color_srgb_to_scene_linear(current_color) != color[i]: - found = False - break - - if export_settings[gltf2_blender_export_keys.SKINS]: - for bone_index in range(0, bone_max): - joint = joints[bone_index] - weight = weights[bone_index] - - joint_id = JOINTS_PREFIX + str(bone_index) - weight_id = WEIGHTS_PREFIX + str(bone_index) - for i in range(0, 4): - if attributes[joint_id][current_new_index * 4 + i] != joint[i]: - found = False - break - if attributes[weight_id][current_new_index * 4 + i] != weight[i]: - found = False - break - - if export_settings[gltf2_blender_export_keys.MORPH]: - for morph_index in range(0, morph_max): - target_position = target_positions[morph_index] - target_normal = target_normals[morph_index] - if use_tangents: - target_tangent = target_tangents[morph_index] - - target_position_id = MORPH_POSITION_PREFIX + str(morph_index) - target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index) - target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index) - for i in range(0, 3): - if attributes[target_position_id][current_new_index * 3 + i] != target_position[i]: - found = False - break - if attributes[target_normal_id][current_new_index * 3 + i] != target_normal[i]: - found = False - break - if use_tangents: - if attributes[target_tangent_id][current_new_index * 3 + i] != target_tangent[i]: - found = False - break - - if found: - indices.append(current_new_index) - - create = False - break - - if not create: - continue - - new_index = 0 - - if primitive.get('max_index') is not None: - new_index = primitive['max_index'] + 1 - - primitive['max_index'] = new_index - - vertex_index_to_new_indices[vertex_index].append(new_index) - - # - # - - indices.append(new_index) - - # - - attributes[POSITION_ATTRIBUTE].extend(v) - attributes[NORMAL_ATTRIBUTE].extend(n) - if use_tangents: - attributes[TANGENT_ATTRIBUTE].extend(t) - - if blender_mesh.uv_layers.active: - for tex_coord_index in range(0, tex_coord_max): - tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index) - - if attributes.get(tex_coord_id) is None: - attributes[tex_coord_id] = [] - - attributes[tex_coord_id].extend(uvs[tex_coord_index]) - - if export_color: - for color_index in range(0, color_max): - color_id = COLOR_PREFIX + str(color_index) - - if attributes.get(color_id) is None: - attributes[color_id] = [] - - attributes[color_id].extend(colors[color_index]) - - if export_settings[gltf2_blender_export_keys.SKINS]: - for bone_index in range(0, bone_max): - joint_id = JOINTS_PREFIX + str(bone_index) - - if attributes.get(joint_id) is None: - attributes[joint_id] = [] - - attributes[joint_id].extend(joints[bone_index]) - - weight_id = WEIGHTS_PREFIX + str(bone_index) - - if attributes.get(weight_id) is None: - attributes[weight_id] = [] - - attributes[weight_id].extend(weights[bone_index]) - - if export_settings[gltf2_blender_export_keys.MORPH]: - for morph_index in range(0, morph_max): - target_position_id = MORPH_POSITION_PREFIX + str(morph_index) - - if attributes.get(target_position_id) is None: - attributes[target_position_id] = [] - - attributes[target_position_id].extend(target_positions[morph_index]) - - target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index) - - if attributes.get(target_normal_id) is None: - attributes[target_normal_id] = [] - - attributes[target_normal_id].extend(target_normals[morph_index]) - - if use_tangents: - target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index) - - if attributes.get(target_tangent_id) is None: - attributes[target_tangent_id] = [] - - attributes[target_tangent_id].extend(target_tangents[morph_index]) - - # - # Add non-empty primitives - # - - result_primitives = [ - primitive - for primitive in material_idx_to_primitives.values() - if len(primitive[INDICES_ID]) != 0 - ] - - print_console('INFO', 'Primitives created: ' + str(len(result_primitives))) + t = vert[i] + i += 1 + t = convert_swizzle_tangent(t, armature, blender_object, export_settings) + ts.extend(t) + + b = vert[i] + i += 1 + b = convert_swizzle_tangent(b, armature, blender_object, export_settings) + b_sign = -1.0 if (Vector(n).cross(Vector(t))).dot(Vector(b)) < 0.0 else 1.0 + ts.append(b_sign) + + for tex_coord_index in range(0, tex_coord_max): + uv = vert[i] + i += 1 + uvs[tex_coord_index].extend(uv) + + for color_index in range(0, color_max): + col = vert[i] + i += 1 + cols[color_index].extend(col) + + if bone_max: + bones = vert[i] + i += 1 + for j in range(0, 4 * bone_max): + if j < len(bones): + joint, weight = bones[j] + else: + joint, weight = 0, 0.0 + joints[j//4].append(joint) + weights[j//4].append(weight) + + for shape_key_index in range(0, len(shape_keys)): + v_morph = vert[i] + i += 1 + v_morph = convert_swizzle_location(v_morph, armature, blender_object, export_settings) + vs_morph[shape_key_index].extend(v_morph) + + if use_morph_normals: + n_morph = vert[i] + i += 1 + n_morph = convert_swizzle_normal(n_morph, armature, blender_object, export_settings) + ns_morph[shape_key_index].extend(n_morph) + + if use_morph_tangents: + rotation = n_morph.rotation_difference(n) + t_morph = Vector(t) + t_morph.rotate(rotation) + ts_morph[shape_key_index].extend(t_morph) + + attributes = {} + attributes['POSITION'] = vs + if ns: attributes['NORMAL'] = ns + if ts: attributes['TANGENT'] = ts + for i, uv in enumerate(uvs): attributes['TEXCOORD_%d' % i] = uv + for i, col in enumerate(cols): attributes['COLOR_%d' % i] = col + for i, js in enumerate(joints): attributes['JOINTS_%d' % i] = js + for i, ws in enumerate(weights): attributes['WEIGHTS_%d' % i] = ws + for i, vm in enumerate(vs_morph): attributes['MORPH_POSITION_%d' % i] = vm + for i, nm in enumerate(ns_morph): attributes['MORPH_NORMAL_%d' % i] = nm + for i, tm in enumerate(ts_morph): attributes['MORPH_TANGENT_%d' % i] = tm + + result_primitives.append({ + 'attributes': attributes, + 'indices': prim.indices, + 'material': material_idx, + }) + + print_console('INFO', 'Primitives created: %d' % len(result_primitives)) return result_primitives diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_pbrSpecularGlossiness.py b/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_pbrSpecularGlossiness.py index ce5e1aed0c87372fbbd2051bc2417288898ffec7..bb1bf2722505b8b3ab2e7526fea2a3f8f9d10cdc 100755 --- a/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_pbrSpecularGlossiness.py +++ b/io_scene_gltf2/blender/imp/gltf2_blender_KHR_materials_pbrSpecularGlossiness.py @@ -79,7 +79,8 @@ def pbr_specular_glossiness(mh): ) if mh.pymat.occlusion_texture is not None: - node = make_settings_node(mh, location=(610, -1060)) + node = make_settings_node(mh) + node.location = (610, -1060) occlusion( mh, location=(510, -970),