简体   繁体   English

在“使用DirectX 11进行3D游戏编程介绍”一书的示例代码中

[英]In an example code of the book “introduction to 3d game programming with directx 11”

void GeometryGenerator::Subdivide(MeshData& meshData)
{
    // Save a copy of the input geometry.
    MeshData inputCopy = meshData;


    meshData.Vertices.resize(0);
    meshData.Indices.resize(0);

    //       v1
    //       *
    //      / \
    //     /   \
    //  m0*-----*m1
    //   / \   / \
    //  /   \ /   \
    // *-----*-----*
    // v0    m2     v2

    UINT numTris = inputCopy.Indices.size()/3;
    for(UINT i = 0; i < numTris; ++i)
    {
        Vertex v0 = inputCopy.Vertices[ inputCopy.Indices[i*3+0] ];
        Vertex v1 = inputCopy.Vertices[ inputCopy.Indices[i*3+1] ];
        Vertex v2 = inputCopy.Vertices[ inputCopy.Indices[i*3+2] ];

        //
        // Generate the midpoints.
        //

        Vertex m0, m1, m2;

        // For subdivision, we just care about the position component.  We 
        // derive the other
        // vertex components in CreateGeosphere.

        m0.Position = XMFLOAT3(
            0.5f*(v0.Position.x + v1.Position.x),
            0.5f*(v0.Position.y + v1.Position.y),
            0.5f*(v0.Position.z + v1.Position.z));

        m1.Position = XMFLOAT3(
            0.5f*(v1.Position.x + v2.Position.x),
            0.5f*(v1.Position.y + v2.Position.y),
            0.5f*(v1.Position.z + v2.Position.z));

        m2.Position = XMFLOAT3(
            0.5f*(v0.Position.x + v2.Position.x),
            0.5f*(v0.Position.y + v2.Position.y),
            0.5f*(v0.Position.z + v2.Position.z));

        //
        // Add new geometry.
        //

        meshData.Vertices.push_back(v0); // 0
        meshData.Vertices.push_back(v1); // 1
        meshData.Vertices.push_back(v2); // 2
        meshData.Vertices.push_back(m0); // 3
        meshData.Vertices.push_back(m1); // 4
        meshData.Vertices.push_back(m2); // 5

        meshData.Indices.push_back(i*6+0);
        meshData.Indices.push_back(i*6+3);
        meshData.Indices.push_back(i*6+5);

        meshData.Indices.push_back(i*6+3);
        meshData.Indices.push_back(i*6+4);
        meshData.Indices.push_back(i*6+5);

        meshData.Indices.push_back(i*6+5);
        meshData.Indices.push_back(i*6+4);
        meshData.Indices.push_back(i*6+2);

        meshData.Indices.push_back(i*6+3);
        meshData.Indices.push_back(i*6+1);
        meshData.Indices.push_back(i*6+4);
    }
}

This function is in 'GeometryGenerator.cpp' file and does subdivide a mesh. 此函数在'GeometryGenerator.cpp'文件中,并且可以细分网格。 Before this fuction is called, a icosahedron is created and transmitted as the parameter meshData. 在调用此功能之前,将创建一个二十面体并将其作为参数meshData进行传输。 The members of MeshData, Vertices and Indices, are vectors of STL. MeshData,顶点和索引的成员是STL的向量。

In my opinion, after this function calls those series of functions, meshData.Vertices.push_back, in the next iteration of the loop some of vertices may be repeatedly stored. 在我看来,在此函数调用了一系列函数meshData.Vertices.push_back之后,在循环的下一次迭代中,可能会重复存储一些顶点。

Anyone could answer 任何人都可以回答

  • whether I am wrong, 我是否有错
  • why the author make the codes like this, 为什么作者编写这样的代码,
  • or whether there is more efficient way if my thought is right. 或者如果我的想法正确,是否有更有效的方法。

Thank you all who read my poor English. 谢谢所有读我英语不好的人。

  • If there is another triangle adjacent to v1 - v2 side then v1, v2 and m1 will be added twice and so on. 如果在v1-v2边附近还有另一个三角形,则将v1,v2和m1相加两次,依此类推。
  • Who knows? 谁知道? Maybe there is an extra deduplication pass after this. 在此之后,也许还有额外的重复数据删除通道。
  • It is possible to perform this on GPU using either geometry shader or straight tessellation. 可以使用几何着色器或直线细分在GPU上执行此操作。 See this example . 请参阅此示例

whether I am wrong 我是否错

I am pretty sure you are right , especially about the duplicated vertices! 我很确定你是对的 ,尤其是关于重复的顶点!

why the author make the codes like this 为什么作者制作这样的代码

No one can answer this except the author himself. 除了作者本人之外,没有人可以回答这个问题。 I would guess that he/she simply oversaw the duplication problem... 他/她只是监督了重复问题...

or whether there is more efficient way if my thought is right. 或者如果我的想法正确,是否有更有效的方法。

I would not care for efficency as long as the algorithm is not correct ! 只要算法不正确,我就不会在乎效率!

First, we need to avoid vertex duplication. 首先,我们需要避免顶点重复。 I simply would leave the existing vertices as are (thus only clear the indices) and append the new ones at the end. 我只是将现有的顶点保持不变(因此仅clear索引),并在最后附加新的顶点。 For this purpose, I would store the edges in a temporary std::map, mapping a pair of indices (the edge) to the newly created index (always smaller index first to avoid problems with (10,12) vs. (12,10) , which identify the same edge...). 为此,我将边缘存储在临时std :: map中,将一对索引(边缘)映射到新创建的索引(始终先使用较小的索引,以避免(10,12)(12,10) ,它标识同一条边...)。

Then for v0, v1, v2, I'd use the indices, not the vertices themselves. 然后对于v0,v1,v2,我将使用索引,而不是顶点本身。 m0, m1, m2 are looked up in the map first, if found, use, otherwise, create a new vertex, add it to the vertices vector and add an entry in our map. 首先在地图上查找m0,m1,m2,如果找到,请使用,否则,创建一个新顶点,将其添加到顶点向量中,然后在我们的地图中添加一个条目。

UINT v0 = copiedIndices[i*3+0];
// ...

UINT m0;
auto key = std::make_pair(v0, v1); // TODO: order indices!!!
auto entry = myMap.find(key); 
if(entry != myMap.end())
{
    m0 = entry->second;
}
else
{
    meshData.Vertices.push_back(newVertex);
    m0 = meshData.Vertices.size() - 1;
    myMap.insert(key, m0);
}

Then you will add your new triangles, just take the indices as are: 然后,您将添加新的三角形,只需按原样使用索引:

meshdata.indices.pushback(v0); // one of the original indices
meshdata.indices.pushback(m0); // one of the new ones
meshdata.indices.pushback(m2);

// ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM