
Tout de bonne humeur et température plus basse en dehors de la fenêtre. Comme promis, je publie une suite de l'article sur le super-duper d'OpenGL moderne. Qui n'a pas lu la première partie -
Ultramodern OpenGL. Partie 1Vous avez peut-être de la chance et je peux mettre tout le matériel restant dans cet article, ce n'est pas certain ...
Texture de tableau
Les tableaux de textures ont été ajoutés à nouveau dans OpenGL 3.0, mais pour une raison quelconque, peu de gens écrivent à leur sujet (les informations sont masquées de manière fiable par les francs-maçons). Vous êtes tous familiers avec la programmation et savez ce qu'est un
tableau , bien que je ferais mieux de «l'approche» de l'autre côté.
Pour réduire le nombre de commutations entre les textures et, par conséquent, pour réduire les opérations de changement d'état, les utilisateurs utilisent
des atlas de texture (une texture qui stocke des données pour plusieurs objets). Mais les gars intelligents de Khronos ont développé une alternative pour nous - la texture du tableau. Maintenant, nous pouvons stocker des textures sous forme de couches dans ce tableau, c'est-à-dire que c'est une alternative aux atlas. Le Wiki OpenGL a une description légèrement différente sur les mipmaps, etc., mais cela me semble trop compliqué (
lien ).
Les avantages de cette approche par rapport aux atlas sont que chaque couche est considérée comme une texture distincte en termes d'emballage et de mipmapping.
Mais revenons à nos béliers ... Le tableau de textures a trois types de cibles:
- GL_TEXTURE_1D_ARRAY
- GL_TEXTURE_2D_ARRAY
- GL_TEXTURE_CUBE_MAP_ARRAY
Code pour créer un tableau de textures:
GLsizei width = 512; GLsizei height = 512; GLsizei layers = 3; glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &texture_array); glTextureStorage3D(texture_array, 0, GL_RGBA8, width, height, layers);
Les plus attentifs ont remarqué que nous créons un référentiel pour les textures 2D, mais pour une raison quelconque, nous utilisons un tableau 3D, il n'y a pas d'erreur ou de faute de frappe ici. Nous stockons des textures 2D, mais puisqu'elles sont situées dans des «couches», nous obtenons un tableau 3D (en fait, les données de pixels sont stockées, pas les textures. Le tableau 3D a des couches 2D avec des données de pixels).
Ici, il est facile de comprendre l'exemple de la texture 1D. Chaque ligne d'un tableau de pixels 2D est une couche 1D distincte. Les textures Mipmap peuvent également être créées automatiquement.
Sur ce point, toutes les difficultés se terminent et l'ajout d'une image à un calque spécifique est assez simple:
glTextureSubImage3D(texarray, mipmap_level, offset.x, offset.y, layer, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Lorsque vous utilisez des tableaux, nous devons changer un peu le shader
#version 450 core layout (location = 0) out vec4 color; layout (location = 0) in vec2 texture_0; uniform sampler2DArray texture_array; uniform uint diffuse_layer; float getCoord(uint capacity, uint layer) { return max(0, min(float(capacity - 1), floor(float(layer) + 0.5))); } void main() { color = texture(texture_array, vec3(texture_0, getCoord(3, diffuse_layer))); }
La meilleure option serait de calculer la couche souhaitée en dehors du shader, pour cela, nous pouvons utiliser
UBO /
SSBO (il est également utilisé pour transférer des matrices et de nombreuses autres données, mais c'est en quelque sorte une autre fois). Si quelqu'un ne peut pas attendre
tyk_1 et
tyk_2 , vous pouvez lire.
Quant aux tailles, c'est-à-dire GL_MAX_ARRAY_TEXTURE_LAYERS qui est 256 en OpenGL 3.3 et 2048 en OpenGL 4.5.
Il vaut la peine de parler de l'objet Sampler (non lié à la texture du tableau, mais une chose utile) - c'est un objet qui est utilisé pour configurer les états d'une unité de texture, quel que soit l'objet actuellement attaché à l'unité. Il permet de séparer les états de l'échantillonneur d'un objet de texture particulier, ce qui améliore l'abstraction.
GLuint sampler_state = 0; glGenSamplers(1, &sampler_state); glSamplerParameteri(sampler_state, GL_TEXTURE_WRAP_S, GL_REPEAT); glSamplerParameteri(sampler_state, GL_TEXTURE_WRAP_T, GL_REPEAT); glSamplerParameteri(sampler_state, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(sampler_state, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameterf(sampler_state, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
Je viens de créer un objet échantillonneur, activé le filtrage linéaire et le filtrage anisotrope 16x pour n'importe quelle unité de texture.
GLuint texture_unit = 0; glBindSampler(texture_unit, sampler_state);
Ici, nous lions simplement l'échantillonneur à l'unité de texture souhaitée, et lorsqu'il cesse d'être le bindim 0 souhaité à cette unité.
glBindSampler(texture_unit, 0);
Lorsque nous avons lié l'échantillonneur, ses paramètres ont priorité sur les paramètres de l'unité de texture. Résultat: il n'est pas nécessaire de modifier la base de code existante pour ajouter des objets d'échantillonneur. Vous pouvez laisser la création de texture telle quelle (avec ses propres états d'échantillonneur) et simplement ajouter du code pour contrôler et utiliser les objets d'échantillonneur.
Lorsqu'il est temps de supprimer l'objet, nous appelons simplement cette fonction:
glDeleteSamplers(1, &sampler_state);
Vue de texture
Je vais traduire cela par "un pointeur de texture (il peut être plus correct que le lien, je suis xs)", car je ne connais pas la meilleure traduction.
Quels sont les pointeurs dans la perspective d'OpenGL?
Tout est très simple, c'est un pointeur vers les données d'une texture immuable (à savoir, mutable), comme nous le voyons dans l'image ci-dessous.

En fait, c'est un objet qui partage les données de texel d'un certain objet de texture, pour l'analogie, nous pouvons utiliser
std :: shared_ptr de C ++ . Tant qu'il existe au moins un pointeur de texture, la texture d'origine ne sera pas supprimée par le pilote.
Le
wiki est décrit plus en détail et mérite d'être lu sur les types de texture et de cible (ils ne doivent pas nécessairement correspondre)
Pour créer un pointeur, nous devons obtenir un descripteur de texture en appelant
glGenTexture (aucune initialisation n'est nécessaire) puis
glTextureView .
glGenTextures(1, &texture_view); glTextureView(texture_view, GL_TEXTURE_2D, source_name, internal_format, min_level, level_count, 5, 1);
Les pointeurs de texture peuvent pointer vers le Nième niveau de mipmap, assez utile et pratique. Les pointeurs peuvent être soit des tableaux de textures, des parties de tableaux, une couche spécifique dans ce tableau, soit une tranche d'une texture 3D en tant que texture 2D.
Tampon unique pour l'index et le sommet
Eh bien, tout sera rapide et facile. Auparavant, la spécification OpenGL pour
Vertex Buffer Object recommandait que le développeur divise les données de sommet et d'index en différents tampons, mais maintenant ce n'est pas nécessaire (une longue histoire pourquoi pas).
Tout ce dont nous avons besoin est de sauvegarder les indices devant les sommets et de dire où les sommets commencent (plus précisément, le décalage), pour cela il y a la commande
glVertexArrayVertexBufferVoici comment nous procéderions:
GLint alignment = GL_NONE; glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment); const GLsizei ind_len = GLsizei(ind_buffer.size() * sizeof(element_t)); const GLsizei vrt_len = GLsizei(vrt_buffer.size() * sizeof(vertex_t)); const GLuint ind_len_aligned = align(ind_len, alignment); const GLuint vrt_len_aligned = align(vrt_len, alignment); GLuint buffer = GL_NONE; glCreateBuffers(1, &buffer); glNamedBufferStorage(buffer, ind_len_aligned + vrt_len_aligned, nullptr, GL_DYNAMIC_STORAGE_BIT); glNamedBufferSubData(buffer, 0, ind_len, ind_buffer.data()); glNamedBufferSubData(buffer, ind_len_aligned, vrt_len, vrt_buffer.data()); GLuint vao = GL_NONE; glCreateVertexArrays(1, &vao); glVertexArrayVertexBuffer(vao, 0, buffer, ind_len_aligned, sizeof(vertex_t)); glVertexArrayElementBuffer(vao, buffer);
Pavage et ombrage de calcul
Je ne vais pas vous parler du shader de tessellation, car il y a beaucoup de matériel sur Google à ce sujet (en russe), voici quelques leçons:
1 ,
2 ,
3 . Nous procédons à l'examen du shader pour les calculs (bliiin, aussi beaucoup de matériel, je vais vous le dire brièvement).
L'avantage des cartes vidéo dans un très grand nombre de cœurs, les cartes vidéo sont conçues pour un grand nombre de petites tâches qui peuvent être effectuées en parallèle. Le shader de calcul, comme son nom l'indique, permet de résoudre des problèmes qui ne sont pas liés au graphisme (pas nécessaire).
Une image, je ne sais pas comment l'appeler (comme les flux sont regroupés).

Que pouvons-nous utiliser?
- Traitement d'image
- Bloom
- Algorithmes basés sur les tuiles (ombrage différé)
- Des simulations
- Particules
- De l'eau
De plus je ne vois aucune raison d'écrire, il y a aussi beaucoup d'informations sur Google, voici un exemple simple d'utilisation:
Voici un exemple de shader de calcul vide:
#version 430 layout(local_size_x = 1, local_size_y = 1) in; layout(rgba32f, binding = 0) uniform image2D img_output; void main() {
Voici quelques liens pour approfondir
1 ,
2 ,
3 ,
4 .
Rendu de chemin
Il s'agit d'une nouvelle extension (pas nouvelle) de
NVidia , son objectif principal est le rendu 2D vectoriel. Nous pouvons l'utiliser pour des textes ou l'interface utilisateur, et puisque les graphiques sont vectoriels, cela ne dépend pas de la résolution, ce qui est sans aucun doute un gros plus et notre interface utilisateur aura fière allure.
Le concept de base est un pochoir, puis une couverture (couverture dans l'original). Définissez le gabarit du chemin, puis visualisez les pixels.
Pour la gestion, GLuint standard est utilisé et les fonctions de création et de suppression ont une convention de dénomination standard.
glGenPathsNV
Voici un peu comment obtenir le chemin:
- SVG ou PostScript dans string'e
glPathStringNV
- tableau de commandes avec les coordonnées correspondantes
glPathCommandsNV
et pour la mise à jour des données glPathSubCommands, glPathCoords, glPathSubCoords
- polices
glPathGlyphsNV, glPathGlyphRangeNV
- combinaisons linéaires de chemins existants (interpolation d'un, deux ou plusieurs chemins)
glCopyPathNV, glInterpolatePathsNV, glCombinePathsNV
- transformation linéaire d'un chemin existant
glTransformPathNV
Liste des commandes standard:
- déplacer vers (x, y)
- chemin étroit
- ligne vers (x, y)
- courbe quadratique (x1, y1, x2, y2)
- courbe cubique (x1, y1, x2, y2, x3, y3)
- courbe quadratique lisse (x, y)
- courbe cubique lisse (x1, y1, x2, y2)
- arc elliptique (rx, ry, rotation sur l'axe des x, drapeau à grand arc, drapeau de balayage, x, y)
Voici à quoi ressemble la chaîne de chemin dans PostScript:
"100 180 moveto 40 10 lineto 190 120 lineto 10 120 lineto 160 10 lineto closepath” // "300 300 moveto 100 400 100 200 300 100 curveto 500 200 500 400 300 300 curveto closepath”
Et ici en SVG:
"M100,180 L40,10 L190,120 L10,120 L160,10 z” // "M300 300 C 100 400,100 200,300 100,500 200,500 400,300 300Z”
Il existe encore toutes sortes de petits pains avec des types de remplissages, bords, coudes:

Je ne décrirai pas tout ici, car il y a beaucoup de matériel et il faudra un article entier (si c'est intéressant, je vais l'écrire en quelque sorte).
Voici une liste de primitives de rendu
- Courbes cubiques
- Courbes quadratiques
- Lignes
- Glyphes de police
- Arcs
- Style Dash & Endcap
Voici du code, puis il y a beaucoup de texte:
C’est tout.
Il me semble que cet article est sorti moins intéressant et informatif, il était difficile de distinguer l'essentiel du matériel. Si quelqu'un souhaite en savoir plus en détail, je peux supprimer certains documents NVidia et les liens vers les spécifications (si je me souviens où je les ai enregistrés). Je suis également heureux de toute aide dans l'édition de l'article.
Comme promis, j'écrirai l'article suivant sur l'optimisation et la réduction des appels de tirage. Je voudrais vous demander d'écrire dans les commentaires ce que vous aimeriez lire d'autre et ce qui vous intéresse:
- Écrire un jeu sur cocos2d-x (Entraînement uniquement, pas d'eau)
- Traduction d'une série d'articles sur Vulkan
- Quelques sujets sur OpenGL (quaternions, nouvelles fonctionnalités)
- Algorithmes d'infographie (éclairage, occlusion ambiante de l'écran spatial, réflexion de l'écran spatial)
- Vos options
Merci à tous pour votre attention.