Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Основные API
На этом шаге вы определите буферы вершин, которые будут содержать сетки и буферы индекса, которые позволяют шейдерам проходить вершины в указанном порядке.
На этом этапе давайте рассмотрим жестко закодированную модель для используемой сетки куба. Оба представления имеют вершины, упорядоченные как список треугольников (в отличие от полосы или другого более эффективного макета треугольника). Все вершины в обоих представлениях также имеют связанные индексы и значения цвета. Большая часть кода Direct3D в этом разделе относится к переменным и объектам, определенным в проекте Direct3D.
Ниже представлен куб для обработки OpenGL ES 2.0. В примере реализации каждая вершина составляет 7 значений с плавающей запятой: 3 координаты положения, за которыми следует 4 значения цвета RGBA.
#define CUBE_INDICES 36
#define CUBE_VERTICES 8
GLfloat cubeVertsAndColors[] =
{
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f
};
GLuint cubeIndices[] =
{
0, 1, 2, // -x
1, 3, 2,
4, 6, 5, // +x
6, 7, 5,
0, 5, 1, // -y
5, 6, 1,
2, 6, 3, // +y
6, 7, 3,
0, 4, 2, // +z
4, 6, 2,
1, 7, 3, // -z
5, 7, 1
};
И вот тот же куб для обработки с помощью Direct3D 11.
VertexPositionColor cubeVerticesAndColors[] =
// struct format is position, color
{
{XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)},
{XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)},
{XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)},
{XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)},
{XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)},
{XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)},
{XMFLOAT3( 0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)},
};
unsigned short cubeIndices[] =
{
0, 2, 1, // -x
1, 2, 3,
4, 5, 6, // +x
5, 7, 6,
0, 1, 5, // -y
0, 5, 4,
2, 6, 7, // +y
2, 7, 3,
0, 4, 6, // -z
0, 6, 2,
1, 3, 7, // +z
1, 7, 5
};
При просмотре этого кода вы заметите, что куб в коде OpenGL ES 2.0 представлен в правой системе координат, а куб в коде Direct3D представлен в левой системе координат. При импорте собственных данных сетки необходимо реверсировать координаты оси Z для вашей модели и соответственно изменить индексы для каждой сетки, чтобы обходить треугольники в соответствии с изменением системы координат.
Если мы успешно переместили сетку куба из правой системы координат OpenGL ES 2.0 в левую сторону Direct3D, давайте посмотрим, как загрузить данные куба для обработки в обеих моделях.
Инструкции
Шаг 1. Создание входного макета
В OpenGL ES 2.0 данные вершин предоставляются в виде атрибутов, которые считываются объектами шейдера. Обычно вы предоставляете строку, содержащую имя атрибута, используемое в GLSL шейдера, объекту программы шейдера и получаете в ответ адрес памяти, который можно передать шейдеру. В этом примере объект буфера вершин содержит список пользовательских структур вершин, определенных и отформатированных следующим образом:
OpenGL ES 2.0: настройте атрибуты, содержащие информацию о каждой вершине.
typedef struct
{
GLfloat pos[3];
GLfloat rgba[4];
} Vertex;
В OpenGL ES 2.0 макеты входных данных задаются неявно; вы используете буфер GL_ELEMENT_ARRAY_BUFFER общего назначения и предоставляете шаг и смещение таким образом, чтобы вершинный шейдер мог интерпретировать данные после их загрузки. ** Перед отрисовкой вы сообщаете шейдеру, какие атрибуты соответствуют каким частям каждого блока вершинных данных с помощью glVertexAttribPointer.
В Direct3D необходимо предоставить входной макет, чтобы описать структуру данных вершин в буфере вершин при создании буфера, а не перед рисованием геометрии. Для этого вы используете входной шаблон, который соответствует макету данных для индивидуальных вершин в памяти. Очень важно указать это точно!
Здесь вы создаете описание ввода в виде массива структур D3D11_INPUT_ELEMENT_DESC.
Direct3D: определение описания входного макета.
struct VertexPositionColor
{
DirectX::XMFLOAT3 pos;
DirectX::XMFLOAT3 color;
};
// ...
const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
Это описание входных данных определяет вершину как пару 2 3-координатных векторов: один трехмерный вектор для хранения положения вершины в координатах модели, а другой трехмерный вектор для хранения значения цвета RGB, связанного с вершиной. В этом случае используется формат с плавающей запятой 3x32, элементы которого мы представляем в коде как XMFLOAT3(X.Xf, X.Xf, X.Xf)
. Типы из библиотеки DirectXMath следует использовать при обработке данных, которые будут использоваться шейдером, так как это обеспечивает правильную упаковку и выравнивание этих данных. (Например, используйте XMFLOAT3 или XMFLOAT4 для векторных данных и XMFLOAT4X4 для матриц.)
Список всех возможных типов форматов см. в DXGI_FORMAT.
После определения поканальной структуры ввода создается объект макета. В следующем коде вы записываете его в m_inputLayout, переменную типа ComPtr (которая указывает на объект типа ID3D11InputLayout). fileData содержит скомпилированный объект шейдера вершин из предыдущего шага, портироватьшейдеры.
Direct3D: создайте входную схему, используемую буфером вершин.
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
// ...
m_d3dDevice->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
fileData->Data,
fileShaderData->Length,
&m_inputLayout
);
Мы определили макет входных данных. Теперь создадим буфер, который использует этот макет, и загрузим его данными кубической сетки.
Шаг 2. Создание и загрузка буферов вершин
В OpenGL ES 2.0 создается пара буферов, одна для данных позиции и одна для цветных данных. (Можно также создать структуру, содержащую и буфер, и данные.) Вы связываете каждый буфер и записываете в них данные о положении и цвете. Позже, во время функции отрисовки, привяжите буферы снова и предоставьте шейдеру информацию о формате данных в буфере, чтобы он смог правильно интерпретировать их.
OpenGL ES 2.0: привязка буферов вершин
// upload the data for the vertex position buffer
glGenBuffers(1, &renderer->vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, renderer->vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTEX) * CUBE_VERTICES, renderer->vertices, GL_STATIC_DRAW);
В Direct3D буферы, доступные для шейдеров, представлены как D3D11_SUBRESOURCE_DATA структуры. Чтобы привязать расположение этого буфера к объекту шейдера, необходимо создать структуру CD3D11_BUFFER_DESC для каждого буфера с ID3DDevice::CreateBuffer, а затем задать буфер контекста устройства Direct3D, вызвав метод, специфичный для типа буфера, например ID3DDeviceContext::IASetVertexBuffers.
При установке буфера необходимо задать шаг (размер элемента данных для отдельной вершины), а также смещение (где фактически начинается массив данных вершин) с начала буфера.
Обратите внимание, что указатель на массив индексов вершин присваивается полю pSysMem структуры D3D11_SUBRESOURCE_DATA. Если это неправильно, сетка будет повреждена или пуста!
Direct3D: создание и настройка буфера вершин
D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
vertexBufferData.pSysMem = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
m_d3dDevice->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&m_vertexBuffer);
// ...
UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
m_d3dContext->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset);
Шаг 3. Создание и загрузка буфера индекса
Буферы индексов — это эффективный способ, позволяющий шейдеру вершин искать отдельные вершины. Хотя они не требуются, мы используем их в этом примере рендера. Как и в случае с буферами вершин в OpenGL ES 2.0, буфер индекса создается и привязан в качестве буфера общего назначения, а созданные ранее индексы вершин копируются в него.
Когда вы будете готовы к рисованию, привязываете вершину и буфер индекса снова и вызовите glDrawElements.
OpenGL ES 2.0: отправьте порядок индекса вызову рисования.
GLuint indexBuffer;
// ...
glGenBuffers(1, &renderer->indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(GLuint) * CUBE_INDICES,
renderer->vertexIndices,
GL_STATIC_DRAW);
// ...
// Drawing function
// Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer);
glDrawElements (GL_TRIANGLES, renderer->numIndices, GL_UNSIGNED_INT, 0);
С Direct3D это немного похожий процесс, хотя и немного более дидактический. Укажите буфер индекса в виде подресурса Direct3D в ID3D11DeviceContext, созданной при настройке Direct3D. Для этого необходимо вызвать ID3D11DeviceContext::IASetIndexBuffer с настроенным подресурсом для массива индексов следующим образом. (Опять обратите внимание, что вы присваиваете указатель на массив cubeIndices полю pSysMem структуры D3D11_SUBRESOURCE_DATA.)
Direct3D: создайте буфер индекса.
m_indexCount = ARRAYSIZE(cubeIndices);
D3D11_SUBRESOURCE_DATA indexBufferData = {0};
indexBufferData.pSysMem = cubeIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
m_d3dDevice->CreateBuffer(
&indexBufferDesc,
&indexBufferData,
&m_indexBuffer);
// ...
m_d3dContext->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0);
Позже вы нарисуете треугольники с вызовом ID3D11DeviceContext::DrawIndexed (или ID3D11DeviceContext::Draw для неиндексированных вершин), следующим образом. (Для получения дополнительных сведений перейдите к разделу Отображение на экране.)
Direct3D: рисование индексированных вершин.
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
// ...
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0);
Предыдущий шаг
Следующий шаг
портировать GLSL
Замечания
При структурировании Direct3D выделите код, который вызывает методы ID3D11Device, в отдельный метод, который вызывается при необходимости повторного создания ресурсов устройства. (В шаблоне проекта Direct3D этот код находится в методах createDeviceRe source объекта отрисовщика. Код, обновляющий контекст устройства (ID3D11DeviceContext), с другой стороны, помещается в метод Render , так как именно здесь вы создаете этапы шейдера и привязываете данные.
Связанные темы
- Практическое руководство. Перенос простого отрисовщика OpenGL ES 2.0 в Direct3D 11
- Перенос объектов шейдера
- Перенос буферов вершин и данных
- портировать GLSL