C++ (DirectX 11)具有恒定场景内容更改的动态顶点/索引缓冲区实现

C++ (DirectX 11)具有恒定场景内容更改的动态顶点/索引缓冲区实现,c++,directx,directx-11,C++,Directx,Directx 11,我第一次深入研究了联合国管理的DirectX 11(请耐心听我说),有一个问题,尽管在论坛上被问了好几次,但仍然让我有很多问题 我正在开发一个应用程序,其中对象会随着时间的推移添加到场景中。在每个渲染循环中,我希望收集场景中的所有顶点,并重用单个顶点和索引缓冲区进行渲染,以获得性能和最佳实践。我的问题是关于动态顶点和索引缓冲区的使用。当场景内容发生变化时,我无法完全理解它们的正确用法 vertexBufferDescription.Usage = D3D11_USAG

我第一次深入研究了联合国管理的DirectX 11(请耐心听我说),有一个问题,尽管在论坛上被问了好几次,但仍然让我有很多问题

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

vertexBufferDescription.Usage               = D3D11_USAGE_DYNAMIC;
vertexBufferDescription.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDescription.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
vertexBufferDescription.MiscFlags           = 0;
vertexBufferDescription.StructureByteStride = 0;
我应该在场景初始化时创建缓冲区,并在每一帧中以某种方式更新它们的内容吗?如果是这样,我应该在缓冲区描述中设置什么字节大小?我应该用什么来初始化它

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

我一直在测试在第一次渲染场景时初始化缓冲区,然后在每个帧上使用贴图/取消贴图。我首先用所有场景对象填充向量列表,然后更新资源,如下所示:

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;
    }
我当前的实现导致整个场景闪烁。但是没有内存泄漏。不知道这是否与我使用Map/Unmap API的方式有关

另外,在这个场景中,什么时候调用buffer->Release()比较理想?
提示或代码样本将是伟大的!提前谢谢

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

memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));
sizeof(totalvertex)
只是询问std::vector的大小,这不是您想要的

请尝试以下代码:

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

另外,当isVertexBufferSet为true时,您似乎不会调用
IASetVertexBuffers
。一定要这样做。

将顶点复制到顶点缓冲区中,每个帧似乎效率很低,除非每个顶点都在更改每个帧,而这在大多数情况下似乎不太可能。创建一次缓冲区要正常得多。与此同时,我设法解决了闪烁的问题。memcpy错误,并且要复制的字节数传递不正确。它必须是sizeof(VERTEX)*totalvertexs.size()。@jcoder您是对的。我忘了提到我正在精确地控制场景的脏状态,以便在大多数情况下离开缓冲区。我只是不确定顶点/索引缓冲区是否不能在init()上创建,而不是在第一帧上创建,如代码示例中所示。
memcpy(resource.pData, &totalVertices[0], sizeof( VERTEX ) * totalVertices.size() );