""" Blender's GLTF exporter does some splitting of blender verts based on loops i.e in my case a mesh with 386 verts ends up with 441 verts after gltf export. As explained at https://blender.stackexchange.com/questions/167372/gltf-export-has-twice-the-vertices-it-should glTF is a last mile format and stores mesh data in a "Ready to load on GPU" state. This script basically predetermines how the export will split the vertices and produces all the vertex indices that will exist in the final gltf data. XXX Caution This script only considers the influence of the UVs (which is unique to my use case). If you are exporting other attributes such as normals and tangents please add the necessary `dot_fields` and `dot` data as has been done at https://git.blender.org/gitweb/gitweb.cgi/blender-addons.git/blob/HEAD:/io_scene_gltf2/blender/exp/gltf2_blender_extract.py in the `extract_primitives` function. """ import bpy import bmesh import numpy as np def get_gltf_export_indices(obj): def __get_uvs(blender_mesh, uv_i): layer = blender_mesh.uv_layers[uv_i] uvs = np.empty(len(blender_mesh.loops) * 2, dtype=np.float32) layer.data.foreach_get('uv', uvs) uvs = uvs.reshape(len(blender_mesh.loops), 2) # Blender UV space -> glTF UV space # u,v -> u,1-v uvs[:, 1] *= -1 uvs[:, 1] += 1 return uvs # Get the active mesh me = obj.data tex_coord_max = len(me.uv_layers) dot_fields = [('vertex_index', np.uint32)] for uv_i in range(tex_coord_max): dot_fields += [('uv%dx' % uv_i, np.float32), ('uv%dy' % uv_i, np.float32)] dots = np.empty(len(me.loops), dtype=np.dtype(dot_fields)) vidxs = np.empty(len(me.loops)) me.loops.foreach_get('vertex_index', vidxs) dots['vertex_index'] = vidxs del vidxs for uv_i in range(tex_coord_max): uvs = __get_uvs(me, uv_i) dots['uv%dx' % uv_i] = uvs[:, 0] dots['uv%dy' % uv_i] = uvs[:, 1] del uvs # Calculate triangles and sort them into primitives. me.calc_loop_triangles() loop_indices = np.empty(len(me.loop_triangles) * 3, dtype=np.uint32) me.loop_triangles.foreach_get('loops', loop_indices) prim_indices = {} # maps material index to TRIANGLES-style indices into dots # Bucket by material index. tri_material_idxs = np.empty(len(me.loop_triangles), dtype=np.uint32) me.loop_triangles.foreach_get('material_index', tri_material_idxs) loop_material_idxs = np.repeat(tri_material_idxs, 3) # material index for every loop unique_material_idxs = np.unique(tri_material_idxs) del tri_material_idxs for material_idx in unique_material_idxs: prim_indices[material_idx] = loop_indices[loop_material_idxs == material_idx] prim_dots = dots[prim_indices[0]] prim_dots, indices = np.unique(prim_dots, return_inverse=True) result = [d[0] for d in prim_dots] return result get_gltf_export_indices(bpy.context.object)