33Nous pouvons maintenant passer des données à chaque groupe d'invocation de vertex shaders. Mais qu'en est-il des
44variables globales? Nous allons enfin passer à la 3D, et nous avons besoin d'une matrice model-view-projection. Nous
55pourrions la transmettre avec les vertices, mais cela serait un gachis de mémoire et, de plus, nous devrions mettre à
6- jour le vertex buffer à chaque frame, alors qu'il est très bien dans se mémoire à hautes performances.
6+ jour le vertex buffer à chaque frame, alors qu'il est très bien rangé dans se mémoire à hautes performances.
77
8- La solution fournie par Vulkan consiste à utiliser des * descripteurs de ressource* (ou * resource descriptors* ). Un
9- descripteur permet à des shaders d'accéder librement à des ressources telles que les buffers ou les images. Nous allons
10- créer un buffer qui contiendra les matrices de transformation. Nous ferons en sorte que le vertex shader puisse y
11- accéder. Il y a trois parties à l'utilisation d'un descripteur de ressource :
8+ La solution fournie par Vulkan consiste à utiliser des * descripteurs de ressource* (ou * resource descriptors* ), qui
9+ font correspondre des données en mémoire à une variable shader. Un descripteur permet à des shaders d'accéder
10+ librement à des ressources telles que les buffers ou les * images* . Attention, Vulkan donne un sens particulier au
11+ terme image. Nous verrons cela bientôt. Nous allons pour l'instant créer un buffer qui contiendra les matrices de
12+ transformation. Nous ferons en sorte que le vertex shader puisse y accéder. Il y a trois parties à l'utilisation d'un
13+ descripteur de ressources :
1214
1315* Spécifier l'organisation des descripteurs durant la création de la pipeline
14- * Allouer un set de descripteurs depuis une pool de descritpeurs
16+ * Allouer un set de descripteurs depuis une pool de descritpeurs (encore un objet de gestion de mémoire)
1517* Lier le descripteur pour les opérations de rendu
1618
17- L'* organisation du descripteur* indique le type de ressources qui seront accedées par la pipeline. Cela ressemble sur
18- le principe à indiquer les attachements accédés. Un * set de descripteurs* spécifie le buffer ou l'image qui sera lié à
19- ce descripteur, de la même manière qu'un framebuffer doit indiquer les ressources qui le composent.
19+ L'* organisation du descripteur* (descriptor layout) indique le type de ressources qui seront accedées par la
20+ pipeline. Cela ressemble sur le principe à indiquer les attachements accédés. Un * set de descripteurs* (descriptor
21+ set) spécifie le buffer ou l'image qui sera lié à ce descripteur, de la même manière qu'un framebuffer doit indiquer
22+ les ressources qui le composent.
2023
2124Il existe plusieurs types de descripteurs, mais dans ce chapitre nous ne verrons que les * uniform buffer objects* (UBO).
2225Nous en verrons d'autres plus tard, et leur utilisation sera très similaire. Rentrons dans le vif du sujet et supposons
23- maintenant que nous voulons que toutes les invocations du vertex shader que nous avons mis en place accèdent tous à la
24- structure C suivante :
26+ maintenant que nous voulons que toutes les invocations du vertex shader que nous avons codé accèdent à la structure C
27+ suivante :
2528
2629``` c++
2730struct UniformBufferObject {
@@ -82,15 +85,15 @@ void main() {
8285```
8386
8487L'ordre des variables `in`, `out` et `uniform` n'a aucune importance. La directive `binding` est assez semblable à
85- `location` ; elle permet de fournir l'indice du binding. Nous allons le référencer dans l'organisation du descripteur.
88+ `location` ; elle permet de fournir l'indice du binding. Nous allons l'indiquer dans l'organisation du descripteur.
8689Notez le changement dans la ligne calculant `gl_Position`, qui prend maintenant en compte la matrice MVP. La dernière
8790composante du vecteur ne sera plus à `0`, car elle sert à diviser les autres coordonnées en fonction de leur distance à
8891la caméra pour créer un effet de profondeur.
8992
9093## Organisation du set de descripteurs
9194
92- La prochaine étape consiste à définir l'UBO du côté du C++. Nous devons aussi informer Vulkan que nous voulons
93- l'utiliser dans le vertex shader.
95+ La prochaine étape consiste à définir l'UBO côté C++. Nous devons aussi informer Vulkan que nous voulons l'utiliser
96+ dans le vertex shader.
9497
9598```c++
9699struct UniformBufferObject {
@@ -104,9 +107,9 @@ Nous pouvons faire correspondre parfaitement la déclaration en C++ avec celle d
104107martrices sont stockées d'une manière compatible bit à bit avec l'interprétation de ces données par les shaders. Nous
105108pouvons ainsi utiliser ` memcpy ` sur une structure ` UniformBufferObject ` vers un ` VkBuffer ` .
106109
107- Nous devons fournir des informations sur chacun des descriptors utilisés par les shaders lors de la création de la
110+ Nous devons fournir des informations sur chacun des descripteurs utilisés par les shaders lors de la création de la
108111pipeline, similairement aux entrées du vertex shader. Nous allons créer une fonction pour gérer toute cette information,
109- et donc pour créer le set de descripteurs. Elle s'appelera ` createDescriptorSetLayout ` et sera appelée juste avant la
112+ et ainsi pour créer le set de descripteurs. Elle s'appelera ` createDescriptorSetLayout ` et sera appelée juste avant la
110113finalisation de la création de la pipeline.
111114
112115``` c++
@@ -145,18 +148,18 @@ hiérarchique. Nous n'utilisons pas cette possiblité et indiquons donc `1`.
145148uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
146149```
147150
148- Nous devons aussi informer Vulkan sur les étapes shaders qui accèderont à cette ressource. Le champ de bits ` stageFlags `
151+ Nous devons aussi informer Vulkan des étapes shaders qui accèderont à cette ressource. Le champ de bits ` stageFlags `
149152permet de combiner toutes les étapes shader concernées. Vous pouvez aussi fournir la valeur
150153` VK_SHADER_STAGE_ALL_GRAPHICS ` . Nous mettons uniquement ` VK_SHADER_STAGE_VERTEX_BIT ` .
151154
152155``` c++
153- uboLayoutBinding.pImmutableSamplers = nullptr ; // Optionnel
156+ uboLayoutBinding.pImmutableSamplers = nullptr ; // Optionel
154157```
155158
156159Le champ ` pImmutableSamplers ` n'a de sens que pour les descripteurs liés aux samplers d'images. Nous nous attaquerons à
157160ce sujet plus tard. Vous pouvez le mettre à ` nullptr ` .
158161
159- Tous les ` binding ` des descripteurs sont ensuite combinés en un seul objet ` VkDescriptorSetLayout ` . Créez pour cela un
162+ Tous les liens des descripteurs sont ensuite combinés en un seul objet ` VkDescriptorSetLayout ` . Créez pour cela un
160163nouveau membre donnée :
161164
162165``` c++
@@ -165,7 +168,8 @@ VkPipelineLayout pipelineLayout;
165168```
166169
167170Nous pouvons créer cet objet à l'aide de la fonction ` vkCreateDescriptorSetLayout ` . Cette fonction prend en argument une
168- structure du type ` VkDescriptorSetLayoutCreateInfo ` qui contient un tableau fait des structures décrivant les bindings :
171+ structure de type ` VkDescriptorSetLayoutCreateInfo ` . Elle contient un tableau contenant les structures qui décrivent les
172+ bindings :
169173
170174``` c++
171175VkDescriptorSetLayoutCreateInfo layoutInfo = {};
@@ -174,7 +178,7 @@ layoutInfo.bindingCount = 1;
174178layoutInfo.pBindings = &uboLayoutBinding;
175179
176180if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr , &descriptorSetLayout) != VK_SUCCESS) {
177- throw std::runtime_error("echec lors de la creation d'un set de descripteurs!");
181+ throw std::runtime_error("echec de la creation d'un set de descripteurs!");
178182}
179183```
180184
@@ -190,7 +194,7 @@ pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
190194
191195Vous vous demandez peut-être pourquoi il est possible de spécifier plusieurs set de descripteurs dans cette structure,
192196dans la mesure où un seul inclut tous les ` bindings ` d'une pipeline. Nous y reviendrons dans le chapitre suivant, quand
193- nous nous intéresserons aux pools de descriptors .
197+ nous nous intéresserons aux pools de descripteurs .
194198
195199L'objet que nous avons créé ne doit être détruit que lorsque le programme se termine.
196200
@@ -208,7 +212,7 @@ void cleanup() {
208212
209213Dans le prochain chapitre nous référencerons le buffer qui contient les données de l'UBO. Mais nous devons bien sûr
210214d'abord créer ce buffer. Comme nous allons accéder et modifier les données du buffer à chaque frame, il est assez
211- inutile d'utiliser un buffer intermédiaire. Ce serait même en fait contre-productif en terme de performance .
215+ inutile d'utiliser un buffer intermédiaire. Ce serait même en fait contre-productif en terme de performances .
212216
213217Comme des frames peuvent être "in flight" pendant que nous essayons de modifier le contenu du buffer, nous allons avoir
214218besoin de plusieurs buffers. Nous pouvons soit en avoir un par frame, soit un par image de la swap chain. Comme nous
@@ -250,7 +254,7 @@ void createUniformBuffer() {
250254}
251255```
252256
253- Nous allons créer une autre fonction qui mettra à jour le buffer et appliquera à son contenu une transformation à chaque
257+ Nous allons créer une autre fonction qui mettra à jour le buffer en appliquant à son contenu une transformation à chaque
254258frame. Nous n'utiliserons donc pas ` vkMapMemory ` ici. Le buffer doit être détruit à la fin du programme :
255259
256260``` c++
@@ -268,9 +272,9 @@ void cleanup() {
268272}
269273```
270274
271- ## Mise à jour des données uniform
275+ ## Mise à jour des données uniformes
272276
273- Créez la fonction ` updateUniformBuffer ` et appelez-la dans ` drawFrame ` juste après que nous avons déterminé l'image de
277+ Créez la fonction ` updateUniformBuffer ` et appelez-la dans ` drawFrame ` , juste après que nous avons déterminé l'image de
274278la swap chain que nous devons acquérir :
275279
276280``` c++
@@ -313,7 +317,7 @@ dont nous avons besoin pour implémenter la 3D. La macro `GLM_FORCE_RADIANS` per
313317représentation des angles.
314318
315319Pour que la rotation s'exécute à une vitesse indépendante du FPS, nous allons utiliser les fonctionnalités de mesure
316- précise contenues dans ` <chrono> ` .
320+ précise de la librairie standrarde C++. Incluez donc ` <chrono> ` :
317321
318322``` c++
319323void updateUniformBuffer (uint32_t currentImage) {
@@ -324,7 +328,7 @@ void updateUniformBuffer(uint32_t currentImage) {
324328}
325329```
326330
327- Nous commençons donc par inclure la logique de calcul du temps écoulé, mesuré en secondes et stocké dans un `float`.
331+ Nous commençons donc par écrire la logique de calcul du temps écoulé, mesuré en secondes et stocké dans un `float`.
328332
329333Nous allons ensuite définir les matrices model, view et projection stockées dans l'UBO. La rotation sera implémentée
330334comme une simple rotation autour de l'axe Z en fonction de la variable `time` :
@@ -335,7 +339,7 @@ ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0
335339```
336340
337341La fonction ` glm::rotate ` accepte en argument une matrice déjà existante, un angle de rotation et un axe de rotation. Le
338- constructeur ` glm::mat4(1.0) ` crée une matrice d' identité. Avec la multiplication ` time * glm::radians(90.0f) ` la
342+ constructeur ` glm::mat4(1.0) ` crée une matrice identité. Avec la multiplication ` time * glm::radians(90.0f) ` la
339343géométrie tournera de 90 degrés par seconde.
340344
341345``` c++
@@ -352,7 +356,7 @@ ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)
352356
353357J'ai opté pour un champ de vision de 45 degrés. Les autres paramètres de ` glm::perspective ` sont le ratio et les plans
354358near et far. Il est important d'utiliser l'étendue actuelle de la swap chain pour calculer le ratio, afin d'utiliser les
355- valeurs qui prennent en compte les redimensionnements.
359+ valeurs qui prennent en compte les redimensionnements de la fenêtre .
356360
357361``` c++
358362ubo.proj[1 ][1 ] *= -1 ;
@@ -362,7 +366,7 @@ GLM a été conçue pour OpenGL, qui utilise les coordonnées de clip et de l'ax
362366compenser cela consiste à changer le signe de l'axe Y dans la matrice de projection.
363367
364368Maintenant que toutes les transformations sont définies nous pouvons copier les données dans le buffer uniform actuel.
365- Nous utilisons le même procédé que pour le vertex buffer, hormis le buffer intermédiaire .
369+ Nous utilisons la première technique que nous avons vue pour la copie de données dans un buffer .
366370
367371``` c++
368372void * data;
@@ -374,7 +378,7 @@ vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
374378Utiliser un UBO de cette manière n'est pas le plus efficace pour transmettre des données fréquemment mises à jour. Une
375379meilleure pratique consiste à utiliser les *push constants*, que nous aborderons peut-être dans un futur chapitre.
376380
377- Dans un avenir plus proche nous allons lier les sets de descirptors au `VkBuffer` contenant les données des matrices,
381+ Dans un avenir plus proche nous allons lier les sets de descripteurs au `VkBuffer` contenant les données des matrices,
378382afin que le vertex shader puisse y avoir accès.
379383
380384[Code C++](/code/21_descriptor_layout.cpp) /
0 commit comments