コード例 #1
0
ファイル: geo.py プロジェクト: paulmotey/Blended-Cities
def fill(vertlist, offset=0, normals=True):
    if normals:
        vertlist.reverse()
    faces = geometry.tessellate_polygon([vertlist])
    if offset != 0:
        for i, f in enumerate(faces):
            faces[i] = (f[0] + offset, f[1] + offset, f[2] + offset)
    return faces
コード例 #2
0
ファイル: vabmesh.py プロジェクト: Italic-/blenderpython
 def from_faces(cls, faces):
     """BMFaceのリストからLoopTrisを生成する。"""
     looptris_tmp = []
     for face in faces:
         loops = face.loops
         # tri_indices = geom.tessellation([loop.vert.co for loop in loops])
         # geom.tessellationのパッチを消したので
         tri_indices = geom.tessellate_polygon(
             [[loop.vert.co for loop in loops]])
         tris = [tuple([loops[i] for i in i3]) for i3 in tri_indices]
         looptris_tmp.extend(tris)
     return cls(looptris_tmp, True)
コード例 #3
0
ファイル: looptris.py プロジェクト: Italic-/blenderpython
    def tessellate(cls, polyline, correct=False):
        """三角形に分割する
        :param polyline: BMLoopかVectorのリスト
        :param correct: ほぼ直線になっている三点に貼られている面を置換する。
        :return: ソート済みのインデックスの二次元リストを返す。
        :rtype: list[(int, int, int)]
        """
        if not polyline or len(polyline) < 3:
            return

        is_loop = isinstance(polyline[0], bmesh.types.BMLoop)

        if len(polyline) == 3:
            tri_indices = [(0, 1, 2)]
        elif len(polyline) == 4:
            if is_loop:
                # 元の面が4頂点だと、歪みが大きくても分割してくれない
                # 1-3で分割した場合 (0, 1, 3), (1, 2, 3)
                d1 = polyline[0].vert.normal.dot(polyline[2].vert.normal)
                # 0-2で分割した場合 (0, 1, 2), (0, 2, 3)
                d2 = polyline[1].vert.normal.dot(polyline[3].vert.normal)
                # 法線の差が大きい方を採用する
                if d1 < d2:
                    tri_indices = [(0, 1, 3), (1, 2, 3)]
                else:
                    tri_indices = [(0, 1, 2), (0, 2, 3)]
            else:
                v1, v2, v3, v4 = polyline
                if (v2 - v4).length < (v1 - v3).length:
                    tri_indices = [(0, 1, 3), (1, 2, 3)]
                else:
                    tri_indices = [(0, 1, 2), (0, 2, 3)]
        else:
            if is_loop:
                seq = [[loop.vert.co for loop in polyline]]
            else:
                seq = [polyline]
            # geom.tessellate_polygon()は 2D list を要求する。
            tri_indices = geom.tessellate_polygon(seq)  # これの精度は不明
            # 順番が無茶苦茶になっているのでソートする
            tri_indices = [tuple(sorted(tri)) for tri in tri_indices]
            tri_indices.sort(key=lambda tri: tri[0])

        if correct:
            tri_indices = cls.correct_tessellate(polyline, tri_indices, True)

        return tri_indices
