Извлечение данных вершин и треугольников из модели инструментария 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 бит).
Чтобы правильно его декодировать, вам нужно получить доступ к макету во время выполнения и декодировать буфер вершин вместе с ним.