Commençons par un petit calcul. On aimerait appliquer dans notre super cool démo du système solaire une
texture de nuages sur notre belle planète Terre. La texture que nous avons est un fichier jpg d'une taille de 1539k
et d'une résolution de 4096 x 2048. Comme nous voulons faire un effet de transparence, nous la chargerons avec
un des formats disponibles sous Demoniak3D qui est le RGBA Float. La question est: quelle est la taille occupée
par la texture dans la mémoire de la carte graphique?
Dans le format RGBA Float, chaque canal est codé sur un float. Le float est la façon classique pour désigner
un nombre réel. Un float fait 4 octets de taille. Donc un pixel ou mieux, un texel (texture element) est
codé sur 4 x 4 = 16 octets. Finalement, la texture complète occupera 4096 x 2048 x 16 = 134317728 octets, soit environ
128 Mo... Sur une carte 3D standard, équipée de 128 Mo de mémoire graphique, ça fait un peu beaucoup. Surtout que
la mémoire graphique n'est pas entièrement réservée au stockage de texture (pour plus de précision sur cette
dernière affirmation, voir le tutorial concerné à la carte graphique:
Graphics Controllers).
La solution à cet épineux problème tient en 4 lettres:
S3TC.
S3TC est le standard en matière de compression de texture depuis un certain temps déjà. Le terme S3TC
signifie S3 Texture Compression. S3TC est un algorithme de compression qui possède plusieurs variantes plus
connues sous les noms de
DXT1,
DXT3 et
DXT5.
S3TC définit une classe d'algorithmes pour la compression hardware et surtout pour la décompression hardware. Afin de pouvoir en
profiter, il est impératif que la carte graphique supporte la compression S3TC. Pour le savoir, un rapide coup d'oeil
au logiciel
HardwareInfos nous permet d'être fixés. La carte supporte le S3TC si
dans la liste "OpenGL GPU Capabilities" on trouve [+]S3TC. Une autre façon de vérifier est d'afficher la liste des extensions OpenGL
(bouton OpenGL Extensions List) et de chercher l'extension
GL_EXT_texture_compression_s3tc. En règle générale, une carte supportant
le S3TC en OpenGL, le supporte aussi en Direct3D.
Mais que nous apporte vraiment la compression de texture ? Tout d'abord un gain de place au niveau de la mémoire de la carte graphique qui peut atteindre un ratio de 1 pour 10.
Ensuite le temps de chargement disque dur vers la mémoire graphique s'en trouve considérablement accéléré puisque, et c'est là la grande force des
fichiers de textures compressées, le chargement est direct. Il n'y a plus les phases de décodage du fichier de texture et de conversion dans
le format de pixel le plus adapté pour l'utilisation de la texture.
Le format de fichier standard pour le stockage des textures compressées est le
DDS. DDS provient de
Direct Draw Surface et porte bien son nom dans le sens
où le contenu d'un fichier DDS est la copie directe (à l'entête du fichier près) de la texture contenue dans la mémoire de la carte graphique. Ceci explique
la vitesse des temps de chargement des fichiers DDS même pour des textures de haute résolution (4096 x 2048 par exemple).
Un autre avantage est la présence, dans le fichier de texture, des
mipmaps. Pour rappel, les mipmaps sont des copies de la texture de base (qui fait aussi partie du jeu de mipmaps) mais dont les dimensions
sont successivement divisées par 2. Si la texture de base (ou mipmap 0) fait 2048x1024, les mipmaps (mipmaps 1 à n) auront les tailles suivantes: 1024x512, 512x256, 256x128, 128x64, 64x32, 32x16, 16x8 et 8x4 si on a généré 8 mipmaps.
Le
mipmapping, terme venant du latin
multum in parvo (beaucoup de choses dans une petite place), permet à la carte graphique de choisir automatiquement la bonne mipmap à affichier
en fonction de la distance entre la caméra et la texture à afficher. L'algorithme de mipmapping peut se résumer ainsi: le choix de la mipmap à afficher (0, 1, ... 8) est proportionnel à la distance entre la caméra et la texture.
Le mipmapping est très utile car il permet de réduire de manière notable les défauts visuels (bruit dans la texture) et diminue le temps de rendu. Rien que ça!
Pour constater la réduction des défauts visuels, chargez le
code sample 15 dans Demoniak3D et comparez
le plan de droite et de gauche. Cela saute aux yeux. Le plan de gauche est texturé en utilisant du mipmapping tandis que le plan de droite ne
possède qu'une simple texture.
Fig. 1 - Code Sample 15Dans le fichier DDS, les différentes mipmaps sont déjà au bon format et bien sûr compressées. Ce qui fait que le temps de chargement global d'une texture et de
ses mipmaps est très rapide. Pour vous en convaincre, faites le test avec le logiciel
DXTViewer.
DXTViewer est un utilitaire
vous permettant de voir des textures compressées S3TC. Il permet aussi de savoir si une carte graphique donnée supporte la compression de texture.
DXTViewer est livré avec deux textures de test. La première est au format JPG et la seconde au format DDS. Chargez d'abord earth_4096x2048.jpg (en cliquant simplement
sur OK dans la boîte Texture Loading Options) et notez le temps de chargement qui est de plusieurs secondes (entre 5 et 10 sec.). Maintenant chargez
earth_4096x2048_DXT1.dds. Le chargement est quasi-immédiat!
Fig. 2 - DXTViewerMaintenant voyons un exemple concret avec la réalisation de la planète Terre. Pour cela, télécharger le
code sample 100 et chargez-le dans Demoniak3D.
Ce code sample utilise pour être réaliste des textures de grandes dimensions: 4096 x 2048 pour la surface de la Terre et 2048 x 1024 pour les nuages.
Fig. 3 - Code Sample 100 - la Terre vue de loinLa figure 3 nous montre le rendu de la Terre vue de loin tandis que la figure 4 nous montre la Terre de près. De loin la Terre est rendue sans défauts visuels et de près les details sont conservés.
Fig. 4 - Code Sample 100 - la Terre vue de prèsLe code du CS100 ne pose pas de difficultés particulières. La texture de la Terre est déclarée dans le noeud texture suivant:
<texture name="earth_tex" filename="data/earth_4096x2048_DXT1.dds"
filtering_mode="TRILINEAR" anisotropy="8.0" />
Pour la surface terreste, la démo utilise une texture compressée suivant le schéma DXT1. Ce type de compression est particulièrement bien
adapté si la texture ne nécessite pas de composante alpha. DXT1 s'applique aux textures RGB. Pour la couche nuageuse, c'est une autre
histoire puisqu'il nous faut gérer de la transparence. L'effet de transparence sera réalisé en utilsant l'alpha blending et pour cela il nous faut une
texture avec le canal alpha. Mais que doit contenir le canal alpha ? Pour y répondre, jettons un coup d'oeil sur la texture des nuages:
Fig. 5 - Code Sample 100 - texture des nuagesLe but est d'avoir une transparence totale pour les zones en noir (alpha=0.0), d'avoir une transparence nulle pour les zones fortement
nuageuses (alpha=1.0) et une transparence partielle pour les zones où la couche nuageuse n'est pas épaisse (alpha>0.0 et alpha<1.0).
Vu que l'on utilise un format de texture compressée, il n'est pas possible dans Demoniak3D de modifier dynamiquement le contenu du
canal alpha. Il faut donc que la texture soit livrée avec le canal alpha correctement initialisé. Pour y parvenir, nous allons
utiliser DXTViewer, qui nous permettra, à partir du fichier de texture original (clouds.bmp) de créer cette texture compressée
avec le canal alpha contenant les bonnes valeurs.
Commencez par charger la texture clouds.bmp dans DXTViewer. Sélectionnez ensuite le format de texel (texel = texture element) RGBA Float et sélectionnez
Create Opacity Map. Cette dernière option permet d'initialiser la valeur du canal alpha comme on le souhaite. Une
opacity-map au sens de Demoniak3D, est une texture
dont le canal alpha est la moyenne arithmétique des trois canaux rgb. Exactement ce qu'il nous faut!
Fig. 6 - DXTViewer - Texture Loading OptionsUne fois la texture chargée dans la carte graphique, DXTViewer nous montre le format de compression: DXT5. Ce format est le plus
utilisé lorsqu'il s'agit de compresser des textures possédant un canal alpha. A présent, il ne nous reste plus qu'à enregistrer la texture
sur le disque dur. Pour cela, nous allons utiliser le seul format que propose actuellement DXTViewer, à savoir le format O3TC.
Ce format, à l'entête du fichier près, est comparable au format DDS. Maintenant que nous avons notre texture de nuage compressée, il ne
nous reste plus qu'à la charger grâce au bout de code suivant:
<texture name="clouds_tex" filename="data/clouds_DXT5.o3tc"
filtering_mode="TRILINEAR" anisotropy="8.0" />
L'effet de transparence est réalisé en activant le blending (mélange des couleurs) au niveau du mesh qui recevra la texture des nuages
avec l'élément blending_params comme le montre le code suivant:
<mesh name="clouds_mesh" render="TRUE" shape_type="SPHERE"
lighting="TRUE" auto_spin="TRUE" texturing="TRUE"
back_face_culling="FALSE" >
<blending_params active="TRUE"
src_factor="BLENDING_FACTOR_SRC_ALPHA"
dst_factor="BLENDING_FACTOR_ONE_MINUS_SRC_ALPHA" />
<sphere stacks="60" slices="60" radius="51.0" />
<position x="0.0" y="0.0" z="0.0" />
<orientation pitch="90.0" />
<attach_material name="clouds_mat" />
<texture material_name="clouds_mat"
texture_name="clouds_tex"
texture_unit="0" />
<spin_values x="1.0" y="1.0" z="1.0" />
<vertices_color r="1.0" g="1.0" b="1.0" a="1.0" />
</mesh>
Le choix des facteurs de blending BLENDING_FACTOR_SRC_ALPHA et BLENDING_FACTOR_ONE_MINUS_SRC_ALPHA nous permet d'obtenir cette transparence variable.
Se reporter au tutorial suivant pour plus d'explications sur le blending et l'emploi de ses facteurs:
Blending.
nVidia propose un ensemble d'utilitaires pour manipuler les fichiers DDS dont un plugin d'export pour Photoshop (qui peut aussi s'utiliser avec PaintShopPro
mais j'ai pas eu encore l'occasion de tester). Ce plugin est vraiment pratique pour la génération de fichiers DDS contenant des mipmaps.
Vous pouvez par exemple choisir le type de compression (DXT1, DXT3 ou DXT5), ou encore le nombre de mipmaps.
Cet ensemble d'utilitaires est disponible à l'adresse suivante:
NVIDIA DDS PLug-in.