コード例 #4
0
def drawCurve(curve, resolution, size, offset):
    # segments = getSegments(curve.data.splines[0])

    polylines = []
    for spl in curve.data.splines:
        segments = getSegments(spl)
        print("Segments:\n", segments)
        polylines.append(segmentsToPolyline(segments, 6, 100))
    print("=" * 80, "\n", polylines)
    chainedPolyLines = []
    for i in polylines:
        for j in i:
            chainedPolyLines.append(j)

    tess = tessellate_polygon(polylines)

    bgl.glBegin(bgl.GL_TRIANGLES)
    for i in tess:
        bgl.glVertex2f(chainedPolyLines[i[0]][0] * size + offset[0], chainedPolyLines[i[0]][1] * size + offset[1])
        bgl.glVertex2f(chainedPolyLines[i[1]][0] * size + offset[0], chainedPolyLines[i[1]][1] * size + offset[1])
        bgl.glVertex2f(chainedPolyLines[i[2]][0] * size + offset[0], chainedPolyLines[i[2]][1] * size + offset[1])
    bgl.glEnd()

    """
コード例 #5
0
ファイル: mesh_utils.py プロジェクト: ubuntunux/Blender
def ngon_tessellate(from_data, indices, fix_loops=True):
    """
    Takes a polyline of indices (fgon) and returns a list of face
    indicie lists. Designed to be used for importers that need indices for an
    fgon to create from existing verts.

    from_data: either a mesh, or a list/tuple of vectors.
    indices: a list of indices to use this list is the ordered closed polyline
       to fill, and can be a subset of the data given.
    fix_loops: If this is enabled polylines that use loops to make multiple
       polylines are delt with correctly.
    """

    from mathutils.geometry import tessellate_polygon
    from mathutils import Vector
    vector_to_tuple = Vector.to_tuple

    if not indices:
        return []

    def mlen(co):
        # manhatten length of a vector, faster then length
        return abs(co[0]) + abs(co[1]) + abs(co[2])

    def vert_treplet(v, i):
        return v, vector_to_tuple(v, 6), i, mlen(v)

    def ed_key_mlen(v1, v2):
        if v1[3] > v2[3]:
            return v2[1], v1[1]
        else:
            return v1[1], v2[1]

    if not fix_loops:
        """
        Normal single concave loop filling
        """
        if type(from_data) in {tuple, list}:
            verts = [Vector(from_data[i]) for ii, i in enumerate(indices)]
        else:
            verts = [from_data.vertices[i].co for ii, i in enumerate(indices)]

        # same as reversed(range(1, len(verts))):
        for i in range(len(verts) - 1, 0, -1):
            if verts[i][1] == verts[i - 1][0]:
                verts.pop(i - 1)

        fill = tessellate_polygon([verts])

    else:
        """
        Seperate this loop into multiple loops be finding edges that are
        used twice. This is used by lightwave LWO files a lot
        """

        if type(from_data) in {tuple, list}:
            verts = [vert_treplet(Vector(from_data[i]), ii)
                     for ii, i in enumerate(indices)]
        else:
            verts = [vert_treplet(from_data.vertices[i].co, ii)
                     for ii, i in enumerate(indices)]

        edges = [(i, i - 1) for i in range(len(verts))]
        if edges:
            edges[0] = (0, len(verts) - 1)

        if not verts:
            return []

        edges_used = set()
        edges_doubles = set()
        # We need to check if any edges are used twice location based.
        for ed in edges:
            edkey = ed_key_mlen(verts[ed[0]], verts[ed[1]])
            if edkey in edges_used:
                edges_doubles.add(edkey)
            else:
                edges_used.add(edkey)

        # Store a list of unconnected loop segments split by double edges.
        # will join later
        loop_segments = []

        v_prev = verts[0]
        context_loop = [v_prev]
        loop_segments = [context_loop]

        for v in verts:
            if v != v_prev:
                # Are we crossing an edge we removed?
                if ed_key_mlen(v, v_prev) in edges_doubles:
                    context_loop = [v]
                    loop_segments.append(context_loop)
                else:
                    if context_loop and context_loop[-1][1] == v[1]:
                        #raise "as"
                        pass
                    else:
                        context_loop.append(v)

                v_prev = v
        # Now join loop segments

        def join_seg(s1, s2):
            if s2[-1][1] == s1[0][1]:
                s1, s2 = s2, s1
            elif s1[-1][1] == s2[0][1]:
                pass
            else:
                return False

            # If were stuill here s1 and s2 are 2 segments in the same polyline
            s1.pop()  # remove the last vert from s1
            s1.extend(s2)  # add segment 2 to segment 1

            if s1[0][1] == s1[-1][1]:  # remove endpoints double
                s1.pop()

            del s2[:]  # Empty this segment s2 so we don't use it again.
            return True

        joining_segments = True
        while joining_segments:
            joining_segments = False
            segcount = len(loop_segments)

            for j in range(segcount - 1, -1, -1):  # reversed(range(segcount)):
                seg_j = loop_segments[j]
                if seg_j:
                    for k in range(j - 1, -1, -1):  # reversed(range(j)):
                        if not seg_j:
                            break
                        seg_k = loop_segments[k]

                        if seg_k and join_seg(seg_j, seg_k):
                            joining_segments = True

        loop_list = loop_segments

        for verts in loop_list:
            while verts and verts[0][1] == verts[-1][1]:
                verts.pop()

        loop_list = [verts for verts in loop_list if len(verts) > 2]
        # DONE DEALING WITH LOOP FIXING

        # vert mapping
        vert_map = [None] * len(indices)
        ii = 0
        for verts in loop_list:
            if len(verts) > 2:
                for i, vert in enumerate(verts):
                    vert_map[i + ii] = vert[2]
                ii += len(verts)

        fill = tessellate_polygon([[v[0] for v in loop] for loop in loop_list])
        #draw_loops(loop_list)
        #raise Exception("done loop")
        # map to original indices
        fill = [[vert_map[i] for i in reversed(f)] for f in fill]

    if not fill:
        print('Warning Cannot scanfill, fallback on a triangle fan.')
        fill = [[0, i - 1, i] for i in range(2, len(indices))]
    else:
        # Use real scanfill.
        # See if its flipped the wrong way.
        flip = None
        for fi in fill:
            if flip is not None:
                break
            for i, vi in enumerate(fi):
                if vi == 0 and fi[i - 1] == 1:
                    flip = False
                    break
                elif vi == 1 and fi[i - 1] == 0:
                    flip = True
                    break

        if not flip:
            for i, fi in enumerate(fill):
                fill[i] = tuple([ii for ii in reversed(fi)])

    return fill
コード例 #6
0
 def tesselateVecs(self, vecs):
     return (tuple(reversed(t)) for t in tessellate_polygon( [[v for v in vecs]] ) )
コード例 #7
0
 def tesselatePoly(self, vecs, poly):
     return (tuple(poly[i] for i in t)
             for t in tessellate_polygon([[vecs[v] for v in poly]]))
コード例 #8
0
ファイル: vabmesh.py プロジェクト: Italic-/blenderpython
    def correct_vectors(cls, vecs):
        """
        要パッチ
        vecs: 単一面の外周を構成するベクトルのリスト。
        """

        # tesstris = geom.tessellation(vecs)
        tesstris = geom.tessellate_polygon([vecs])

        if len(vecs) <= 3:
            return tesstris

        tesstris = list(tesstris)

        removed_tris = set()
        new_tris = []
        corrected_num = 0
        for tri in tesstris:
            if tri in removed_tris:
                continue
            i1, i2, i3 = tri

            # v3 <- v2 <- v1
            if i1 + 1 == i2 and i2 + 1 == i3:
                v1, v2, v3 = vecs[i1], vecs[i2], vecs[i3]
            elif i2 + 1 == i3 and i3 + 1 == i1:
                v1, v2, v3 = vecs[i2], vecs[i3], vecs[i1]
            elif i3 + 1 == i1 and i1 + 1 == i2:
                v1, v2, v3 = vecs[i3], vecs[i1], vecs[i2]
            else:
                continue
            vec1 = v1 - v2
            vec2 = v3 - v2
            angle = vec1.angle(vec2, 0.0)
            if angle >= cls.CORRECT_ANGLE_THRESHOLD:
                # i1とi3を持つ面を探す
                for link_tri in tesstris:
                    if link_tri != tri:
                        if i1 in link_tri and i3 in link_tri:
                            break
                else:
                    link_tri = None
                if link_tri:
                    i4 = link_tri[link_tri.index(i1) - 1]
                    vec3 = vecs[i4] - v2
                    if vec3.length > cls.CORRECT_DIST_THRESHOLD:
                        tri1 = (i1, i2, i4)
                        tri2 = (i2, i3, i4)
                        new_tris.extend((tri1, tri2))
                        removed_tris.add(tri)
                        removed_tris.add(link_tri)
                        corrected_num += 1

        for tri in removed_tris:
            tesstris.remove(tri)
        for tri in new_tris:
            tesstris.append(tri)

        # print('Corrected {0} faces.'.format(corrected_num))

        return tesstris
コード例 #9
0
def extract_primitives(glTF, blender_mesh, 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.
    """
    print_console('INFO', 'Extracting primitive: ' + blender_mesh.name)

    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 = {}

    #
    # 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: '',
        INDICES_ID: [],
        ATTRIBUTES_ID: no_material_attributes
    }

    material_name_to_primitives = {'': no_material_primitives}

    #

    vertex_index_to_new_indices = {}

    material_map[''] = vertex_index_to_new_indices

    #
    # Create primitive for each material.
    #
    for blender_material in blender_mesh.materials:
        if blender_material is None:
            continue

        attributes = {POSITION_ATTRIBUTE: [], NORMAL_ATTRIBUTE: []}

        if use_tangents:
            attributes[TANGENT_ATTRIBUTE] = []

        primitive = {
            MATERIAL_ID: blender_material.name,
            INDICES_ID: [],
            ATTRIBUTES_ID: attributes
        }

        material_name_to_primitives[blender_material.name] = primitive

        #

        vertex_index_to_new_indices = {}

        material_map[blender_material.name] = vertex_index_to_new_indices

    tex_coord_max = 0
    if blender_mesh.uv_layers.active:
        tex_coord_max = len(blender_mesh.uv_layers)

    #

    vertex_colors = {}

    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_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:
        morph_max = len(blender_mesh.shape_keys.key_blocks) - 1

        for blender_shape_key in blender_mesh.shape_keys.key_blocks:
            if blender_shape_key != blender_shape_key.relative_key:
                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

    #
    # Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
    #
    for blender_polygon in blender_mesh.polygons:
        export_color = True

        #

        if blender_polygon.material_index < 0 or blender_polygon.material_index >= len(blender_mesh.materials) or \
                blender_mesh.materials[blender_polygon.material_index] is None:
            primitive = material_name_to_primitives['']
            vertex_index_to_new_indices = material_map['']
        else:
            primitive = material_name_to_primitives[blender_mesh.materials[
                blender_polygon.material_index].name]
            vertex_index_to_new_indices = material_map[blender_mesh.materials[
                blender_polygon.material_index].name]
        #

        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]

        loop_index_list = []

        if len(blender_polygon.loop_indices) == 3:
            loop_index_list.extend(blender_polygon.loop_indices)
        elif len(blender_polygon.loop_indices) > 3:
            # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
            polyline = []

            for loop_index in blender_polygon.loop_indices:
                vertex_index = blender_mesh.loops[loop_index].vertex_index
                v = blender_mesh.vertices[vertex_index].co
                polyline.append(Vector((v[0], v[1], v[2])))

            triangles = tessellate_polygon((polyline, ))

            for triangle in triangles:
                loop_index_list.append(
                    blender_polygon.loop_indices[triangle[0]])
                loop_index_list.append(
                    blender_polygon.loop_indices[triangle[2]])
                loop_index_list.append(
                    blender_polygon.loop_indices[triangle[1]])
        else:
            continue

        for loop_index in loop_index_list:
            vertex_index = blender_mesh.loops[loop_index].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 = []

            vertex = blender_mesh.vertices[vertex_index]

            v = convert_swizzle_location(vertex.co, export_settings)
            if blender_polygon.use_smooth:
                n = convert_swizzle_location(vertex.normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(
                        blender_mesh.loops[loop_index].tangent,
                        export_settings)
                    b = convert_swizzle_location(
                        blender_mesh.loops[loop_index].bitangent,
                        export_settings)
            else:
                n = convert_swizzle_location(face_normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(face_tangent, export_settings)
                    b = convert_swizzle_location(face_bitangent,
                                                 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]), 1.0
                    ])

            #

            bone_count = 0

            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:
                        continue

                    #

                    vertex_group_index = group_element.group
                    vertex_group_name = blender_vertex_groups[
                        vertex_group_index].name

                    joint_index = None

                    if modifiers is not None:
                        modifiers_dict = {m.type: m for m in modifiers}
                        if "ARMATURE" in modifiers_dict:
                            armature = modifiers_dict["ARMATURE"].object
                            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,
                        export_settings)

                    # Store delta.
                    v_morph -= v

                    target_positions.append(v_morph)

                    #

                    n_morph = None

                    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])
                    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_location(n_morph,
                                                       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]))

                        t_morph.rotate(rotation)

                        target_tangents.append(t_morph)

            #
            #

            create = True

            for current_new_index in vertex_index_to_new_indices[vertex_index]:
                found = True

                for i in range(0, 3):
                    if attributes[POSITION_ATTRIBUTE][current_new_index * 3 +
                                                      i] != v[i]:
                        found = False
                        break

                    if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 +
                                                    i] != n[i]:
                        found = False
                        break

                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 primitive plus split them if needed.
    #

    result_primitives = []

    for material_name, primitive in material_name_to_primitives.items():
        export_color = True

        #

        indices = primitive[INDICES_ID]

        if len(indices) == 0:
            continue

        position = primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]
        normal = primitive[ATTRIBUTES_ID][NORMAL_ATTRIBUTE]
        if use_tangents:
            tangent = primitive[ATTRIBUTES_ID][TANGENT_ATTRIBUTE]
        tex_coords = []
        for tex_coord_index in range(0, tex_coord_max):
            tex_coords.append(primitive[ATTRIBUTES_ID][TEXCOORD_PREFIX +
                                                       str(tex_coord_index)])
        colors = []
        if export_color:
            for color_index in range(0, color_max):
                tex_coords.append(primitive[ATTRIBUTES_ID][COLOR_PREFIX +
                                                           str(color_index)])
        joints = []
        weights = []
        if export_settings[gltf2_blender_export_keys.SKINS]:
            for bone_index in range(0, bone_max):
                joints.append(primitive[ATTRIBUTES_ID][JOINTS_PREFIX +
                                                       str(bone_index)])
                weights.append(primitive[ATTRIBUTES_ID][WEIGHTS_PREFIX +
                                                        str(bone_index)])

        target_positions = []
        target_normals = []
        target_tangents = []
        if export_settings[gltf2_blender_export_keys.MORPH]:
            for morph_index in range(0, morph_max):
                target_positions.append(
                    primitive[ATTRIBUTES_ID][MORPH_POSITION_PREFIX +
                                             str(morph_index)])
                target_normals.append(
                    primitive[ATTRIBUTES_ID][MORPH_NORMAL_PREFIX +
                                             str(morph_index)])
                if use_tangents:
                    target_tangents.append(
                        primitive[ATTRIBUTES_ID][MORPH_TANGENT_PREFIX +
                                                 str(morph_index)])

        #

        count = len(indices)

        if count == 0:
            continue

        max_index = max(indices)

        #

        # NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
        # Specifically, the value 65535 (in UINT16) cannot be used as a vertex index.
        # https://github.com/KhronosGroup/glTF/issues/1142
        # https://github.com/KhronosGroup/glTF/pull/1476/files

        range_indices = 65535

        #

        if max_index >= range_indices:
            #
            # Splitting result_primitives.
            #

            # At start, all indices are pending.
            pending_attributes = {POSITION_ATTRIBUTE: [], NORMAL_ATTRIBUTE: []}

            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE] = []

            pending_primitive = {
                MATERIAL_ID: material_name,
                INDICES_ID: [],
                ATTRIBUTES_ID: pending_attributes
            }

            pending_primitive[INDICES_ID].extend(indices)

            pending_attributes[POSITION_ATTRIBUTE].extend(position)
            pending_attributes[NORMAL_ATTRIBUTE].extend(normal)
            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE].extend(tangent)
            tex_coord_index = 0
            for tex_coord in tex_coords:
                pending_attributes[TEXCOORD_PREFIX +
                                   str(tex_coord_index)] = tex_coord
                tex_coord_index += 1
            if export_color:
                color_index = 0
                for color in colors:
                    pending_attributes[COLOR_PREFIX + str(color_index)] = color
                    color_index += 1
            if export_settings[gltf2_blender_export_keys.SKINS]:
                joint_index = 0
                for joint in joints:
                    pending_attributes[JOINTS_PREFIX +
                                       str(joint_index)] = joint
                    joint_index += 1
                weight_index = 0
                for weight in weights:
                    pending_attributes[WEIGHTS_PREFIX +
                                       str(weight_index)] = weight
                    weight_index += 1
            if export_settings[gltf2_blender_export_keys.MORPH]:
                morph_index = 0
                for target_position in target_positions:
                    pending_attributes[MORPH_POSITION_PREFIX +
                                       str(morph_index)] = target_position
                    morph_index += 1
                morph_index = 0
                for target_normal in target_normals:
                    pending_attributes[MORPH_NORMAL_PREFIX +
                                       str(morph_index)] = target_normal
                    morph_index += 1
                if use_tangents:
                    morph_index = 0
                    for target_tangent in target_tangents:
                        pending_attributes[MORPH_TANGENT_PREFIX +
                                           str(morph_index)] = target_tangent
                        morph_index += 1

            pending_indices = pending_primitive[INDICES_ID]

            # Continue until all are processed.
            while len(pending_indices) > 0:

                process_indices = pending_primitive[INDICES_ID]
                max_index = max(process_indices)

                pending_indices = []

                #
                #

                all_local_indices = []

                for i in range(0, (max_index // range_indices) + 1):
                    all_local_indices.append([])

                #
                #

                # For all faces ...
                for face_index in range(0, len(process_indices), 3):

                    written = False

                    face_min_index = min(process_indices[face_index + 0],
                                         process_indices[face_index + 1],
                                         process_indices[face_index + 2])
                    face_max_index = max(process_indices[face_index + 0],
                                         process_indices[face_index + 1],
                                         process_indices[face_index + 2])

                    # ... check if it can be but in a range of maximum indices.
                    for i in range(0, (max_index // range_indices) + 1):
                        offset = i * range_indices

                        # Yes, so store the primitive with its indices.
                        if face_min_index >= offset and face_max_index < offset + range_indices:
                            all_local_indices[i].extend([
                                process_indices[face_index + 0],
                                process_indices[face_index + 1],
                                process_indices[face_index + 2]
                            ])

                            written = True
                            break

                    # If not written, the triangle face has indices from different ranges.
                    if not written:
                        pending_indices.extend([
                            process_indices[face_index + 0],
                            process_indices[face_index + 1],
                            process_indices[face_index + 2]
                        ])

                # Only add result_primitives, which do have indices in it.
                for local_indices in all_local_indices:
                    if len(local_indices) > 0:
                        current_primitive = extract_primitive_floor(
                            pending_primitive, local_indices, use_tangents)

                        result_primitives.append(current_primitive)

                        print_console(
                            'DEBUG',
                            'Adding primitive with splitting. Indices: ' +
                            str(len(current_primitive[INDICES_ID])) +
                            ' Vertices: ' + str(
                                len(current_primitive[ATTRIBUTES_ID]
                                    [POSITION_ATTRIBUTE]) // 3))

                # Process primitive faces having indices in several ranges.
                if len(pending_indices) > 0:
                    pending_primitive = extract_primitive_pack(
                        pending_primitive, pending_indices, use_tangents)

                    print_console(
                        'DEBUG', 'Creating temporary primitive for splitting')

        else:
            #
            # No splitting needed.
            #
            result_primitives.append(primitive)

            print_console(
                'DEBUG', 'Adding primitive without splitting. Indices: ' +
                str(len(primitive[INDICES_ID])) + ' Vertices: ' +
                str(len(primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))

    print_console('INFO', 'Primitives created: ' + str(len(result_primitives)))

    return result_primitives
コード例 #10
0
def tessellate_uvs(uvs):
    return tessellate_polygon([[Vector(uv) for uv in uvs]])
コード例 #11
0
 def tesselateVecs(self, vecs):
     return (tuple(reversed(t))
             for t in tessellate_polygon([[v for v in vecs]]))
コード例 #12
0
def build_objects(object_layers, object_surfs, object_tags, object_name, add_subd_mod, skel_to_arm):
    """Using the gathered data, create the objects."""
    ob_dict= {}  # Used for the parenting setup.
    print("Adding %d Materials" % len(object_surfs))

    for surf_key in object_surfs:
        surf_data= object_surfs[surf_key]
        surf_data.bl_mat= bpy.data.materials.new(surf_data.name)
        surf_data.bl_mat.diffuse_color= (surf_data.colr[:])
        surf_data.bl_mat.diffuse_intensity= surf_data.diff
        surf_data.bl_mat.emit= surf_data.lumi
        surf_data.bl_mat.specular_intensity= surf_data.spec
        if surf_data.refl != 0.0:
            surf_data.bl_mat.raytrace_mirror.use= True
        surf_data.bl_mat.raytrace_mirror.reflect_factor= surf_data.refl
        surf_data.bl_mat.raytrace_mirror.gloss_factor= 1.0-surf_data.rblr
        if surf_data.tran != 0.0:
            surf_data.bl_mat.use_transparency= True
            surf_data.bl_mat.transparency_method= 'RAYTRACE'
        surf_data.bl_mat.alpha= 1.0 - surf_data.tran
        surf_data.bl_mat.raytrace_transparency.ior= surf_data.rind
        surf_data.bl_mat.raytrace_transparency.gloss_factor= 1.0 - surf_data.tblr
        surf_data.bl_mat.translucency= surf_data.trnl
        surf_data.bl_mat.specular_hardness= int(4*((10*surf_data.glos)*(10*surf_data.glos)))+4
        # The Gloss is as close as possible given the differences.

    # Single layer objects use the object file's name instead.
    if len(object_layers) and object_layers[-1].name == 'Layer 1':
        object_layers[-1].name= object_name
        print("Building '%s' Object" % object_name)
    else:
        print("Building %d Objects" % len(object_layers))

    # Before adding any meshes or armatures go into Object mode.
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')

    for layer_data in object_layers:
        me= bpy.data.meshes.new(layer_data.name)
        me.vertices.add(len(layer_data.pnts))
        me.tessfaces.add(len(layer_data.pols))
        # for vi in range(len(layer_data.pnts)):
        #     me.vertices[vi].co= layer_data.pnts[vi]

        # faster, would be faster again to use an array
        me.vertices.foreach_set("co", [axis for co in layer_data.pnts for axis in co])

        ngons= {}   # To keep the FaceIdx consistent, handle NGons later.
        edges= []   # Holds the FaceIdx of the 2-point polys.
        for fi, fpol in enumerate(layer_data.pols):
            fpol.reverse()   # Reversing gives correct normal directions
            # PointID 0 in the last element causes Blender to think it's un-used.
            if fpol[-1] == 0:
                fpol.insert(0, fpol[-1])
                del fpol[-1]

            vlen= len(fpol)
            if vlen == 3 or vlen == 4:
                for i in range(vlen):
                    me.tessfaces[fi].vertices_raw[i]= fpol[i]
            elif vlen == 2:
                edges.append(fi)
            elif vlen != 1:
                ngons[fi]= fpol  # Deal with them later

        ob= bpy.data.objects.new(layer_data.name, me)
        bpy.context.scene.objects.link(ob)
        ob_dict[layer_data.index]= [ob, layer_data.parent_index]

        # Move the object so the pivot is in the right place.
        ob.location= layer_data.pivot

        # Create the Material Slots and assign the MatIndex to the correct faces.
        mat_slot= 0
        for surf_key in layer_data.surf_tags:
            if object_tags[surf_key] in object_surfs:
                me.materials.append(object_surfs[object_tags[surf_key]].bl_mat)

                for fi in layer_data.surf_tags[surf_key]:
                    me.tessfaces[fi].material_index= mat_slot
                    me.tessfaces[fi].use_smooth= object_surfs[object_tags[surf_key]].smooth

                mat_slot+=1

        # Create the Vertex Groups (LW's Weight Maps).
        if len(layer_data.wmaps) > 0:
            print("Adding %d Vertex Groups" % len(layer_data.wmaps))
            for wmap_key in layer_data.wmaps:
                vgroup= ob.vertex_groups.new()
                vgroup.name= wmap_key
                wlist= layer_data.wmaps[wmap_key]
                for pvp in wlist:
                    vgroup.add((pvp[0], ), pvp[1], 'REPLACE')

        # Create the Shape Keys (LW's Endomorphs).
        if len(layer_data.morphs) > 0:
            print("Adding %d Shapes Keys" % len(layer_data.morphs))
            ob.shape_key_add('Basis')   # Got to have a Base Shape.
            for morph_key in layer_data.morphs:
                skey= ob.shape_key_add(morph_key)
                dlist= layer_data.morphs[morph_key]
                for pdp in dlist:
                    me.shape_keys.key_blocks[skey.name].data[pdp[0]].co= [pdp[1], pdp[2], pdp[3]]

        # Create the Vertex Color maps.
        if len(layer_data.colmaps) > 0:
            print("Adding %d Vertex Color Maps" % len(layer_data.colmaps))
            for cmap_key in layer_data.colmaps:
                map_pack= create_mappack(layer_data, cmap_key, "COLOR")
                me.vertex_colors.new(cmap_key)
                vcol= me.tessface_vertex_colors[-1]
                if not vcol or not vcol.data:
                    break
                for fi in map_pack:
                    if fi > len(vcol.data):
                        continue
                    face= map_pack[fi]
                    colf= vcol.data[fi]

                    if len(face) > 2:
                        colf.color1= face[0]
                        colf.color2= face[1]
                        colf.color3= face[2]
                    if len(face) == 4:
                        colf.color4= face[3]

        # Create the UV Maps.
        if len(layer_data.uvmaps) > 0:
            print("Adding %d UV Textures" % len(layer_data.uvmaps))
            for uvmap_key in layer_data.uvmaps:
                map_pack= create_mappack(layer_data, uvmap_key, "UV")
                me.uv_textures.new(name=uvmap_key)
                uvm= me.tessface_uv_textures[-1]
                if not uvm or not uvm.data:
                    break
                for fi in map_pack:
                    if fi > len(uvm.data):
                        continue
                    face= map_pack[fi]
                    uvf= uvm.data[fi]

                    if len(face) > 2:
                        uvf.uv1= face[0]
                        uvf.uv2= face[1]
                        uvf.uv3= face[2]
                    if len(face) == 4:
                        uvf.uv4= face[3]

        # Now add the NGons.
        if len(ngons) > 0:
            for ng_key in ngons:
                face_offset= len(me.tessfaces)
                ng= ngons[ng_key]
                v_locs= []
                for vi in range(len(ng)):
                    v_locs.append(mathutils.Vector(layer_data.pnts[ngons[ng_key][vi]]))
                tris= tessellate_polygon([v_locs])
                me.tessfaces.add(len(tris))
                for tri in tris:
                    face= me.tessfaces[face_offset]
                    face.vertices_raw[0]= ng[tri[0]]
                    face.vertices_raw[1]= ng[tri[1]]
                    face.vertices_raw[2]= ng[tri[2]]
                    face.material_index= me.tessfaces[ng_key].material_index
                    face.use_smooth= me.tessfaces[ng_key].use_smooth
                    face_offset+= 1

        # FaceIDs are no longer a concern, so now update the mesh.
        has_edges= len(edges) > 0 or len(layer_data.edge_weights) > 0
        me.update(calc_edges=has_edges)

        # Add the edges.
        edge_offset= len(me.edges)
        me.edges.add(len(edges))
        for edge_fi in edges:
            me.edges[edge_offset].vertices[0]= layer_data.pols[edge_fi][0]
            me.edges[edge_offset].vertices[1]= layer_data.pols[edge_fi][1]
            edge_offset+= 1

        # Apply the Edge Weighting.
        if len(layer_data.edge_weights) > 0:
            for edge in me.edges:
                edge_sa= "{0} {1}".format(edge.vertices[0], edge.vertices[1])
                edge_sb= "{0} {1}".format(edge.vertices[1], edge.vertices[0])
                if edge_sa in layer_data.edge_weights:
                    edge.crease= layer_data.edge_weights[edge_sa]
                elif edge_sb in layer_data.edge_weights:
                    edge.crease= layer_data.edge_weights[edge_sb]

        # Unfortunately we can't exlude certain faces from the subdivision.
        if layer_data.has_subds and add_subd_mod:
            ob.modifiers.new(name="Subsurf", type='SUBSURF')

        # Should we build an armature from the embedded rig?
        if len(layer_data.bones) > 0 and skel_to_arm:
            bpy.ops.object.armature_add()
            arm_object= bpy.context.active_object
            arm_object.name= "ARM_" + layer_data.name
            arm_object.data.name= arm_object.name
            arm_object.location= layer_data.pivot
            bpy.ops.object.mode_set(mode='EDIT')
            build_armature(layer_data, arm_object.data.edit_bones)
            bpy.ops.object.mode_set(mode='OBJECT')

        # Clear out the dictionaries for this layer.
        layer_data.bone_names.clear()
        layer_data.bone_rolls.clear()
        layer_data.wmaps.clear()
        layer_data.colmaps.clear()
        layer_data.uvmaps.clear()
        layer_data.morphs.clear()
        layer_data.surf_tags.clear()

        # We may have some invalid mesh data, See: [#27916]
        # keep this last!
        print("validating mesh: %r..." % me.name)
        me.validate(verbose=1)
        print("done!")

    # With the objects made, setup the parents and re-adjust the locations.
    for ob_key in ob_dict:
        if ob_dict[ob_key][1] != -1 and ob_dict[ob_key][1] in ob_dict:
            parent_ob = ob_dict[ob_dict[ob_key][1]]
            ob_dict[ob_key][0].parent= parent_ob[0]
            ob_dict[ob_key][0].location-= parent_ob[0].location

    bpy.context.scene.update()

    print("Done Importing LWO File")
コード例 #13
0
 def tesselatePoly(self, vecs, poly):
     return (tuple(poly[i] for i in t) for t in tessellate_polygon( [[vecs[v] for v in poly]] ) )
コード例 #14
0
def build_objects(object_layers, object_surfs, object_tags, object_name, add_subd_mod, skel_to_arm, use_existing_materials):
    """Using the gathered data, create the objects."""
    ob_dict= {}  # Used for the parenting setup.
    print("Adding %d Materials" % len(object_surfs))

    for surf_key in object_surfs:
        surf_data= object_surfs[surf_key]
        surf_data.bl_mat = bpy.data.materials.get(surf_data.name) if use_existing_materials else None
        if surf_data.bl_mat is None:
            surf_data.bl_mat= bpy.data.materials.new(surf_data.name)
            surf_data.bl_mat.diffuse_color= (surf_data.colr[:])
            surf_data.bl_mat.diffuse_intensity= surf_data.diff
            surf_data.bl_mat.emit= surf_data.lumi
            surf_data.bl_mat.specular_intensity= surf_data.spec
            if surf_data.refl != 0.0:
                surf_data.bl_mat.raytrace_mirror.use= True
            surf_data.bl_mat.raytrace_mirror.reflect_factor= surf_data.refl
            surf_data.bl_mat.raytrace_mirror.gloss_factor= 1.0-surf_data.rblr
            if surf_data.tran != 0.0:
                surf_data.bl_mat.use_transparency= True
                surf_data.bl_mat.transparency_method= 'RAYTRACE'
            surf_data.bl_mat.alpha= 1.0 - surf_data.tran
            surf_data.bl_mat.raytrace_transparency.ior= surf_data.rind
            surf_data.bl_mat.raytrace_transparency.gloss_factor= 1.0 - surf_data.tblr
            surf_data.bl_mat.translucency= surf_data.trnl
            surf_data.bl_mat.specular_hardness= int(4*((10*surf_data.glos)*(10*surf_data.glos)))+4
        # The Gloss is as close as possible given the differences.

    # Single layer objects use the object file's name instead.
    if len(object_layers) and object_layers[-1].name == 'Layer 1':
        object_layers[-1].name= object_name
        print("Building '%s' Object" % object_name)
    else:
        print("Building %d Objects" % len(object_layers))

    # Before adding any meshes or armatures go into Object mode.
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')

    for layer_data in object_layers:
        me= bpy.data.meshes.new(layer_data.name)
        me.vertices.add(len(layer_data.pnts))
        me.tessfaces.add(len(layer_data.pols))
        # for vi in range(len(layer_data.pnts)):
        #     me.vertices[vi].co= layer_data.pnts[vi]

        # faster, would be faster again to use an array
        me.vertices.foreach_set("co", [axis for co in layer_data.pnts for axis in co])

        ngons= {}   # To keep the FaceIdx consistent, handle NGons later.
        edges= []   # Holds the FaceIdx of the 2-point polys.
        for fi, fpol in enumerate(layer_data.pols):
            fpol.reverse()   # Reversing gives correct normal directions
            # PointID 0 in the last element causes Blender to think it's un-used.
            if fpol[-1] == 0:
                fpol.insert(0, fpol[-1])
                del fpol[-1]

            vlen= len(fpol)
            if vlen == 3 or vlen == 4:
                for i in range(vlen):
                    me.tessfaces[fi].vertices_raw[i]= fpol[i]
            elif vlen == 2:
                edges.append(fi)
            elif vlen != 1:
                ngons[fi]= fpol  # Deal with them later

        ob= bpy.data.objects.new(layer_data.name, me)
        bpy.context.collection.objects.link(ob)
        ob_dict[layer_data.index]= [ob, layer_data.parent_index]

        # Move the object so the pivot is in the right place.
        ob.location= layer_data.pivot

        # Create the Material Slots and assign the MatIndex to the correct faces.
        mat_slot= 0
        for surf_key in layer_data.surf_tags:
            if object_tags[surf_key] in object_surfs:
                me.materials.append(object_surfs[object_tags[surf_key]].bl_mat)

                for fi in layer_data.surf_tags[surf_key]:
                    me.tessfaces[fi].material_index= mat_slot
                    me.tessfaces[fi].use_smooth= object_surfs[object_tags[surf_key]].smooth

                mat_slot+=1

        # Create the Vertex Groups (LW's Weight Maps).
        if len(layer_data.wmaps) > 0:
            print("Adding %d Vertex Groups" % len(layer_data.wmaps))
            for wmap_key in layer_data.wmaps:
                vgroup= ob.vertex_groups.new()
                vgroup.name= wmap_key
                wlist= layer_data.wmaps[wmap_key]
                for pvp in wlist:
                    vgroup.add((pvp[0], ), pvp[1], 'REPLACE')

        # Create the Shape Keys (LW's Endomorphs).
        if len(layer_data.morphs) > 0:
            print("Adding %d Shapes Keys" % len(layer_data.morphs))
            ob.shape_key_add('Basis')   # Got to have a Base Shape.
            for morph_key in layer_data.morphs:
                skey= ob.shape_key_add(morph_key)
                dlist= layer_data.morphs[morph_key]
                for pdp in dlist:
                    me.shape_keys.key_blocks[skey.name].data[pdp[0]].co= [pdp[1], pdp[2], pdp[3]]

        # Create the Vertex Color maps.
        if len(layer_data.colmaps) > 0:
            print("Adding %d Vertex Color Maps" % len(layer_data.colmaps))
            for cmap_key in layer_data.colmaps:
                map_pack= create_mappack(layer_data, cmap_key, "COLOR")
                me.vertex_colors.new(cmap_key)
                vcol= me.tessface_vertex_colors[-1]
                if not vcol or not vcol.data:
                    break
                for fi in map_pack:
                    if fi > len(vcol.data):
                        continue
                    face= map_pack[fi]
                    colf= vcol.data[fi]

                    if len(face) > 2:
                        colf.color1= face[0]
                        colf.color2= face[1]
                        colf.color3= face[2]
                    if len(face) == 4:
                        colf.color4= face[3]

        # Create the UV Maps.
        if len(layer_data.uvmaps) > 0:
            print("Adding %d UV Textures" % len(layer_data.uvmaps))
            for uvmap_key in layer_data.uvmaps:
                map_pack= create_mappack(layer_data, uvmap_key, "UV")
                me.uv_textures.new(name=uvmap_key)
                uvm= me.tessface_uv_textures[-1]
                if not uvm or not uvm.data:
                    break
                for fi in map_pack:
                    if fi > len(uvm.data):
                        continue
                    face= map_pack[fi]
                    uvf= uvm.data[fi]

                    if len(face) > 2:
                        uvf.uv1= face[0]
                        uvf.uv2= face[1]
                        uvf.uv3= face[2]
                    if len(face) == 4:
                        uvf.uv4= face[3]

        # Now add the NGons.
        if len(ngons) > 0:
            for ng_key in ngons:
                face_offset= len(me.tessfaces)
                ng= ngons[ng_key]
                v_locs= []
                for vi in range(len(ng)):
                    v_locs.append(mathutils.Vector(layer_data.pnts[ngons[ng_key][vi]]))
                tris= tessellate_polygon([v_locs])
                me.tessfaces.add(len(tris))
                for tri in tris:
                    face= me.tessfaces[face_offset]
                    face.vertices_raw[0]= ng[tri[0]]
                    face.vertices_raw[1]= ng[tri[1]]
                    face.vertices_raw[2]= ng[tri[2]]
                    face.material_index= me.tessfaces[ng_key].material_index
                    face.use_smooth= me.tessfaces[ng_key].use_smooth
                    face_offset+= 1

        # FaceIDs are no longer a concern, so now update the mesh.
        has_edges= len(edges) > 0 or len(layer_data.edge_weights) > 0
        me.update(calc_edges=has_edges)

        # Add the edges.
        edge_offset= len(me.edges)
        me.edges.add(len(edges))
        for edge_fi in edges:
            me.edges[edge_offset].vertices[0]= layer_data.pols[edge_fi][0]
            me.edges[edge_offset].vertices[1]= layer_data.pols[edge_fi][1]
            edge_offset+= 1

        # Apply the Edge Weighting.
        if len(layer_data.edge_weights) > 0:
            for edge in me.edges:
                edge_sa= "{0} {1}".format(edge.vertices[0], edge.vertices[1])
                edge_sb= "{0} {1}".format(edge.vertices[1], edge.vertices[0])
                if edge_sa in layer_data.edge_weights:
                    edge.crease= layer_data.edge_weights[edge_sa]
                elif edge_sb in layer_data.edge_weights:
                    edge.crease= layer_data.edge_weights[edge_sb]

        # Unfortunately we can't exlude certain faces from the subdivision.
        if layer_data.has_subds and add_subd_mod:
            ob.modifiers.new(name="Subsurf", type='SUBSURF')

        # Should we build an armature from the embedded rig?
        if len(layer_data.bones) > 0 and skel_to_arm:
            bpy.ops.object.armature_add()
            arm_object= bpy.context.active_object
            arm_object.name= "ARM_" + layer_data.name
            arm_object.data.name= arm_object.name
            arm_object.location= layer_data.pivot
            bpy.ops.object.mode_set(mode='EDIT')
            build_armature(layer_data, arm_object.data.edit_bones)
            bpy.ops.object.mode_set(mode='OBJECT')

        # Clear out the dictionaries for this layer.
        layer_data.bone_names.clear()
        layer_data.bone_rolls.clear()
        layer_data.wmaps.clear()
        layer_data.colmaps.clear()
        layer_data.uvmaps.clear()
        layer_data.morphs.clear()
        layer_data.surf_tags.clear()

        # We may have some invalid mesh data, See: [#27916]
        # keep this last!
        print("validating mesh: %r..." % me.name)
        me.validate(verbose=1)
        print("done!")

    # With the objects made, setup the parents and re-adjust the locations.
    for ob_key in ob_dict:
        if ob_dict[ob_key][1] != -1 and ob_dict[ob_key][1] in ob_dict:
            parent_ob = ob_dict[ob_dict[ob_key][1]]
            ob_dict[ob_key][0].parent= parent_ob[0]
            ob_dict[ob_key][0].location-= parent_ob[0].location

    bpy.context.scene.update()

    print("Done Importing LWO File")
コード例 #15
0
def face_random_points_ngons(num_points, tessfaces):

    from random import random
    import mathutils
    from mathutils.geometry import area_tri, tessellate_polygon

    # Split all quads into 2 tris, tris remain unchanged
    tri_faces = []
    for f in tessfaces:
        tris = []
        verts = f.id_data.vertices
        fv = f.vertices[:]

        if len(fv) == 3:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
        elif len(fv) == 4:
            tris.append((verts[fv[0]].co, verts[fv[1]].co, verts[fv[2]].co))
            tris.append((verts[fv[0]].co, verts[fv[3]].co, verts[fv[2]].co))
        else:
            fvngon = [v.co for v in verts]
            tris.extend([[fvngon[i] for i in tess] for tess in tessellate_polygon([fvngon])])

        tri_faces.append(tris)

    # For each face, generate the required number of random points
    sampled_points = [None] * (num_points * len(tessfaces))
    # sampled points need to be vectorized as npo below
    for i, tf, npo in enumerate(zip(tri_faces,num_points)):
        for k in range(npo):
            # If this is a quad, we need to weight its 2 tris by their area
            if len(tf) == 2:

                area1 = area_tri(*tf[0])
                area2 = area_tri(*tf[1])
                area_tot = area1 + area2
                area1 = area1 / area_tot
                area2 = area2 / area_tot
                vecs = tf[0 if (random() < area1) else 1]

            elif len(tf) == 1:

                vecs = tf[0]

            else:

                areas = [area_tri(*tface) for tface in tf]
                area_tot = sum(areas)
                areas = [(area / area_tot) for area in areas]

                #  vecs = tf[0 if (random() < area1) else 1]   ???

            u1 = random()
            u2 = random()
            u_tot = u1 + u2

            if u_tot > 1:
                u1 = 1.0 - u1
                u2 = 1.0 - u2

            side1 = vecs[1] - vecs[0]
            side2 = vecs[2] - vecs[0]

            p = vecs[0] + u1 * side1 + u2 * side2

            sampled_points[npo * i + k] = p

    return sampled_points
コード例 #16
0
def extract_primitives(glTF, blender_mesh, 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.
    """
    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 = {}

    #
    # 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
    }

    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

    tex_coord_max = 0
    if blender_mesh.uv_layers.active:
        tex_coord_max = len(blender_mesh.uv_layers)

    #

    vertex_colors = {}

    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_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:
        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

    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

    #
    # Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
    #
    for blender_polygon in blender_mesh.polygons:
        export_color = True

        #

        if 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]

        loop_index_list = []

        if len(blender_polygon.loop_indices) == 3:
            loop_index_list.extend(blender_polygon.loop_indices)
        elif len(blender_polygon.loop_indices) > 3:
            # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
            polyline = []

            for loop_index in blender_polygon.loop_indices:
                vertex_index = blender_mesh.loops[loop_index].vertex_index
                v = blender_mesh.vertices[vertex_index].co
                polyline.append(Vector((v[0], v[1], v[2])))

            triangles = tessellate_polygon((polyline, ))

            for triangle in triangles:
                if bpy.app.version < (2, 81, 15):
                    # tessellate_polygon winding-order is reversed in old versions of Blender
                    # See https://developer.blender.org/T70594
                    triangle = (triangle[0], triangle[2], triangle[1])

                for triangle_index in triangle:
                    loop_index_list.append(
                        blender_polygon.loop_indices[triangle_index])
        else:
            continue

        for loop_index in loop_index_list:
            vertex_index = blender_mesh.loops[loop_index].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 = []

            vertex = blender_mesh.vertices[vertex_index]

            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_and_tangent(
                        blender_mesh.loops[loop_index].normal, armature,
                        blender_object, export_settings)
                else:
                    n = convert_swizzle_normal_and_tangent(
                        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_and_tangent(face_normal, armature,
                                                       blender_object,
                                                       export_settings)
                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
                    if len(color) == 3:
                        colors.append([
                            color_srgb_to_scene_linear(color[0]),
                            color_srgb_to_scene_linear(color[1]),
                            color_srgb_to_scene_linear(color[2]), 1.0
                        ])
                    else:
                        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

            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:
                        continue

                    #

                    vertex_group_index = group_element.group
                    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)

                    #

                    n_morph = None

                    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])
                    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_and_tangent(
                        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]))

                        t_morph.rotate(rotation)

                        target_tangents.append(t_morph)

            #
            #

            create = True

            for current_new_index in vertex_index_to_new_indices[vertex_index]:
                found = True

                for i in range(0, 3):
                    if attributes[POSITION_ATTRIBUTE][current_new_index * 3 +
                                                      i] != v[i]:
                        found = False
                        break

                    if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 +
                                                    i] != n[i]:
                        found = False
                        break

                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)))

    return result_primitives
コード例 #17
0
def tessellate_uvs(uvs):
    return tessellate_polygon([uvs])
コード例 #18
0
def draw_manipulator(self, context):

    glEnable(GL_BLEND)
    glEnable(GL_LINE_SMOOTH)

    locations_2d = self.locations_2d

    locations_2d_scaled = []
    for v in locations_2d:
        origin = 0, 0
        point = v[0], v[1]
        value = get_preferences().fidget_manimulator_scale
        px, py = scale(origin, point, value)
        locations_2d_scaled.append(Vector((px, py)))

    locations_2d = locations_2d_scaled

    locations_2d_rotated = []
    for v in locations_2d:
        origin = 0, 0
        point = v[0], v[1]
        angle = math.radians(get_preferences().fidget_manimulator_rotation)
        px, py = rotate(origin, point, angle)
        locations_2d_rotated.append(Vector((px, py)))

    locations_2d = locations_2d_rotated

    location_2d_2 = []
    location_2d_3 = []

    for v in locations_2d:
        origin = 0, 0
        point = v[0], v[1]
        angle = math.radians(120)
        px, py = rotate(origin, point, angle)
        location_2d_2.append(Vector((px, py)))

    for v in locations_2d:
        origin = 0, 0
        point = v[0], v[1]
        angle = math.radians(-120)
        px, py = rotate(origin, point, angle)
        location_2d_3.append(Vector((px, py)))

    for v in locations_2d:
        v[0] = v[0] + self.center[0]
        v[1] = v[1] + self.center[1]
    for v in location_2d_2:
        v[0] = v[0] + self.center[0]
        v[1] = v[1] + self.center[1]
    for v in location_2d_3:
        v[0] = v[0] + self.center[0]
        v[1] = v[1] + self.center[1]

    triangles = tessellate_polygon([locations_2d])
    triangles2 = tessellate_polygon([location_2d_2])
    triangles3 = tessellate_polygon([location_2d_3])

    if inside_polygon(self.mouse_pos[0], self.mouse_pos[1], locations_2d):
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color_hover)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color_mode2_hover)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color_mode3_hover)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_top = True
    else:
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color_mode2)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button1_color_mode3)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_top = False
    glBegin(GL_TRIANGLES)
    for tri in triangles:
        for v_id in tri:
            v = locations_2d[v_id]
            glVertex2f(v[0], v[1])
    glEnd()

    if get_preferences().fidget_enable_outline:
        bgR, bgG, bgB, bgA = set_color(get_preferences().fidget_outline)
        glColor4f(bgR, bgG, bgB, bgA)
        glLineWidth(get_preferences().fidget_outline_width)
        glBegin(GL_LINE_LOOP)
        for loc_2d in locations_2d:
            glVertex2f(loc_2d[0], loc_2d[1])
        glEnd()

    if inside_polygon(self.mouse_pos[0], self.mouse_pos[1], location_2d_2):
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color_hover)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color_mode2_hover)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color_mode3_hover)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_left = True
    else:
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color_mode2)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button2_color_mode3)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_left = False
    glBegin(GL_TRIANGLES)
    for tri in triangles2:
        for v_id in tri:
            v = location_2d_2[v_id]
            glVertex2f(v[0], v[1])
    glEnd()

    if get_preferences().fidget_enable_outline:
        bgR, bgG, bgB, bgA = set_color(get_preferences().fidget_outline)
        glLineWidth(get_preferences().fidget_outline_width)
        glColor4f(bgR, bgG, bgB, bgA)
        glBegin(GL_LINE_LOOP)
        for loc_2d in location_2d_2:
            glVertex2f(loc_2d[0], loc_2d[1])
        glEnd()

    if inside_polygon(self.mouse_pos[0], self.mouse_pos[1], location_2d_3):
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color_hover)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color_mode2_hover)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color_mode3_hover)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_right = True
    else:
        if get_preferences().mode == "MODE1":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color)
        elif get_preferences().mode == "MODE2":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color_mode2)
        elif get_preferences().mode == "MODE3":
            bgR, bgG, bgB, bgA = set_color(
                get_preferences().fidget_button3_color_mode3)
        glColor4f(bgR, bgG, bgB, bgA)
        self.button_right = False
    glBegin(GL_TRIANGLES)
    for tri in triangles3:
        for v_id in tri:
            v = location_2d_3[v_id]
            glVertex2f(v[0], v[1])
    glEnd()

    if get_preferences().fidget_enable_outline:
        bgR, bgG, bgB, bgA = set_color(get_preferences().fidget_outline)
        glLineWidth(get_preferences().fidget_outline_width)
        glColor4f(bgR, bgG, bgB, bgA)
        glBegin(GL_LINE_LOOP)
        for loc_2d in location_2d_3:
            glVertex2f(loc_2d[0], loc_2d[1])
        glEnd()

    glDisable(GL_LINE_SMOOTH)
    glDisable(GL_BLEND)
コード例 #19
0
 def test_empty(self):
     self.assertEqual([], geometry.tessellate_polygon([]))
コード例 #20
0
def extract_primitives(glTF, blender_mesh, 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.
    """
    print_console('INFO', 'Extracting primitive: ' + blender_mesh.name)

    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 = {}

    #
    # 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: '',
        INDICES_ID: [],
        ATTRIBUTES_ID: no_material_attributes
    }

    material_name_to_primitives = {'': no_material_primitives}

    #

    vertex_index_to_new_indices = {}

    material_map[''] = vertex_index_to_new_indices

    #
    # Create primitive for each material.
    #
    for blender_material in blender_mesh.materials:
        if blender_material is None:
            continue

        attributes = {
            POSITION_ATTRIBUTE: [],
            NORMAL_ATTRIBUTE: []
        }

        if use_tangents:
            attributes[TANGENT_ATTRIBUTE] = []

        primitive = {
            MATERIAL_ID: blender_material.name,
            INDICES_ID: [],
            ATTRIBUTES_ID: attributes
        }

        material_name_to_primitives[blender_material.name] = primitive

        #

        vertex_index_to_new_indices = {}

        material_map[blender_material.name] = vertex_index_to_new_indices

    tex_coord_max = 0
    if blender_mesh.uv_layers.active:
        tex_coord_max = len(blender_mesh.uv_layers)

    #

    vertex_colors = {}

    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_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:
        morph_max = len(blender_mesh.shape_keys.key_blocks) - 1

        for blender_shape_key in blender_mesh.shape_keys.key_blocks:
            if blender_shape_key != blender_shape_key.relative_key:
                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

    #
    # Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
    #
    for blender_polygon in blender_mesh.polygons:
        export_color = True

        #

        if blender_polygon.material_index < 0 or blender_polygon.material_index >= len(blender_mesh.materials) or \
                blender_mesh.materials[blender_polygon.material_index] is None:
            primitive = material_name_to_primitives['']
            vertex_index_to_new_indices = material_map['']
        else:
            primitive = material_name_to_primitives[blender_mesh.materials[blender_polygon.material_index].name]
            vertex_index_to_new_indices = material_map[blender_mesh.materials[blender_polygon.material_index].name]
        #

        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]

        loop_index_list = []

        if len(blender_polygon.loop_indices) == 3:
            loop_index_list.extend(blender_polygon.loop_indices)
        elif len(blender_polygon.loop_indices) > 3:
            # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
            polyline = []

            for loop_index in blender_polygon.loop_indices:
                vertex_index = blender_mesh.loops[loop_index].vertex_index
                v = blender_mesh.vertices[vertex_index].co
                polyline.append(Vector((v[0], v[1], v[2])))

            triangles = tessellate_polygon((polyline,))

            for triangle in triangles:
                loop_index_list.append(blender_polygon.loop_indices[triangle[0]])
                loop_index_list.append(blender_polygon.loop_indices[triangle[2]])
                loop_index_list.append(blender_polygon.loop_indices[triangle[1]])
        else:
            continue

        for loop_index in loop_index_list:
            vertex_index = blender_mesh.loops[loop_index].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 = []

            vertex = blender_mesh.vertices[vertex_index]

            v = convert_swizzle_location(vertex.co, export_settings)
            if blender_polygon.use_smooth:
                if blender_mesh.has_custom_normals:
                    n = convert_swizzle_location(blender_mesh.loops[loop_index].normal, export_settings)
                else:
                    n = convert_swizzle_location(vertex.normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(blender_mesh.loops[loop_index].tangent, export_settings)
                    b = convert_swizzle_location(blender_mesh.loops[loop_index].bitangent, export_settings)
            else:
                n = convert_swizzle_location(face_normal, export_settings)
                if use_tangents:
                    t = convert_swizzle_tangent(face_tangent, export_settings)
                    b = convert_swizzle_location(face_bitangent, 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]),
                        1.0
                    ])

            #

            bone_count = 0

            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:
                        continue

                    #

                    vertex_group_index = group_element.group
                    vertex_group_name = blender_vertex_groups[vertex_group_index].name

                    joint_index = 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
                            if armature:
                                skin = gltf2_blender_gather_skins.gather_skin(armature, modifier.id_data, 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,
                                                       export_settings)

                    # Store delta.
                    v_morph -= v

                    target_positions.append(v_morph)

                    #

                    n_morph = None

                    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])
                    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_location(n_morph, 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]))

                        t_morph.rotate(rotation)

                        target_tangents.append(t_morph)

            #
            #

            create = True

            for current_new_index in vertex_index_to_new_indices[vertex_index]:
                found = True

                for i in range(0, 3):
                    if attributes[POSITION_ATTRIBUTE][current_new_index * 3 + i] != v[i]:
                        found = False
                        break

                    if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 + i] != n[i]:
                        found = False
                        break

                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 primitive plus split them if needed.
    #

    result_primitives = []

    for material_name, primitive in material_name_to_primitives.items():
        export_color = True

        #

        indices = primitive[INDICES_ID]

        if len(indices) == 0:
            continue

        position = primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]
        normal = primitive[ATTRIBUTES_ID][NORMAL_ATTRIBUTE]
        if use_tangents:
            tangent = primitive[ATTRIBUTES_ID][TANGENT_ATTRIBUTE]
        tex_coords = []
        for tex_coord_index in range(0, tex_coord_max):
            tex_coords.append(primitive[ATTRIBUTES_ID][TEXCOORD_PREFIX + str(tex_coord_index)])
        colors = []
        if export_color:
            for color_index in range(0, color_max):
                tex_coords.append(primitive[ATTRIBUTES_ID][COLOR_PREFIX + str(color_index)])
        joints = []
        weights = []
        if export_settings[gltf2_blender_export_keys.SKINS]:
            for bone_index in range(0, bone_max):
                joints.append(primitive[ATTRIBUTES_ID][JOINTS_PREFIX + str(bone_index)])
                weights.append(primitive[ATTRIBUTES_ID][WEIGHTS_PREFIX + str(bone_index)])

        target_positions = []
        target_normals = []
        target_tangents = []
        if export_settings[gltf2_blender_export_keys.MORPH]:
            for morph_index in range(0, morph_max):
                target_positions.append(primitive[ATTRIBUTES_ID][MORPH_POSITION_PREFIX + str(morph_index)])
                target_normals.append(primitive[ATTRIBUTES_ID][MORPH_NORMAL_PREFIX + str(morph_index)])
                if use_tangents:
                    target_tangents.append(primitive[ATTRIBUTES_ID][MORPH_TANGENT_PREFIX + str(morph_index)])

        #

        count = len(indices)

        if count == 0:
            continue

        max_index = max(indices)

        #

        # NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
        # Specifically, the value 65535 (in UINT16) cannot be used as a vertex index.
        # https://github.com/KhronosGroup/glTF/issues/1142
        # https://github.com/KhronosGroup/glTF/pull/1476/files

        range_indices = 65535

        #

        if max_index >= range_indices:
            #
            # Splitting result_primitives.
            #

            # At start, all indices are pending.
            pending_attributes = {
                POSITION_ATTRIBUTE: [],
                NORMAL_ATTRIBUTE: []
            }

            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE] = []

            pending_primitive = {
                MATERIAL_ID: material_name,
                INDICES_ID: [],
                ATTRIBUTES_ID: pending_attributes
            }

            pending_primitive[INDICES_ID].extend(indices)

            pending_attributes[POSITION_ATTRIBUTE].extend(position)
            pending_attributes[NORMAL_ATTRIBUTE].extend(normal)
            if use_tangents:
                pending_attributes[TANGENT_ATTRIBUTE].extend(tangent)
            tex_coord_index = 0
            for tex_coord in tex_coords:
                pending_attributes[TEXCOORD_PREFIX + str(tex_coord_index)] = tex_coord
                tex_coord_index += 1
            if export_color:
                color_index = 0
                for color in colors:
                    pending_attributes[COLOR_PREFIX + str(color_index)] = color
                    color_index += 1
            if export_settings[gltf2_blender_export_keys.SKINS]:
                joint_index = 0
                for joint in joints:
                    pending_attributes[JOINTS_PREFIX + str(joint_index)] = joint
                    joint_index += 1
                weight_index = 0
                for weight in weights:
                    pending_attributes[WEIGHTS_PREFIX + str(weight_index)] = weight
                    weight_index += 1
            if export_settings[gltf2_blender_export_keys.MORPH]:
                morph_index = 0
                for target_position in target_positions:
                    pending_attributes[MORPH_POSITION_PREFIX + str(morph_index)] = target_position
                    morph_index += 1
                morph_index = 0
                for target_normal in target_normals:
                    pending_attributes[MORPH_NORMAL_PREFIX + str(morph_index)] = target_normal
                    morph_index += 1
                if use_tangents:
                    morph_index = 0
                    for target_tangent in target_tangents:
                        pending_attributes[MORPH_TANGENT_PREFIX + str(morph_index)] = target_tangent
                        morph_index += 1

            pending_indices = pending_primitive[INDICES_ID]

            # Continue until all are processed.
            while len(pending_indices) > 0:

                process_indices = pending_primitive[INDICES_ID]
                max_index = max(process_indices)

                pending_indices = []

                #
                #

                all_local_indices = []

                for i in range(0, (max_index // range_indices) + 1):
                    all_local_indices.append([])

                #
                #

                # For all faces ...
                for face_index in range(0, len(process_indices), 3):

                    written = False

                    face_min_index = min(process_indices[face_index + 0], process_indices[face_index + 1],
                                         process_indices[face_index + 2])
                    face_max_index = max(process_indices[face_index + 0], process_indices[face_index + 1],
                                         process_indices[face_index + 2])

                    # ... check if it can be but in a range of maximum indices.
                    for i in range(0, (max_index // range_indices) + 1):
                        offset = i * range_indices

                        # Yes, so store the primitive with its indices.
                        if face_min_index >= offset and face_max_index < offset + range_indices:
                            all_local_indices[i].extend(
                                [process_indices[face_index + 0], process_indices[face_index + 1],
                                 process_indices[face_index + 2]])

                            written = True
                            break

                    # If not written, the triangle face has indices from different ranges.
                    if not written:
                        pending_indices.extend([process_indices[face_index + 0], process_indices[face_index + 1],
                                                process_indices[face_index + 2]])

                # Only add result_primitives, which do have indices in it.
                for local_indices in all_local_indices:
                    if len(local_indices) > 0:
                        current_primitive = extract_primitive_floor(pending_primitive, local_indices, use_tangents)

                        result_primitives.append(current_primitive)

                        print_console('DEBUG', 'Adding primitive with splitting. Indices: ' + str(
                            len(current_primitive[INDICES_ID])) + ' Vertices: ' + str(
                            len(current_primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))

                # Process primitive faces having indices in several ranges.
                if len(pending_indices) > 0:
                    pending_primitive = extract_primitive_pack(pending_primitive, pending_indices, use_tangents)

                    print_console('DEBUG', 'Creating temporary primitive for splitting')

        else:
            #
            # No splitting needed.
            #
            result_primitives.append(primitive)

            print_console('DEBUG', 'Adding primitive without splitting. Indices: ' + str(
                len(primitive[INDICES_ID])) + ' Vertices: ' + str(
                len(primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))

    print_console('INFO', 'Primitives created: ' + str(len(result_primitives)))

    return result_primitives
コード例 #21
0
    def modal(self, context, event):
        self.mouse_x = event.mouse_region_x
        self.mouse_y = event.mouse_region_y

        self.region = context.region

        if context.space_data is not None:
            self.region_3d = context.space_data.region_3d

            self.updateSelectionModes(context)

            # self.flag_redraw -> one more redraw needed at the end of modals
            # (which block this very one)
            if self.flag and not self.flag_redraw:
                self.region.tag_redraw()
                self.flag_redraw = True
            elif self.flag_redraw:
                self.flag_redraw = False
                
            self.flag = False

            if (self.region_3d is not None and context.mode == 'EDIT_MESH'
                and self.running):

                coords = (self.mouse_x, self.mouse_y)

                self.ray_origin = region_2d_to_origin_3d(
                    self.region,
                    self.region_3d,
                    coords)
                self.ray_direction = region_2d_to_vector_3d(
                    self.region,
                    self.region_3d,
                    coords)*RAY_MAX

                obj = context.object
                matrix_world = obj.matrix_world

                if self.bmesh is None or not self.bmesh.is_valid:
                    self.bmesh = from_edit_mesh(obj.data)

                df = self.draw_face
                de = self.draw_edges
                dv = self.draw_verts

                found = False

                if self.select_verts:

                    min_dist_sqr = None
                    point_vert = None

                    for vert in self.bmesh.verts:
                        if not vert.hide:
                            point = matrix_world*vert.co
                            point_2d = self.location_3d_to_region_2d(point)

                            dist_sqr = self.testVert2D(point_2d)

                            if dist_sqr is not None:
                                if (min_dist_sqr is None
                                    or min_dist_sqr > dist_sqr):
                                    min_dist_sqr = dist_sqr
                                    point_vert = point

                    if point_vert is None or min_dist_sqr > DIST_MAX_SQR:
                        #????
                        self.draw_face = None
                        self.draw_edges = []
                        self.draw_verts = []

                    else:
                        found = True
                        self.draw_face = None
                        self.draw_edges = []
                        self.draw_verts = [point_vert]


                if self.select_edges and not found:

                    min_dist_sqr = None
                    points_edge = None

                    for edge in self.bmesh.edges:
                        if not edge.hide:
                            points = [matrix_world*v.co for v in edge.verts]
                            points_2d = [self.location_3d_to_region_2d(point)
                                         for point in points]

                            dist_sqr = self.testEdge2D(points_2d)

                            if dist_sqr is not None:
                                if (min_dist_sqr is None
                                    or min_dist_sqr > dist_sqr):
                                    min_dist_sqr = dist_sqr
                                    points_edge = points

                    if points_edge is None or min_dist_sqr > DIST_MAX_SQR:
                        #????
                        self.draw_face = None
                        self.draw_edges = []
                        self.draw_verts = []

                    else:
                        found = True
                        self.draw_face = None
                        self.draw_edges = [points_edge]
                        self.draw_verts = points_edge
                        

                if self.select_faces and not found:

                    min_dist = None
                    points_face = None
                    
                    for face in self.bmesh.faces:
                        if not face.hide:
                            points = [matrix_world*v.co for v in face.verts]
                            points_2d = [self.location_3d_to_region_2d(point)
                                         for point in points]
                            tess_face = tessellate_polygon((points,))

                            possible_tris = []

                            for tri in tess_face:
                                if self.testTri2D([points_2d[i] for i in tri]):
                                    possible_tris.append(tri)

                            for tri in possible_tris:
                                dist = self.testTri3D([points[i] for i in tri])
                                if dist is not None:
                                    if min_dist is None or min_dist > dist:
                                        min_dist = dist
                                        points_face = points
                                        break

                    if points_face is None:
                        self.draw_face = None
                        self.draw_edges = [] # XXX TEMP!!!
                        self.draw_verts = [] # XXX
                    else:
                        self.draw_face = points_face
                        self.draw_edges = [(points_face[i - 1], v)
                                           for i, v in enumerate(points_face)]
                        self.draw_verts = points_face

                if (df != self.draw_face or de != self.draw_edges
                    or dv != self.draw_verts):
                    self.region.tag_redraw()
                    # forced redraw -> not another modal
                    # -> no need for a new one
                    self.flag_redraw = True
コード例 #22
0
ファイル: mesh_utils.py プロジェクト: antont/blender
def ngon_tessellate(from_data, indices, fix_loops=True):
    """
    Takes a polyline of indices (fgon) and returns a list of face
    index lists. Designed to be used for importers that need indices for an
    fgon to create from existing verts.

    :arg from_data: either a mesh, or a list/tuple of vectors.
    :type from_data: list or :class:`bpy.types.Mesh`
    :arg indices: a list of indices to use this list
       is the ordered closed polyline
       to fill, and can be a subset of the data given.
    :type indices: list
    :arg fix_loops: If this is enabled polylines
       that use loops to make multiple
       polylines are delt with correctly.
    :type fix_loops: bool
    """

    from mathutils.geometry import tessellate_polygon
    from mathutils import Vector
    vector_to_tuple = Vector.to_tuple

    if not indices:
        return []

    def mlen(co):
        # manhatten length of a vector, faster then length
        return abs(co[0]) + abs(co[1]) + abs(co[2])

    def vert_treplet(v, i):
        return v, vector_to_tuple(v, 6), i, mlen(v)

    def ed_key_mlen(v1, v2):
        if v1[3] > v2[3]:
            return v2[1], v1[1]
        else:
            return v1[1], v2[1]

    if not fix_loops:
        """
        Normal single concave loop filling
        """
        if type(from_data) in {tuple, list}:
            verts = [Vector(from_data[i]) for ii, i in enumerate(indices)]
        else:
            verts = [from_data.vertices[i].co for ii, i in enumerate(indices)]

        # same as reversed(range(1, len(verts))):
        for i in range(len(verts) - 1, 0, -1):
            if verts[i][1] == verts[i - 1][0]:
                verts.pop(i - 1)

        fill = tessellate_polygon([verts])

    else:
        """
        Seperate this loop into multiple loops be finding edges that are
        used twice. This is used by lightwave LWO files a lot
        """

        if type(from_data) in {tuple, list}:
            verts = [
                vert_treplet(Vector(from_data[i]), ii)
                for ii, i in enumerate(indices)
            ]
        else:
            verts = [
                vert_treplet(from_data.vertices[i].co, ii)
                for ii, i in enumerate(indices)
            ]

        edges = [(i, i - 1) for i in range(len(verts))]
        if edges:
            edges[0] = (0, len(verts) - 1)

        if not verts:
            return []

        edges_used = set()
        edges_doubles = set()
        # We need to check if any edges are used twice location based.
        for ed in edges:
            edkey = ed_key_mlen(verts[ed[0]], verts[ed[1]])
            if edkey in edges_used:
                edges_doubles.add(edkey)
            else:
                edges_used.add(edkey)

        # Store a list of unconnected loop segments split by double edges.
        # will join later
        loop_segments = []

        v_prev = verts[0]
        context_loop = [v_prev]
        loop_segments = [context_loop]

        for v in verts:
            if v != v_prev:
                # Are we crossing an edge we removed?
                if ed_key_mlen(v, v_prev) in edges_doubles:
                    context_loop = [v]
                    loop_segments.append(context_loop)
                else:
                    if context_loop and context_loop[-1][1] == v[1]:
                        #raise "as"
                        pass
                    else:
                        context_loop.append(v)

                v_prev = v
        # Now join loop segments

        def join_seg(s1, s2):
            if s2[-1][1] == s1[0][1]:
                s1, s2 = s2, s1
            elif s1[-1][1] == s2[0][1]:
                pass
            else:
                return False

            # If were stuill here s1 and s2 are 2 segments in the same polyline
            s1.pop()  # remove the last vert from s1
            s1.extend(s2)  # add segment 2 to segment 1

            if s1[0][1] == s1[-1][1]:  # remove endpoints double
                s1.pop()

            del s2[:]  # Empty this segment s2 so we don't use it again.
            return True

        joining_segments = True
        while joining_segments:
            joining_segments = False
            segcount = len(loop_segments)

            for j in range(segcount - 1, -1, -1):  # reversed(range(segcount)):
                seg_j = loop_segments[j]
                if seg_j:
                    for k in range(j - 1, -1, -1):  # reversed(range(j)):
                        if not seg_j:
                            break
                        seg_k = loop_segments[k]

                        if seg_k and join_seg(seg_j, seg_k):
                            joining_segments = True

        loop_list = loop_segments

        for verts in loop_list:
            while verts and verts[0][1] == verts[-1][1]:
                verts.pop()

        loop_list = [verts for verts in loop_list if len(verts) > 2]
        # DONE DEALING WITH LOOP FIXING

        # vert mapping
        vert_map = [None] * len(indices)
        ii = 0
        for verts in loop_list:
            if len(verts) > 2:
                for i, vert in enumerate(verts):
                    vert_map[i + ii] = vert[2]
                ii += len(verts)

        fill = tessellate_polygon([[v[0] for v in loop] for loop in loop_list])
        #draw_loops(loop_list)
        #raise Exception("done loop")
        # map to original indices
        fill = [[vert_map[i] for i in reversed(f)] for f in fill]

    if not fill:
        print('Warning Cannot scanfill, fallback on a triangle fan.')
        fill = [[0, i - 1, i] for i in range(2, len(indices))]
    else:
        # Use real scanfill.
        # See if its flipped the wrong way.
        flip = None
        for fi in fill:
            if flip is not None:
                break
            for i, vi in enumerate(fi):
                if vi == 0 and fi[i - 1] == 1:
                    flip = False
                    break
                elif vi == 1 and fi[i - 1] == 0:
                    flip = True
                    break

        if not flip:
            for i, fi in enumerate(fill):
                fill[i] = tuple([ii for ii in reversed(fi)])

    return fill
コード例 #23
0
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.
    Vertices in multiple faces get split up as necessary.
    """
    print_console('INFO', 'Extracting primitive: ' + blender_mesh.name)

    #
    # First, decide what attributes to gather (eg. how many COLOR_n, etc.)
    # Also calculate normals/tangents now if necessary.
    #

    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()

    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 export_settings[gltf2_blender_export_keys.TEX_COORDS]:
        if blender_mesh.uv_layers.active:
            tex_coord_max = len(blender_mesh.uv_layers)

    color_max = 0
    if export_settings[gltf2_blender_export_keys.COLORS]:
        color_max = len(blender_mesh.vertex_colors)

    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 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,
            ))


    use_materials = export_settings[gltf2_blender_export_keys.MATERIALS]

    #
    # Gather the verts and indices for each primitive.
    #

    prims = {}

    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 = []

        if len(blender_polygon.loop_indices) == 3:
            loop_index_list.extend(blender_polygon.loop_indices)
        elif len(blender_polygon.loop_indices) > 3:
            # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
            polyline = []

            for loop_index in blender_polygon.loop_indices:
                vertex_index = blender_mesh.loops[loop_index].vertex_index
                v = blender_mesh.vertices[vertex_index].co
                polyline.append(Vector((v[0], v[1], v[2])))

            triangles = tessellate_polygon((polyline,))

            for triangle in triangles:
                for triangle_index in triangle:
                    loop_index_list.append(blender_polygon.loop_indices[triangle_index])
        else:
            continue

        for loop_index in loop_index_list:
            vertex_index = blender_mesh.loops[loop_index].vertex_index
            vertex = blender_mesh.vertices[vertex_index]

            # vert will be a tuple of all the vertex attributes.
            # Used as cache key in prim.verts.
            vert = (vertex_index,)

            v = vertex.co
            vert += ((v[0], v[1], v[2]),)

            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 = face_normal
                    if use_tangents:
                        t = face_tangent
                        b = face_bitangent
                vert += ((n[0], n[1], n[2]),)
                if use_tangents:
                    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
                        try:
                            joint = group_to_joint[group_element.group]
                        except Exception:
                            continue
                        if joint is None:
                            continue
                        bones.append((joint, weight))
                bones.sort(key=lambda x: x[1], reverse=True)
                bones = tuple(bones)
                vert += (bones,)

            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:
                        normals = shape_key.vertex_normals
                        n_morph = Vector((
                            normals[vertex_index * 3 + 0],
                            normals[vertex_index * 3 + 1],
                            normals[vertex_index * 3 + 2],
                        ))
                    else:
                        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)

    #
    # Put the verts into attribute arrays.
    #

    result_primitives = []

    for material_idx, prim in prims.items():
        if not prim.indices:
            continue

        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:
                    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