(DirectX 11)动态顶点/索引缓冲区实现,具有不断的场景内容更改

时间:2013-03-20 23:26:42

标签: c++ directx directx-11

第一次钻研未经管理的DirectX 11(请跟我一起)并且有一个问题,虽然在论坛上多次询问仍然让我有问题。

我正在开发app,随着时间的推移将对象添加到场景中。在每个渲染循环中,我想收集场景中的所有顶点,并渲染它们重用单个顶点和索引缓冲区以获得性能和最佳实践。我的问题是关于动态顶点和索引缓冲区的使用。当场景内容发生变化时,我无法完全理解它们的正确用法。

vertexBufferDescription.Usage               = D3D11_USAGE_DYNAMIC;
vertexBufferDescription.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDescription.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
vertexBufferDescription.MiscFlags           = 0;
vertexBufferDescription.StructureByteStride = 0;

我应该在场景初始化时创建缓冲区并以某种方式在每个帧中更新它们的内容吗?如果是这样,我应该在缓冲区描述中设置什么ByteSize?我用什么来初始化它?

或者,我是否应该在第一次使用当前顶点计数作为其大小渲染场景(第1帧)时创建它?如果是这样,当我向场景添加另一个对象时,我不需要重新创建缓冲区并将缓冲区描述的ByteWidth更改为新的顶点计数吗?如果我的场景不断更新每个帧的顶点,那么单个动态缓冲区的使用会以这种方式失去其目的......

我一直在测试渲染场景时初始化缓冲区,并从那里开始,在每个帧上使用Map / Unmap。我首先填写一个包含所有场景对象的矢量列表,然后像这样更新资源:

void Scene::Render() 
{
    (...)

    std::vector<VERTEX> totalVertices;
    std::vector<int> totalIndices;
    int totalVertexCount = 0;
    int totalIndexCount = 0;

    for (shapeIterator = models.begin(); shapeIterator != models.end(); ++shapeIterator)
    {
            Model* currentModel = (*shapeIterator);

            // totalVertices gets filled here...
    }

     // At this point totalVertices and totalIndices have all scene data

    if (isVertexBufferSet)
    {
        // This is where it copies the new vertices to the buffer.
        // but it's causing flickering in the entire screen...
        D3D11_MAPPED_SUBRESOURCE resource;
        context->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
        memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));
        context->Unmap(vertexBuffer, 0);
    }
    else
    {
        // This is run in the first frame. But what if new vertices are added to the scene?
        vertexBufferDescription.ByteWidth = sizeof(VERTEX) * totalVertexCount;
        UINT stride = sizeof(VERTEX);
        UINT offset = 0;

        D3D11_SUBRESOURCE_DATA resourceData;
        ZeroMemory(&resourceData, sizeof(resourceData));
        resourceData.pSysMem = &totalVertices[0];

        device->CreateBuffer(&vertexBufferDescription, &resourceData, &vertexBuffer);
        context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
        isVertexBufferSet = true;
    }

在渲染循环结束时,在跟踪每个对象的顶点的缓冲区位置的同时,我最终调用了Draw():

    context->Draw(objectVertexCount, currentVertexOffset);
}

我当前的实现导致整个场景闪烁。但没有内存泄漏。不知道它与我使用Map / Unmap API的方式有什么关系吗?

此外,在这种情况下,何时调用buffer-&gt; Release()是理想的? 提示或代码示例会很棒!提前谢谢!

1 个答案:

答案 0 :(得分:3)

在进入顶点缓冲区的memcpy中,执行以下操作:

memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));

sizeof( totalVertices )只是要求std :: vector&lt;的大小。 VERTEX&gt;这不是你想要的。

请尝试以下代码:

memcpy(resource.pData, &totalVertices[0], sizeof( VERTEX ) * totalVertices.size() );

当isVertexBufferSet为true时,您似乎不会调用IASetVertexBuffers。确保你这样做。