Как упоминалось в предыдущем ответе, вы обновляете весь буфер каждый раз, что будет медленно в зависимости от размера модели.
Решение действительно заключается в том, чтобы реализовать частичные обновления, для этого есть две возможности: Вы хотите обновить одну вершину, или вы хотите обновить произвольные индексы (например, вы хотите переместить N вершин в одну go, в разные места, например, в вершину 1,20,23.
Первое решение довольно простое, сначала создайте свой буфер со следующим описанием:
Usage = D3D11_USAGE_DEFAULT;
CPUAccessFlags = 0;
BindFlags = D3D11_BIND_VERTEX_BUFFER;
ByteWidth = sizeof(ST_Vertex) * _nVertexCount
D3D11_SUBRESOURCE_DATA d3dBufferData;
d3dBufferData.pSysMem = pVerticesInfo;
hr = pd3dDevice->CreateBuffer(&descBuffer, &d3dBufferData, &_pVertexBuffer);
Это гарантирует, что ваш буфер вершин доступен только для gpu.
Далее создайте вторую динамику c буфер, имеющий размер одной вершины (в этом случае вам не нужны никакие флаги связывания, поскольку он будет использоваться только для копий)
_pCopyVertexBuffer
Usage = D3D11_USAGE_DYNAMIC; //Staging works as well
CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
BindFlags = 0;
ByteWidth = sizeof(ST_Vertex);
D3D11_SUBRESOURCE_DATA d3dBufferData;
d3dBufferData.pSysMem = NULL;
hr = pd3dDevice->CreateBuffer(&descBuffer, &d3dBufferData, &_pCopyVertexBuffer);
when you move a vertex, copy the changed vertex in the copy buffer :
ST_Vertex changedVertex;
D3D11_MAPPED_SUBRESOURCE d3dMappedResource;
pImmediateContext->Map(_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &d3dMappedResource);
ST_Vertex* pBuffer = (ST_Vertex*)d3dMappedResource.pData;
pBuffer->xfPosition.x = changedVertex.xfPosition.x;
pBuffer->.xfPosition.y = changedVertex.xfPosition.y;
pBuffer->.xfPosition.z = changedVertex.xfPosition.z;
pImmediateContext->Unmap(_pVertexBuffer, 0);
Поскольку вы используете D3D11_MAP_WRITE_DISCARD, обязательно запишите все Атрибуты там (не только положение).
Теперь, когда вы сделали, вы можете использовать ID3D11DeviceContext :: CopySubresourceRegion для только скопируйте измененную вершину в текущем местоположении:
Я предполагаю, что vertexID является индексом измененной вершины:
pd3DeviceContext->CopySubresourceRegion(_pVertexBuffer,
0, //must be 0
vertexID * sizeof(ST_Vertex), //location of the vertex in you gpu vertex buffer
0, //must be 0
0, //must be 0
_pCopyVertexBuffer,
0, //must be 0
NULL //in this case we copy the full content of _pCopyVertexBuffer, so we can set to null
);
Теперь, если вы хотите обновить список вершин, все получится более сложный, и у вас есть несколько вариантов:
- Сначала вы примените эту технику с одной вершиной в al oop, это будет работать довольно хорошо, если ваша ревизия мала.
-Если ваша ревизия установлена очень большой (близкий к почти полному размеру вершины, вы, вероятно, вместо этого можете переписать весь буфер).
-Продолжительный метод заключается в использовании вычислительного шейдера для выполнения обновлений (это тот, который я обычно использую как наиболее гибкая версия). Публикация всего кода привязки c ++ была бы слишком длинной, но вот концепция:
- ваш буфер вершин должен иметь BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_UNORDERED_ACCESS; // это позволяет писать с вычислением
- , вам необходимо создать ID3D11UnorderedAccessView для этого буфера (чтобы шейдер мог записать в него)
- вам нужны следующие флаги mis c: D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS // это позволяет записать как RWByteAddressBuffer
- , после чего вы создаете два динамических c структурированных буфера (я предпочитаю их над byteaddress, но в dx11 буфер вершин и структурированный не разрешены, поэтому для записи вам нужен raw)
- первый структурированный буфер имеет шаг ST_Vertex (это ваш набор изменений)
- второй структурированный буфер имеет шаг 4 (uint, это индексы)
- оба структурированы буферы получают произвольное количество элементов (обычно я использую 1024 или 2048), так что это будет максимальное количество вершин, которое вы можете обновить за один проход.
- для обоих структурированных буферов необходим ID3D11ShaderResourceView (шейдер виден, читается только)
Затем процесс обновления выглядит следующим образом:
* 104 9 * запись измененных вершин и местоположений в структурированных буферах (используя сброс карты, если вам нужно меньше копировать, все нормально) присоединить оба структурированных буфера для чтения присоединить ID3D11UnorderedAccessView для записи установка вычислительного шейдера отправка вызова отсоединение ID3D11UnorderedAccessView для записи (это ОЧЕНЬ важно)
Это пример кода вычислительного шейдера ( Я полагаю, что для простоты вершина является позицией
1065 *