从SharpDX工具箱模型中提取顶点和三角形数据

本文关键字:顶点 三角形 数据 提取 SharpDX 工具箱 模型 | 更新日期: 2023-09-27 18:24:52

我正在使用SharpDX 2.6加载的模型创建凸包和三角形网格。

我找到了一些从模型中提取顶点和索引的示例代码,但它们是基于XNA和(似乎是)DirectX 9的——我的程序使用的是带有DirectX 11的SharpDX(和SharpDX工具包,所以很多东西都与XNA相似)。

我发现的提取顶点和索引(作为三角形)的代码:

public void ExtractData(List<JVector> vertices, List<JOctree.TriangleVertexIndices> indices, Model model)
    {
        Matrix[] bones_ = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(bones_);
        foreach (ModelMesh mm in model.Meshes)
        {
            Matrix xform = bones_[mm.ParentBone.Index];
            foreach (ModelMeshPart mmp in mm.MeshParts)
            {
                int offset = vertices.Count;
                Vector3[] a = new Vector3[mmp.NumVertices];
                mm.VertexBuffer.GetData<Vector3>(mmp.StreamOffset + mmp.BaseVertex * mmp.VertexStride,
                    a, 0, mmp.NumVertices, mmp.VertexStride);
                for (int i = 0; i != a.Length; ++i)
                    Vector3.Transform(ref a[i], ref xform, out a[i]);
                for (int i = 0; i < a.Length; i++) vertices.Add(new JVector(a[i].X, a[i].Y, a[i].Z));
                if (mm.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
                    throw new Exception(
                        String.Format("Model uses 32-bit indices, which are not supported."));
                short[] s = new short[mmp.PrimitiveCount * 3];
                mm.IndexBuffer.GetData<short>(mmp.StartIndex * 2, s, 0, mmp.PrimitiveCount * 3);
                JOctree.TriangleVertexIndices[] tvi = new JOctree.TriangleVertexIndices[mmp.PrimitiveCount];
                for (int i = 0; i != tvi.Length; ++i)
                {
                    tvi[i].I0 = s[i * 3 + 2] + offset;
                    tvi[i].I1 = s[i * 3 + 1] + offset;
                    tvi[i].I2 = s[i * 3 + 0] + offset;
                }
                indices.AddRange(tvi);
            }
        }
    }

以下是我能够将其重新制作成的内容(对于使用SharpDX工具包的DirectX 11):我已经将其概括为简单地从模型中构建八叉树,但管道的主要部分仍然是一样的。

    public static Octree BuildOctree(Model model) {
        List<JVector> vertices = new List<JVector>();
        List<TriangleVertexIndices> indices = new List<TriangleVertexIndices>();           
        Matrix[] bones = new Matrix[model.Bones.Count];
        model.CopyAbsoluteBoneTransformsTo(bones);   
        foreach (ModelMesh modelMesh in model.Meshes)
        {               
            JMatrix boneTransform = PhysicsSystem.toJMatrix(bones[modelMesh.ParentBone.Index]);
            foreach (ModelMeshPart meshPart in modelMesh.MeshParts)
            {
                int offset = vertices.Count;              
                var meshVertices = meshPart.VertexBuffer.Resource.Buffer.GetData<JVector>();
                for (int i = 0; i < meshVertices.Length; ++i)
                {
                    JVector.Transform(ref meshVertices[i], ref boneTransform, out meshVertices[i]);
                }
                vertices.AddRange(meshVertices);    // append transformed vertices
                var indexElements = meshPart.IndexBuffer.Resource.GetData<short>(); // this is dangerous if the model uses larger integers
                // Each TriangleVertexIndices holds the indices that constitute a triangle primitive
                TriangleVertexIndices[] tvi = new TriangleVertexIndices[indexElements.Length];
                for (int i = 0; i <= tvi.Length - 2; i += 3) {
                    tvi[i].I0 = indexElements[i + 0] + offset;
                    tvi[i].I1 = indexElements[i + 1] + offset;
                    tvi[i].I2 = indexElements[i + 2] + offset;
                }
                indices.AddRange(tvi);  // append triangles           
            }
        }
        Octree ot = new Octree(vertices, indices);
        //ot.BuildOctree(); // (already happens in Octree constructor)
        return ot;
    }

我使用这个代码的变体(没有三角形计算,只有顶点)以类似的方式创建凸包形状。

我的问题是:有什么方法可以改进这个代码吗?

这个代码是否正确/是否有您立即认为可能错误的地方?

当我使用这种方法从盒子的模型中提取顶点时(与Jitter教程中使用的方法相同),我得到的表示不是一个形状网格细节分布不均匀的长方体,这比使用内置的BoxShape基本体更能减缓碰撞(使用BoxShape时为60fps平面,使用单个长方体与静态TerrainShape碰撞时为20-30帧)。为什么会出现这种情况?

我觉得,虽然我对代码的重写产生了一些输出,但感觉一点也不优化。

从SharpDX工具箱模型中提取顶点和三角形数据

不幸的是,您无法轻松提取数据。顶点缓冲区中的元素可能因模型顶点结构而异(请参阅编译器代码,可以有Vector4Vector3Vector2甚至16位)。

要正确解码它,您需要在运行时访问布局并使用它解码顶点缓冲区。