从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帧)。为什么会出现这种情况?
我觉得,虽然我对代码的重写产生了一些输出,但感觉一点也不优化。
不幸的是,您无法轻松提取数据。顶点缓冲区中的元素可能因模型顶点结构而异(请参阅编译器代码,可以有Vector4
、Vector3
、Vector2
甚至16位)。
要正确解码它,您需要在运行时访问布局并使用它解码顶点缓冲区。