Извлечение данных вершин и треугольников из модели инструментария SharpDX

Я работаю над созданием выпуклых оболочек и треугольных сеток из моделей, загруженных с SharpDX 2.6.

Я нашел несколько примеров кода для извлечения вершин и индексов из модели, но они основаны на XNA и (как представляется,) DirectX 9 - моя программа использует SharpDX с DirectX 11 (и инструментарием 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);
            }
        }
    }

Вот что мне удалось переработать (для DirectX 11 с простотой набора инструментов SharpDX): я обобщил это, чтобы просто построить октодерево из модели, но основной кусок конвейера остается тем же.

    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, ~20-30 при использовании одного блока, сталкивающегося со статическим TerrainShape). Почему это может быть так?

Я чувствую, что, хотя мое переписывание кода приводит к некоторому выводу, оно вообще не кажется оптимальным.

1 ответ

К сожалению, вы не можете легко извлечь данные. Элементы в буфере вершин могут различаться в зависимости от структуры вершины модели (см. Код компилятора, вы можете иметь Vector4, Vector3, Vector2 или даже 16 бит).

Чтобы правильно его декодировать, вам нужно получить доступ к макету во время выполнения и декодировать буфер вершин вместе с ним.

Другие вопросы по тегам