public static unsafe BlobAssetReference <Collider> Create(NativeArray <float3> vertices, NativeArray <int3> triangles, CollisionFilter filter, Material material)
        {
            // Copy vertices
            var tempVertices = new NativeArray <float3>(vertices, Allocator.Temp);

            // Triangle indices - needed for WeldVertices
            var tempIndices = new NativeArray <int>(triangles.Length * 3, Allocator.Temp);

            for (int iTriangle = 0; iTriangle < triangles.Length; iTriangle++)
            {
                if (triangles[iTriangle][0] >= 0 && triangles[iTriangle][0] < vertices.Length &&
                    triangles[iTriangle][1] >= 0 && triangles[iTriangle][1] < vertices.Length &&
                    triangles[iTriangle][2] >= 0 && triangles[iTriangle][2] < vertices.Length)
                {
                    tempIndices[iTriangle * 3]     = triangles[iTriangle][0];
                    tempIndices[iTriangle * 3 + 1] = triangles[iTriangle][1];
                    tempIndices[iTriangle * 3 + 2] = triangles[iTriangle][2];
                }
                else
                {
                    throw new ArgumentException("Tried to create a MeshCollider with indices referencing outside vertex array");
                }
            }

            // Build connectivity and primitives

            NativeList <float3> uniqueVertices = MeshConnectivityBuilder.WeldVertices(tempIndices, tempVertices);

            var tempTriangleIndices = new NativeArray <int3>(triangles.Length, Allocator.Temp);

            UnsafeUtility.MemCpy(tempTriangleIndices.GetUnsafePtr(), tempIndices.GetUnsafePtr(), tempIndices.Length * UnsafeUtility.SizeOf <int>());

            var connectivity = new MeshConnectivityBuilder(tempTriangleIndices, uniqueVertices);
            NativeList <MeshConnectivityBuilder.Primitive> primitives = connectivity.EnumerateQuadDominantGeometry(tempTriangleIndices, uniqueVertices);

            // Build bounding volume hierarchy
            int nodeCount = math.max(primitives.Length * 2 + 1, 2); // We need at least two nodes - an "invalid" node and a root node.
            var nodes     = new NativeArray <BoundingVolumeHierarchy.Node>(nodeCount, Allocator.Temp);
            int numNodes  = 0;

            {
                // Prepare data for BVH
                var points = new NativeList <BoundingVolumeHierarchy.PointAndIndex>(primitives.Length, Allocator.Temp);
                var aabbs  = new NativeArray <Aabb>(primitives.Length, Allocator.Temp);

                for (int i = 0; i < primitives.Length; i++)
                {
                    MeshConnectivityBuilder.Primitive p = primitives[i];

                    // Skip degenerate triangles
                    if (MeshConnectivityBuilder.IsTriangleDegenerate(p.Vertices[0], p.Vertices[1], p.Vertices[2]))
                    {
                        continue;
                    }

                    aabbs[i] = Aabb.CreateFromPoints(p.Vertices);
                    points.Add(new BoundingVolumeHierarchy.PointAndIndex
                    {
                        Position = aabbs[i].Center,
                        Index    = i
                    });
                }

                var bvh = new BoundingVolumeHierarchy(nodes);

                bvh.Build(points.AsArray(), aabbs, out numNodes, useSah: true);
            }

            // Build mesh sections
            BoundingVolumeHierarchy.Node *nodesPtr = (BoundingVolumeHierarchy.Node *)nodes.GetUnsafePtr();
            MeshBuilder.TempSection       sections = MeshBuilder.BuildSections(nodesPtr, numNodes, primitives);

            // Allocate collider
            int meshDataSize      = Mesh.CalculateMeshDataSize(numNodes, sections.Ranges);
            int totalColliderSize = Math.NextMultipleOf(sizeof(MeshCollider), 16) + meshDataSize;

            MeshCollider *meshCollider = (MeshCollider *)UnsafeUtility.Malloc(totalColliderSize, 16, Allocator.Temp);

            // Initialize it
            {
                UnsafeUtility.MemClear(meshCollider, totalColliderSize);
                meshCollider->MemorySize = totalColliderSize;

                meshCollider->m_Header.Type          = ColliderType.Mesh;
                meshCollider->m_Header.CollisionType = CollisionType.Composite;
                meshCollider->m_Header.Version      += 1;
                meshCollider->m_Header.Magic         = 0xff;

                ref var mesh = ref meshCollider->Mesh;

                mesh.Init(nodesPtr, numNodes, sections, filter, material);

                // Calculate combined filter
                meshCollider->m_Header.Filter = mesh.Sections.Length > 0 ? mesh.Sections[0].Filters[0] : CollisionFilter.Default;
                for (int i = 0; i < mesh.Sections.Length; ++i)
                {
                    for (var j = 0; j < mesh.Sections[i].Filters.Length; ++j)
                    {
                        var f = mesh.Sections[i].Filters[j];
                        meshCollider->m_Header.Filter = CollisionFilter.CreateUnion(meshCollider->m_Header.Filter, f);
                    }
                }

                meshCollider->m_Aabb             = meshCollider->Mesh.BoundingVolumeHierarchy.Domain;
                meshCollider->NumColliderKeyBits = meshCollider->Mesh.NumColliderKeyBits;
            }
        // followed by variable sized mesh data

        #region Construction

        // Create a mesh collider asset from a set of triangles
        public static unsafe BlobAssetReference <Collider> Create(float3[] vertices, int[] indices, CollisionFilter?filter = null, Material?material = null)
        {
            int numVertices  = vertices.Length;
            int numIndices   = indices.Length;
            int numTriangles = numIndices / 3;

            // Copy vertices
            float3[] tempVertices = new float3[numVertices];
            Array.Copy(vertices, tempVertices, numVertices);

            // Copy indices
            int[] tempIndices = new int[numIndices];
            for (int iTriangle = 0; iTriangle < numTriangles; iTriangle++)
            {
                int iIndex0 = iTriangle * 3;
                int iIndex1 = iIndex0 + 1;
                int iIndex2 = iIndex0 + 2;
                tempIndices[iIndex0] = indices[iIndex0];
                tempIndices[iIndex1] = indices[iIndex1];
                tempIndices[iIndex2] = indices[iIndex2];
            }

            // Build connectivity and primitives
            List <MeshConnectivityBuilder.Primitive> primitives = null;
            {
                MeshConnectivityBuilder.WeldVertices(tempIndices, ref tempVertices);
                var connectivity = new MeshConnectivityBuilder(tempIndices, tempVertices);
                primitives = connectivity.EnumerateQuadDominantGeometry(tempIndices, tempVertices);
            }

            // Build bounding volume hierarchy
            var nodes    = new NativeArray <BoundingVolumeHierarchy.Node>(primitives.Count * 2 + 1, Allocator.Temp);
            int numNodes = 0;

            {
                // Prepare data for BVH
                var points = new NativeArray <BoundingVolumeHierarchy.PointAndIndex>(primitives.Count, Allocator.Temp);
                var aabbs  = new NativeArray <Aabb>(primitives.Count, Allocator.Temp);

                for (int i = 0; i < primitives.Count; i++)
                {
                    MeshConnectivityBuilder.Primitive p = primitives[i];

                    // Skip degenerate triangles
                    if (MeshConnectivityBuilder.IsTriangleDegenerate(p.Vertices[0], p.Vertices[1], p.Vertices[2]))
                    {
                        continue;
                    }

                    aabbs[i]  = Aabb.CreateFromPoints(p.Vertices);
                    points[i] = new BoundingVolumeHierarchy.PointAndIndex
                    {
                        Position = aabbs[i].Center,
                        Index    = i
                    };
                }

                var bvh = new BoundingVolumeHierarchy(nodes);
                bvh.Build(points, aabbs, out numNodes, useSah: true);

                points.Dispose();
                aabbs.Dispose();
            }

            // Build mesh sections
            BoundingVolumeHierarchy.Node * nodesPtr = (BoundingVolumeHierarchy.Node *)nodes.GetUnsafePtr();
            List <MeshBuilder.TempSection> sections = MeshBuilder.BuildSections(nodesPtr, numNodes, primitives);

            // Allocate collider
            int           meshDataSize      = Mesh.CalculateMeshDataSize(numNodes, sections);
            int           totalColliderSize = Math.NextMultipleOf(sizeof(MeshCollider), 16) + meshDataSize;
            MeshCollider *meshCollider      = (MeshCollider *)UnsafeUtility.Malloc(totalColliderSize, 16, Allocator.Temp);

            // Initialize it
            {
                UnsafeUtility.MemClear(meshCollider, totalColliderSize);
                meshCollider->MemorySize = totalColliderSize;

                meshCollider->m_Header.Type          = ColliderType.Mesh;
                meshCollider->m_Header.CollisionType = CollisionType.Composite;
                meshCollider->m_Header.Version      += 1;
                meshCollider->m_Header.Magic         = 0xff;

                ref var mesh = ref meshCollider->Mesh;

                mesh.Init(nodesPtr, numNodes, sections, filter ?? CollisionFilter.Default, material ?? Material.Default);

                // Calculate combined filter
                meshCollider->m_Header.Filter = mesh.Sections[0].Filters[0];
                for (int i = 0; i < mesh.Sections.Length; ++i)
                {
                    foreach (CollisionFilter f in mesh.Sections[i].Filters)
                    {
                        meshCollider->m_Header.Filter = CollisionFilter.CreateUnion(meshCollider->m_Header.Filter, f);
                    }
                }

                meshCollider->m_Aabb             = meshCollider->Mesh.BoundingVolumeHierarchy.Domain;
                meshCollider->NumColliderKeyBits = meshCollider->Mesh.NumColliderKeyBits;
            }