Example #1
0
        public hkRootLevelContainer BuildNavmesh(BuildParams p, List <Vector3> verts, List <int> indices)
        {
            var root = new hkRootLevelContainer();

            NavMeshNative.SetNavmeshBuildParams(p.Cellsize, p.Cellheight, p.SlopeAngle, p.AgentHeight, p.AgentClimb, p.AgentRadius, p.MinRegionArea);
            var buildSuccess = NavMeshNative.BuildNavmeshForMesh(verts.ToArray(), verts.Count, indices.ToArray(), indices.Count);

            if (!buildSuccess)
            {
                return(null);
            }

            var vcount = NavMeshNative.GetMeshVertCount();
            var icount = NavMeshNative.GetMeshTriCount();

            if (vcount == 0 || icount == 0)
            {
                return(null);
            }

            ushort[]  bverts   = new ushort[vcount * 3];
            ushort[]  bindices = new ushort[icount * 3 * 2];
            Vector3[] vbverts  = new Vector3[vcount];
            NavMeshNative.GetMeshVerts(bverts);
            NavMeshNative.GetMeshTris(bindices);

            Vector3[] bounds = new Vector3[2];
            NavMeshNative.GetBoundingBox(bounds);

            var nmesh = new hkaiNavMesh();

            nmesh.m_aabb       = new hkAabb();
            nmesh.m_aabb.m_min = new Vector4(bounds[0].X, bounds[0].Y, bounds[0].Z, 1.0f);
            nmesh.m_aabb.m_max = new Vector4(bounds[1].X, bounds[1].Y, bounds[1].Z, 1.0f);

            nmesh.m_edgeData         = new List <int>();
            nmesh.m_edgeDataStriding = 1;
            nmesh.m_edges            = new List <hkaiNavMeshEdge>();
            nmesh.m_erosionRadius    = 0.0f;
            nmesh.m_faceData         = new List <int>();
            nmesh.m_faceDataStriding = 1;
            nmesh.m_faces            = new List <hkaiNavMeshFace>();
            nmesh.m_flags            = 0;
            nmesh.m_vertices         = new List <Vector4>();

            for (int i = 0; i < bverts.Length / 3; i++)
            {
                var vx = bverts[i * 3];
                var vy = bverts[i * 3 + 1];
                var vz = bverts[i * 3 + 2];

                var vert = new Vector3(bounds[0].X + (float)vx * p.Cellsize,
                                       bounds[0].Y + (float)vy * p.Cellheight,
                                       bounds[0].Z + (float)vz * p.Cellsize);
                nmesh.m_vertices.Add(new Vector4(vert.X, vert.Y, vert.Z, 1.0f));
                vbverts[i] = vert;
            }

            for (int t = 0; t < bindices.Length / 2; t += 3)
            {
                var f = new hkaiNavMeshFace();
                f.m_clusterIndex       = 0;
                f.m_numEdges           = 3;
                f.m_startEdgeIndex     = nmesh.m_edges.Count;
                f.m_startUserEdgeIndex = -1;
                f.m_padding            = 0xCDCD;
                nmesh.m_faces.Add(f);
                nmesh.m_faceData.Add(0);

                for (int i = 0; i < 3; i++)
                {
                    var e = new hkaiNavMeshEdge();
                    e.m_a     = bindices[t * 2 + i];
                    e.m_b     = bindices[t * 2 + ((i + 1) % 3)];
                    e.m_flags = 4;
                    // Record adjacency
                    if (bindices[t * 2 + 3 + i] == 0xFFFF)
                    {
                        // No adjacency
                        e.m_oppositeEdge = 0xFFFFFFFF;
                        e.m_oppositeFace = 0xFFFFFFFF;
                    }
                    else
                    {
                        e.m_oppositeFace = bindices[t * 2 + 3 + i];
                        // Find the edge that has this face as an adjancency
                        for (int j = 0; j < 3; j++)
                        {
                            var edge = bindices[t * 2 + 3 + i] * 6 + 3 + j;
                            if (bindices[edge] == (t / 3))
                            {
                                e.m_oppositeEdge = (uint)bindices[t * 2 + 3 + i] * 3 + (uint)j;
                            }
                        }
                    }
                    nmesh.m_edges.Add(e);
                    nmesh.m_edgeData.Add(0);
                }
            }

            root.m_namedVariants = new List <hkRootLevelContainerNamedVariant>();
            var variant = new hkRootLevelContainerNamedVariant();

            variant.m_className = "hkaiNavMesh";
            variant.m_name      = "hkaiNavMesh";
            variant.m_variant   = nmesh;
            root.m_namedVariants.Add(variant);

            // Next step: build a bvh
            var shortIndices = new ushort[bindices.Length / 2];

            for (int i = 0; i < bindices.Length / 2; i += 3)
            {
                shortIndices[i]     = bindices[i * 2];
                shortIndices[i + 1] = bindices[i * 2 + 1];
                shortIndices[i + 2] = bindices[i * 2 + 2];
            }
            bool didbuild = BVHNative.BuildBVHForMesh(vbverts, vbverts.Length, shortIndices, shortIndices.Length);

            if (!didbuild)
            {
                return(null);
            }

            var nodecount = BVHNative.GetBVHSize();
            var nsize     = BVHNative.GetNodeSize();
            var nodes     = new NativeBVHNode[nodecount];

            BVHNative.GetBVHNodes(nodes);

            // Rebuild in friendlier tree form
            List <BVNode> bnodes = new List <BVNode>((int)nodecount);

            foreach (var n in nodes)
            {
                var bnode = new BVNode();
                bnode.Min            = new Vector3(n.minX, n.minY, n.minZ);
                bnode.Max            = new Vector3(n.maxX, n.maxY, n.maxZ);
                bnode.IsLeaf         = n.isLeaf == 1;
                bnode.PrimitiveCount = n.primitiveCount;
                bnode.Primitive      = n.firstChildOrPrimitive;
                bnodes.Add(bnode);
            }
            for (int i = 0; i < nodes.Length; i++)
            {
                if (nodes[i].isLeaf == 0)
                {
                    bnodes[i].Left  = bnodes[(int)nodes[i].firstChildOrPrimitive];
                    bnodes[i].Right = bnodes[(int)nodes[i].firstChildOrPrimitive + 1];
                }
            }

            var bvhvariant = new hkRootLevelContainerNamedVariant();

            bvhvariant.m_className = "hkcdStaticAabbTree";
            bvhvariant.m_name      = "hkcdStaticAabbTree";
            var tree = new hkcdStaticAabbTree();

            bvhvariant.m_variant = tree;
            root.m_namedVariants.Add(bvhvariant);

            tree.m_treePtr         = new hkcdStaticTreeDefaultTreeStorage6();
            tree.m_treePtr.m_nodes = bnodes[0].BuildAxis6Tree();
            var min = bnodes[0].Min;
            var max = bnodes[0].Max;

            tree.m_treePtr.m_domain       = new hkAabb();
            tree.m_treePtr.m_domain.m_min = new Vector4(min.X, min.Y, min.Z, 1.0f);
            tree.m_treePtr.m_domain.m_max = new Vector4(max.X, max.Y, max.Z, 1.0f);

            // Build a dummy directed graph
            var gvariant = new hkRootLevelContainerNamedVariant();

            gvariant.m_className = "hkaiDirectedGraphExplicitCost";
            gvariant.m_name      = "hkaiDirectedGraphExplicitCost";
            var graph = new hkaiDirectedGraphExplicitCost();

            gvariant.m_variant = graph;
            root.m_namedVariants.Add(gvariant);

            graph.m_nodes = new List <hkaiDirectedGraphExplicitCostNode>();
            var node = new hkaiDirectedGraphExplicitCostNode();

            node.m_numEdges       = 0;
            node.m_startEdgeIndex = 0;
            graph.m_nodes.Add(node);

            graph.m_positions = new List <Vector4>();
            var c = (max - min) / 2;

            graph.m_positions.Add(new Vector4(c.X, c.Y, c.Z, 1.0f));

            return(root);
        }
        public void AddMesh(List <Vector3> verts, List <ushort> indices)
        {
            // Try and build the BVH for the mesh first
            var  bv       = verts.ToArray();
            var  bi       = indices.ToArray();
            bool didbuild = BVHNative.BuildBVHForMesh(bv, bv.Count(), bi, bi.Count());

            if (didbuild)
            {
                var nodecount = BVHNative.GetBVHSize();
                var nsize     = BVHNative.GetNodeSize();
                var nodes     = new NativeBVHNode[nodecount];
                BVHNative.GetBVHNodes(nodes);

                // Rebuild in friendlier tree form
                List <BVNode> bnodes = new List <BVNode>((int)nodecount);
                foreach (var n in nodes)
                {
                    var bnode = new BVNode();
                    bnode.Min            = new Vector3(n.minX, n.minY, n.minZ);
                    bnode.Max            = new Vector3(n.maxX, n.maxY, n.maxZ);
                    bnode.IsLeaf         = n.isLeaf == 1;
                    bnode.PrimitiveCount = n.primitiveCount;
                    bnode.Primitive      = n.firstChildOrPrimitive;
                    bnodes.Add(bnode);
                }
                for (int i = 0; i < nodes.Length; i++)
                {
                    if (nodes[i].isLeaf == 0)
                    {
                        bnodes[i].Left  = bnodes[(int)nodes[i].firstChildOrPrimitive];
                        bnodes[i].Right = bnodes[(int)nodes[i].firstChildOrPrimitive + 1];
                    }
                }

                // Split the mesh into sections using the BVH and primitive counts as
                // guidence
                bnodes[0].ComputePrimitiveCounts();
                bnodes[0].ComputeUniqueIndicesCounts(indices);
                bnodes[0].IsSectionHead = true;
                bnodes[0].AttemptSectionSplit();

                // Take out the section heads and replace them with new leafs that reference
                // the new section
                List <BVNode> sectionBVHs = new List <BVNode>();
                foreach (var node in bnodes)
                {
                    if (node.IsSectionHead)
                    {
                        var secnode = new BVNode();
                        secnode.Min            = node.Min;
                        secnode.Max            = node.Max;
                        secnode.PrimitiveCount = node.PrimitiveCount;
                        secnode.Left           = node.Left;
                        secnode.Right          = node.Right;
                        node.Left      = null;
                        node.Right     = null;
                        node.IsLeaf    = true;
                        node.Primitive = (uint)sectionBVHs.Count();
                        sectionBVHs.Add(secnode);
                    }
                }

                List <CollisionSection> sections = new List <CollisionSection>();
                foreach (var b in sectionBVHs)
                {
                    var s = new CollisionSection();
                    s.SectionHead = b;
                    s.GatherSectionIndices(indices);
                    sections.Add(s);
                }

                // Count all the indices across sections to figure out what vertices need to be shared
                byte[] indicescount = new byte[indices.Count];
                foreach (var s in sections)
                {
                    foreach (var v in s.UsedIndices)
                    {
                        indicescount[v]++;
                    }
                }
                var shared = new HashSet <ushort>();
                for (ushort i = 0; i < indices.Count(); i++)
                {
                    if (indicescount[i] > 1)
                    {
                        shared.Add(i);
                    }
                }

                // Build shared indices mapping table and compress the shared verts
                List <ulong> sharedVerts = new List <ulong>();
                Dictionary <ushort, ushort> sharedIndexRemapTable = new Dictionary <ushort, ushort>();
                foreach (var i in shared.OrderBy(x => x))
                {
                    sharedIndexRemapTable.Add(i, (ushort)sharedVerts.Count());
                    sharedVerts.Add(CompressSharedVertex(verts[i], bnodes[0].Min, bnodes[0].Max));
                }

                // build the havok mesh
                fsnpCustomParamCompressedMeshShape mesh = new fsnpCustomParamCompressedMeshShape();
                mesh.m_convexRadius   = 0.01f;
                mesh.m_dispatchType   = Enum.COMPOSITE;
                mesh.m_edgeWeldingMap = new hknpSparseCompactMapunsignedshort();
                mesh.m_edgeWeldingMap.m_primaryKeyToIndex     = null;
                mesh.m_edgeWeldingMap.m_secondaryKeyMask      = 0;
                mesh.m_edgeWeldingMap.m_sencondaryKeyBits     = 0;
                mesh.m_edgeWeldingMap.m_valueAndSecondaryKeys = null;
                mesh.m_quadIsFlat                             = new hkBitField();
                mesh.m_quadIsFlat.m_storage                   = new hkBitFieldStoragehkArrayunsignedinthkContainerHeapAllocator();
                mesh.m_quadIsFlat.m_storage.m_numBits         = 0;
                mesh.m_quadIsFlat.m_storage.m_words           = null;
                mesh.m_triangleIsInterior                     = new hkBitField();
                mesh.m_triangleIsInterior.m_storage           = new hkBitFieldStoragehkArrayunsignedinthkContainerHeapAllocator();
                mesh.m_triangleIsInterior.m_storage.m_numBits = 0;
                mesh.m_triangleIsInterior.m_storage.m_words   = null;
                mesh.m_triangleIndexToShapeKey                = null;
                mesh.m_pParam            = null;
                mesh.m_shapeTagCodecInfo = 4294967295;
                mesh.m_flags             = 516;
                mesh.m_numShapeKeyBits   = 5; // ?

                var meshdata = new hknpCompressedMeshShapeData();
                mesh.m_data = meshdata;

                var meshtree = new hknpCompressedMeshShapeTree();
                meshdata.m_meshTree       = meshtree;
                meshtree.m_bitsPerKey     = 5; // ?
                meshtree.m_domain         = new hkAabb();
                meshtree.m_domain.m_min   = new Vector4(bnodes[0].Min.X, bnodes[0].Min.Y, bnodes[0].Min.Z, 1.0f);
                meshtree.m_domain.m_max   = new Vector4(bnodes[0].Max.X, bnodes[0].Max.Y, bnodes[0].Max.Z, 1.0f);
                meshtree.m_maxKeyValue    = 30; // ?
                meshtree.m_nodes          = bnodes[0].BuildAxis5Tree();
                meshtree.m_sharedVertices = sharedVerts;

                var bvh = meshdata.getMeshBVH();

                // Now let's process all the sections
                meshtree.m_packedVertices      = new List <uint>();
                meshtree.m_primitiveDataRuns   = new List <hknpCompressedMeshShapeTreeDataRun>();
                meshtree.m_sharedVerticesIndex = new List <ushort>();
                meshtree.m_primitives          = new List <hkcdStaticMeshTreeBasePrimitive>();
                meshtree.m_sections            = new List <hkcdStaticMeshTreeBaseSection>();
                foreach (var s in sections)
                {
                    var sharedindexbase = meshtree.m_sharedVerticesIndex.Count;
                    var packedvertbase  = meshtree.m_packedVertices.Count;
                    var primitivesbase  = meshtree.m_primitives.Count;

                    var sec    = new hkcdStaticMeshTreeBaseSection();
                    var offset = s.SectionHead.Min;
                    var scale  = (s.SectionHead.Max - s.SectionHead.Min) / new Vector3((float)0x7FF, (float)0x7FF, (float)0x3FF);
                    sec.m_codecParms_0 = offset.X;
                    sec.m_codecParms_1 = offset.Y;
                    sec.m_codecParms_2 = offset.Z;
                    sec.m_codecParms_3 = scale.X;
                    sec.m_codecParms_4 = scale.Y;
                    sec.m_codecParms_5 = scale.Z;
                    sec.m_domain       = new hkAabb();
                    sec.m_domain.m_min = new Vector4(s.SectionHead.Min.X, s.SectionHead.Min.Y, s.SectionHead.Min.Z, 1.0f);
                    sec.m_domain.m_max = new Vector4(s.SectionHead.Max.X, s.SectionHead.Max.Y, s.SectionHead.Max.Z, 1.0f);

                    // Map the indices to either shared/packed verts and pack verts that need packing
                    var  packedIndicesRemap = new Dictionary <ushort, byte>();
                    byte idxcounter         = 0;
                    foreach (var idx in s.UsedIndices.OrderBy(x => x))
                    {
                        if (!shared.Contains(idx))
                        {
                            packedIndicesRemap.Add(idx, idxcounter);
                            var vert = verts[idx];
                            meshtree.m_packedVertices.Add(CompressPackedVertex(verts[idx], scale, offset));
                            var decomp = meshdata.DecompressPackedVertex(meshtree.m_packedVertices.Last(), scale, offset);
                            idxcounter++;
                        }
                    }
                    var sharedstart = idxcounter;
                    idxcounter = 0;
                    foreach (var idx in s.UsedIndices.OrderBy(x => x))
                    {
                        if (shared.Contains(idx))
                        {
                            packedIndicesRemap.Add(idx, (byte)(idxcounter + sharedstart));
                            meshtree.m_sharedVerticesIndex.Add(sharedIndexRemapTable[idx]);
                            idxcounter++;
                        }
                    }

                    sec.m_firstPackedVertex     = (uint)packedvertbase;
                    sec.m_numSharedIndices      = idxcounter;
                    sec.m_numPackedVertices     = sharedstart;
                    sec.m_sharedVertices        = new hkcdStaticMeshTreeBaseSectionSharedVertices();
                    sec.m_sharedVertices.m_data = (uint)(((uint)sharedstart & 0xFF) | ((uint)sharedindexbase << 8));

                    // Now pack the primitives
                    for (int i = 0; i < s.Indices.Count / 3; i++)
                    {
                        var p = new hkcdStaticMeshTreeBasePrimitive();
                        p.m_indices_0 = packedIndicesRemap[s.Indices[i * 3]];
                        p.m_indices_1 = packedIndicesRemap[s.Indices[i * 3 + 1]];
                        p.m_indices_2 = packedIndicesRemap[s.Indices[i * 3 + 2]];
                        p.m_indices_3 = p.m_indices_2;
                        meshtree.m_primitives.Add(p);
                    }
                    sec.m_primitives        = new hkcdStaticMeshTreeBaseSectionPrimitives();
                    sec.m_primitives.m_data = (((uint)s.Indices.Count / 3) & 0xFF) | ((uint)primitivesbase << 8);

                    // Create a data run
                    sec.m_dataRuns        = new hkcdStaticMeshTreeBaseSectionDataRuns();
                    sec.m_dataRuns.m_data = ((uint)meshtree.m_primitiveDataRuns.Count() << 8) | 1;
                    var run = new hknpCompressedMeshShapeTreeDataRun();
                    run.m_count        = (byte)(s.Indices.Count / 3);
                    run.m_index        = 0;
                    run.m_value        = new hknpCompressedMeshShapeTreeDataRunData();
                    run.m_value.m_data = 65535;
                    meshtree.m_primitiveDataRuns.Add(run);

                    sec.m_nodes = s.SectionHead.BuildAxis4Tree();

                    meshtree.m_sections.Add(sec);
                }

                meshtree.m_numPrimitiveKeys = meshtree.m_primitives.Count;

                var simdtree = new hkcdSimdTree();
                meshdata.m_simdTree = simdtree;
                simdtree.m_nodes    = new List <hkcdSimdTreeNode>();
                for (int i = 0; i < 2; i++)
                {
                    hkcdSimdTreeNode n = new hkcdSimdTreeNode();
                    n.m_data_0 = 0;
                    n.m_data_1 = 0;
                    n.m_data_2 = 0;
                    n.m_data_3 = 0;
                    float mi = -3.40282E+38F;
                    float ma = 3.40282E+38F;
                    n.m_hx = new Vector4(mi, mi, mi, mi);
                    n.m_hy = new Vector4(mi, mi, mi, mi);
                    n.m_hz = new Vector4(mi, mi, mi, mi);
                    n.m_lx = new Vector4(ma, ma, ma, ma);
                    n.m_ly = new Vector4(ma, ma, ma, ma);
                    n.m_lz = new Vector4(ma, ma, ma, ma);
                    simdtree.m_nodes.Add(n);
                }

                _meshes.Add(mesh);
            }
        }