Porter les mémoires tampons et les données de vertex
API importantes
- ID3DDevice ::CreateBuffer
- ID3DDeviceContext ::IASetVertexBuffers
- ID3D11DeviceContext ::IASetIndexBuffer
Dans cette étape, vous allez définir les mémoires tampons de vertex qui contiennent vos maillages et les mémoires tampons d’index qui permettent aux nuanceurs de parcourir les sommets dans un ordre spécifié.
À ce stade, examinons le modèle codé en dur pour le maillage de cube que nous utilisons. Les deux représentations ont les sommets organisés sous la forme d’une liste de triangles (par opposition à une bande ou à une autre disposition de triangle plus efficace). Tous les sommets dans les deux représentations ont également des index associés et des valeurs de couleur. La majeure partie du code Direct3D de cette rubrique fait référence aux variables et aux objets définis dans le projet Direct3D.
Voici le cube à traiter par OpenGL ES 2.0. Dans l’exemple d’implémentation, chaque vertex est de 7 valeurs flottantes : 3 coordonnées de position suivies de 4 valeurs de couleur RVBA.
#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
};
Et voici le même cube pour le traitement par 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
};
En examinant ce code, vous remarquerez que le cube dans le code OpenGL ES 2.0 est représenté dans un système de coordonnées de droite, tandis que le cube du code spécifique à Direct3D est représenté dans un système de coordonnées de gauche. Lors de l’importation de vos propres données de maillage, vous devez inverser les coordonnées de l’axe z de votre modèle et modifier les index de chaque maillage en conséquence pour parcourir les triangles en fonction de la modification du système de coordonnées.
En supposant que nous avons correctement déplacé le maillage de cube du système de coordonnées OpenGL ES ES 2.0 à gauche vers direct3D gaucher, voyons comment charger les données du cube pour le traitement dans les deux modèles.
Instructions
Étape 1 : Créer une disposition d’entrée
Dans OpenGL ES 2.0, vos données de vertex sont fournies en tant qu’attributs qui seront fournis et lus par les objets de nuanceur. Vous fournissez généralement une chaîne qui contient le nom d’attribut utilisé dans le GLSL du nuanceur pour l’objet de programme de nuanceur et récupérez un emplacement de mémoire que vous pouvez fournir au nuanceur. Dans cet exemple, un objet de mémoire tampon de vertex contient une liste de structures de vertex personnalisées, définies et mises en forme comme suit :
OpenGL ES 2.0 : Configurez les attributs qui contiennent les informations par vertex.
typedef struct
{
GLfloat pos[3];
GLfloat rgba[4];
} Vertex;
Dans OpenGL ES 2.0, les dispositions d’entrée sont implicites ; vous prenez un GL_ELEMENT_ARRAY_BUFFER usage général et fournissez la progression et le décalage afin que le nuanceur de vertex puisse interpréter les données après leur chargement. Vous informez le nuanceur avant de rendre les attributs mappés aux parties de chaque bloc de données de vertex avec glVertexAttribPointer.
Dans Direct3D, vous devez fournir une disposition d’entrée pour décrire la structure des données de vertex dans la mémoire tampon de vertex lorsque vous créez la mémoire tampon, au lieu de dessiner la géométrie. Pour ce faire, vous utilisez une disposition d’entrée qui correspond à la disposition des données pour nos sommets individuels en mémoire. Il est très important de spécifier cela avec précision !
Ici, vous créez une description d’entrée en tant que tableau de structures D3D11_INPUT_ELEMENT_DESC.
Direct3D : Définir une description de disposition d’entrée.
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 },
};
Cette description d’entrée définit un sommet en tant que paire de 2 vecteurs de coordonnées 3D : un vecteur 3D pour stocker la position du sommet dans les coordonnées du modèle, et un autre vecteur 3D pour stocker la valeur de couleur RVB associée au sommet. Dans ce cas, vous utilisez le format à virgule flottante 3x32 bits, dont nous représentons dans le code en tant que XMFLOAT3(X.Xf, X.Xf, X.Xf)
. Vous devez utiliser des types de la bibliothèque DirectXMath chaque fois que vous gérez des données qui seront utilisées par un nuanceur, car elles garantissent l’empaquetage et l’alignement appropriés de ces données. (Par exemple, utiliser XMFLOAT3 ou XMFLOAT4 pour les données vectorielles et XMFLOAT4X4 pour les matrices.)
Pour obtenir la liste de tous les types de format possibles, reportez-vous à DXGI_FORMAT.
Une fois la disposition d’entrée par vertex définie, vous créez l’objet de disposition. Dans le code suivant, vous l’écrivez dans m_inputLayout, variable de type ComPtr (qui pointe vers un objet de type ID3D11InputLayout). fileData contient l’objet nuanceur de vertex compilé de l’étape précédente, portez les nuanceurs.
Direct3D : Créez la disposition d’entrée utilisée par la mémoire tampon de vertex.
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
// ...
m_d3dDevice->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
fileData->Data,
fileShaderData->Length,
&m_inputLayout
);
Nous avons défini la disposition d’entrée. À présent, nous allons créer une mémoire tampon qui utilise cette disposition et la charger avec les données de maillage de cube.
Étape 2 : Créer et charger la ou les mémoires tampons de vertex
Dans OpenGL ES 2.0, vous créez une paire de mémoires tampons, une pour les données de position et une pour les données de couleur. (Vous pouvez également créer un struct qui contient à la fois et une mémoire tampon unique.) Vous liez chaque mémoire tampon et écrivez des données de position et de couleur dans celles-ci. Plus tard, pendant votre fonction de rendu, liez à nouveau les mémoires tampons et fournissez au nuanceur le format des données dans la mémoire tampon afin qu’elle puisse l’interpréter correctement.
OpenGL ES 2.0 : lier les mémoires tampons de vertex
// 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);
Dans Direct3D, les mémoires tampons accessibles au nuanceur sont représentées en tant que structures D3D11_SUBRESOURCE_DATA. Pour lier l’emplacement de cette mémoire tampon à l’objet de nuanceur, vous devez créer une structure CD3D11_BUFFER_DESC pour chaque mémoire tampon avec ID3DDevice ::CreateBuffer, puis définir la mémoire tampon du contexte d’appareil Direct3D en appelant une méthode set spécifique au type de mémoire tampon, par exemple ID3DDeviceContext ::IASetVertexBuffers.
Lorsque vous définissez la mémoire tampon, vous devez définir la progression (la taille de l’élément de données pour un sommet individuel) ainsi que le décalage (où le tableau de données de vertex démarre réellement) à partir du début de la mémoire tampon.
Notez que nous affectons le pointeur au tableau vertexIndices au champ pSysMem de la structure D3D11_SUBRESOURCE_DATA . Si ce n’est pas correct, votre maillage sera endommagé ou vide !
Direct3D : Créer et définir la mémoire tampon de vertex
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);
Étape 3 : Créer et charger la mémoire tampon d’index
Les mémoires tampons d’index constituent un moyen efficace pour permettre au nuanceur de vertex de rechercher des sommets individuels. Bien qu’ils ne soient pas obligatoires, nous les utilisons dans cet exemple de renderer. Comme avec les mémoires tampons de vertex dans OpenGL ES 2.0, une mémoire tampon d’index est créée et liée en tant que mémoire tampon à usage général et les index de vertex que vous avez créés précédemment sont copiés dans celui-ci.
Lorsque vous êtes prêt à dessiner, vous liez à la fois le sommet et la mémoire tampon d’index, puis appelez glDrawElements.
OpenGL ES 2.0 : envoyez l’ordre d’index à l’appel de dessin.
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);
Avec Direct3D, il s’agit d’un processus un peu similaire, mais un peu plus didactique. Fournissez la mémoire tampon d’index en tant que sous-ressource Direct3D à l’ID3D11DeviceContext que vous avez créé lors de la configuration de Direct3D. Pour ce faire, appelez ID3D11DeviceContext ::IASetIndexBuffer avec la sous-source configurée pour le tableau d’index, comme suit. (Là encore, notez que vous affectez le pointeur au tableau cubeIndices au champ pSysMem de la structure D3D11_SUBRESOURCE_DATA .)
Direct3D : Créez la mémoire tampon d’index.
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);
Plus tard, vous dessinerez les triangles avec un appel à ID3D11DeviceContext ::D rawIndexed (ou ID3D11DeviceContext ::D raw pour les sommets non indexés), comme suit. (Pour plus d’informations, passez à Dessiner sur l’écran.)
Direct3D : dessinez les sommets indexés.
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
// ...
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0);
Étape précédente
Étape suivante
Notes
Lorsque vous structurez votre Direct3D, séparez le code qui appelle des méthodes sur ID3D11Device dans une méthode appelée chaque fois que les ressources de l’appareil doivent être recréées. (Dans le modèle de projet Direct3D, ce code se trouve dans l’objet rendererMéthodes CreateDeviceResource . Le code qui met à jour le contexte de l’appareil (ID3D11DeviceContext), en revanche, est placé dans la méthode Render, car c’est là que vous construisez réellement les étapes du nuanceur et liez les données.
Rubriques connexes
- Guide pratique pour porter un convertisseur OpenGL ES 2.0 simple vers Direct3D 11
- Porter les objets nuanceur
- Porter les mémoires tampons et les données de vertex
- Porter le langage GLSL