| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- <!DOCTYPE html><html lang="fr"><head>
- <meta charset="utf-8">
- <title>Textures</title>
- <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
- <meta name="twitter:card" content="summary_large_image">
- <meta name="twitter:site" content="@threejs">
- <meta name="twitter:title" content="Three.js – Textures">
- <meta property="og:image" content="https://threejs.org/files/share.png">
- <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
- <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
- <link rel="stylesheet" href="../resources/lesson.css">
- <link rel="stylesheet" href="../resources/lang.css">
- <script type="importmap">
- {
- "imports": {
- "three": "../../build/three.module.js"
- }
- }
- </script>
- </head>
- <body>
- <div class="container">
- <div class="lesson-title">
- <h1>Textures</h1>
- </div>
- <div class="lesson">
- <div class="lesson-main">
- <p>Cet article fait partie d'une série d'articles sur three.js.
- Le premier article concernait <a href="fundamentals.html">les bases de three.js</a>.
- L'<a href="setup.html">article précédent</a> expliquait comment se préparer pour cet article.
- Si vous ne l'avez pas encore lu, vous pourriez vouloir commencer par là.</p>
- <p>Les textures sont un sujet assez vaste dans Three.js et
- je ne suis pas sûr à 100% du niveau auquel les expliquer, mais je vais essayer.
- Il y a de nombreux sujets et beaucoup d'entre eux sont interdépendants, il est donc difficile d'expliquer
- tout en une seule fois. Voici une table des matières rapide pour cet article.</p>
- <ul>
- <li><a href="#hello">Bonjour la texture</a></li>
- <li><a href="#six">6 textures, une différente sur chaque face d'un cube</a></li>
- <li><a href="#loading">Charger des textures</a></li>
- <ul>
- <li><a href="#easy">La manière simple</a></li>
- <li><a href="#wait1">Attendre le chargement d'une texture</a></li>
- <li><a href="#waitmany">Attendre le chargement de plusieurs textures</a></li>
- <li><a href="#cors">Charger des textures depuis d'autres origines</a></li>
- </ul>
- <li><a href="#memory">Utilisation de la mémoire</a></li>
- <li><a href="#format">JPG vs PNG</a></li>
- <li><a href="#filtering-and-mips">Filtrage et mips</a></li>
- <li><a href="#uvmanipulation">Répétition, décalage, rotation, habillage</a></li>
- </ul>
- <h2 id="-a-name-hello-a-hello-texture"><a name="hello"></a> Bonjour la texture</h2>
- <p>Les textures sont <em>généralement</em> des images qui sont le plus souvent créées
- dans un programme tiers comme Photoshop ou GIMP. Par exemple, mettons
- cette image sur un cube.</p>
- <div class="threejs_center">
- <img src="../examples/resources/images/wall.jpg" style="width: 600px;" class="border">
- </div>
- <p>Nous allons modifier un de nos premiers exemples. Tout ce que nous avons à faire est de créer un <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a>. Appelez sa
- méthode <a href="/docs/#api/en/loaders/TextureLoader#load"><code class="notranslate" translate="no">load</code></a> avec l'URL d'une
- image et définissez la propriété <code class="notranslate" translate="no">map</code> du matériau sur le résultat au lieu de définir sa <code class="notranslate" translate="no">color</code>.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader();
- +const texture = loader.load( 'resources/images/wall.jpg' );
- +texture.colorSpace = THREE.SRGBColorSpace;
- const material = new THREE.MeshBasicMaterial({
- - color: 0xFF8844,
- + map: texture,
- });
- </pre>
- <p>Notez que nous utilisons <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a>, donc pas besoin de lumières.</p>
- <p></p><div translate="no" class="threejs_example_container notranslate">
- <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/textured-cube.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/textured-cube.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <h2 id="-a-name-six-a-6-textures-a-different-one-on-each-face-of-a-cube"><a name="six"></a> 6 textures, une différente sur chaque face d'un cube</h2>
- <p>Que diriez-vous de 6 textures, une sur chaque face d'un cube ?</p>
- <div class="threejs_center">
- <div>
- <img src="../examples/resources/images/flower-1.jpg" style="width: 100px;" class="border">
- <img src="../examples/resources/images/flower-2.jpg" style="width: 100px;" class="border">
- <img src="../examples/resources/images/flower-3.jpg" style="width: 100px;" class="border">
- </div>
- <div>
- <img src="../examples/resources/images/flower-4.jpg" style="width: 100px;" class="border">
- <img src="../examples/resources/images/flower-5.jpg" style="width: 100px;" class="border">
- <img src="../examples/resources/images/flower-6.jpg" style="width: 100px;" class="border">
- </div>
- </div>
- <p>Nous créons simplement 6 matériaux et les passons sous forme de tableau lorsque nous créons le <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a></p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
- -const texture = loader.load( 'resources/images/wall.jpg' );
- -texture.colorSpace = THREE.SRGBColorSpace;
- -const material = new THREE.MeshBasicMaterial({
- - map: texture,
- -});
- +const materials = [
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-1.jpg')}),
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-2.jpg')}),
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-3.jpg')}),
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-4.jpg')}),
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-5.jpg')}),
- + new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-6.jpg')}),
- +];
- -const cube = new THREE.Mesh(geometry, material);
- +const cube = new THREE.Mesh(geometry, materials);
- +function loadColorTexture( path ) {
- + const texture = loader.load( path );
- + texture.colorSpace = THREE.SRGBColorSpace;
- + return texture;
- +}
- </pre>
- <p>Ça marche !</p>
- <p></p><div translate="no" class="threejs_example_container notranslate">
- <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/textured-cube-6-textures.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/textured-cube-6-textures.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <p>Il convient de noter cependant que tous les types de géométrie ne supportent pas plusieurs
- matériaux. <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a> peut utiliser 6 matériaux, un pour chaque face.
- <a href="/docs/#api/en/geometries/ConeGeometry"><code class="notranslate" translate="no">ConeGeometry</code></a> peut utiliser 2 matériaux, un pour le fond et un pour le cône.
- <a href="/docs/#api/en/geometries/CylinderGeometry"><code class="notranslate" translate="no">CylinderGeometry</code></a> peut utiliser 3 matériaux : fond, haut et côté.
- Dans d'autres cas, vous devrez construire ou charger une géométrie personnalisée et/ou modifier les coordonnées de texture.</p>
- <p>Il est beaucoup plus courant dans d'autres moteurs 3D et beaucoup plus performant d'utiliser un
- <a href="https://en.wikipedia.org/wiki/Texture_atlas">atlas de textures</a>
- si vous souhaitez autoriser plusieurs images sur une seule géométrie. Un atlas de textures
- est un endroit où vous placez plusieurs images dans une seule texture et utilisez ensuite les coordonnées de texture
- sur les sommets de votre géométrie pour sélectionner quelles parties d'une texture sont utilisées
- sur chaque triangle de votre géométrie.</p>
- <p>Que sont les coordonnées de texture ? Ce sont des données ajoutées à chaque sommet d'une pièce de géométrie
- qui spécifient quelle partie de la texture correspond à ce sommet spécifique.
- Nous les aborderons lorsque nous commencerons à <a href="custom-buffergeometry.html">construire une géométrie personnalisée</a>.</p>
- <h2 id="-a-name-loading-a-loading-textures"><a name="loading"></a> Chargement des textures</h2>
- <h3 id="-a-name-easy-a-the-easy-way"><a name="easy"></a> La manière simple</h3>
- <p>La plupart du code sur ce site utilise la méthode la plus simple pour charger des textures.
- Nous créons un <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a>, puis appelons sa méthode <a href="/docs/#api/en/loaders/TextureLoader#load"><code class="notranslate" translate="no">load</code></a>.
- Cela renvoie un objet <a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a>.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const texture = loader.load('resources/images/flower-1.jpg');
- </pre>
- <p>Il est important de noter qu'en utilisant cette méthode, notre texture sera transparente jusqu'à
- ce que l'image soit chargée de manière asynchrone par three.js, moment auquel elle mettra à jour la texture
- avec l'image téléchargée.</p>
- <p>Cela présente le grand avantage de ne pas avoir à attendre le chargement de la texture et notre
- page commencera à s'afficher immédiatement. C'est probablement acceptable pour un grand nombre de cas d'utilisation
- mais si nous le souhaitons, nous pouvons demander à three.js de nous informer lorsque la texture a fini de se télécharger.</p>
- <h3 id="-a-name-wait1-a-waiting-for-a-texture-to-load"><a name="wait1"></a> Attendre le chargement d'une texture</h3>
- <p>Pour attendre le chargement d'une texture, la méthode <code class="notranslate" translate="no">load</code> du chargeur de textures prend un rappel
- qui sera appelé lorsque la texture aura fini de se charger. En reprenant notre premier exemple,
- nous pouvons attendre le chargement de la texture avant de créer notre <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> et de l'ajouter à la scène
- comme ceci</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
- loader.load('resources/images/wall.jpg', (texture) => {
- texture.colorSpace = THREE.SRGBColorSpace;
- const material = new THREE.MeshBasicMaterial({
- map: texture,
- });
- const cube = new THREE.Mesh(geometry, material);
- scene.add(cube);
- cubes.push(cube); // add to our list of cubes to rotate
- });
- </pre>
- <p>À moins que vous ne vidiez le cache de votre navigateur et que vous ayez une connexion lente, il est peu probable
- que vous voyiez une différence, mais soyez assuré qu'elle attend le chargement de la texture.</p>
- <p></p><div translate="no" class="threejs_example_container notranslate">
- <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/textured-cube-wait-for-texture.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/textured-cube-wait-for-texture.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <h3 id="-a-name-waitmany-a-waiting-for-multiple-textures-to-load"><a name="waitmany"></a> Attendre le chargement de plusieurs textures</h3>
- <p>Pour attendre que toutes les textures soient chargées, vous pouvez utiliser un <a href="/docs/#api/en/loaders/managers/LoadingManager"><code class="notranslate" translate="no">LoadingManager</code></a>. Créez-en un
- et passez-le au <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a>, puis définissez sa propriété <a href="/docs/#api/en/loaders/managers/LoadingManager#onLoad"><code class="notranslate" translate="no">onLoad</code></a>
- sur un rappel.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loadManager = new THREE.LoadingManager();
- *const loader = new THREE.TextureLoader(loadManager);
- const materials = [
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
- new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
- ];
- +loadManager.onLoad = () => {
- + const cube = new THREE.Mesh(geometry, materials);
- + scene.add(cube);
- + cubes.push(cube); // add to our list of cubes to rotate
- +};
- </pre>
- <p>Le <a href="/docs/#api/en/loaders/managers/LoadingManager"><code class="notranslate" translate="no">LoadingManager</code></a> a également une propriété <a href="/docs/#api/en/loaders/managers/LoadingManager#onProgress"><code class="notranslate" translate="no">onProgress</code></a>
- que nous pouvons définir sur un autre rappel pour afficher un indicateur de progression.</p>
- <p>Nous allons d'abord ajouter une barre de progression en HTML</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><body>
- <canvas id="c"></canvas>
- + <div id="loading">
- + <div class="progress"><div class="progressbar"></div></div>
- + </div>
- </body>
- </pre>
- <p>et le CSS associé</p>
- <pre class="prettyprint showlinemods notranslate lang-css" translate="no">#loading {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- #loading .progress {
- margin: 1.5em;
- border: 1px solid white;
- width: 50vw;
- }
- #loading .progressbar {
- margin: 2px;
- background: white;
- height: 1em;
- transform-origin: top left;
- transform: scaleX(0);
- }
- </pre>
- <p>Ensuite, dans le code, nous mettrons à jour l'échelle de la <code class="notranslate" translate="no">progressbar</code> dans notre rappel <code class="notranslate" translate="no">onProgress</code>. Il est
- appelé avec l'URL du dernier élément chargé, le nombre d'éléments chargés jusqu'à présent et le nombre total
- d'éléments à charger.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loadingElem = document.querySelector('#loading');
- +const progressBarElem = loadingElem.querySelector('.progressbar');
- loadManager.onLoad = () => {
- + loadingElem.style.display = 'none';
- const cube = new THREE.Mesh(geometry, materials);
- scene.add(cube);
- cubes.push(cube); // add to our list of cubes to rotate
- };
- +loadManager.onProgress = (urlOfLastItemLoaded, itemsLoaded, itemsTotal) => {
- + const progress = itemsLoaded / itemsTotal;
- + progressBarElem.style.transform = `scaleX(${progress})`;
- +};
- </pre>
- <p>À moins que vous ne vidiez votre cache et que vous ayez une connexion lente, il est possible que vous ne voyiez
- pas la barre de chargement.</p>
- <p></p><div translate="no" class="threejs_example_container notranslate">
- <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/textured-cube-wait-for-all-textures.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/textured-cube-wait-for-all-textures.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <h2 id="-a-name-cors-a-loading-textures-from-other-origins"><a name="cors"></a> Charger des textures depuis d'autres origines</h2>
- <p>Pour utiliser des images provenant d'autres serveurs, ces serveurs doivent envoyer les en-têtes corrects.
- S'ils ne le font pas, vous ne pouvez pas utiliser les images dans three.js et vous obtiendrez une erreur.
- Si vous gérez le serveur fournissant les images, assurez-vous qu'il
- <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">envoie les en-têtes corrects</a>.
- Si vous ne contrôlez pas le serveur hébergeant les images et qu'il n'envoie pas les
- en-têtes d'autorisation, vous ne pouvez pas utiliser les images de ce serveur.</p>
- <p>Par exemple, <a href="https://imgur.com">imgur</a>, <a href="https://flickr.com">flickr</a> et
- <a href="https://github.com">github</a> envoient tous des en-têtes vous permettant d'utiliser les images
- hébergées sur leurs serveurs dans three.js. La plupart des autres sites web ne le font pas.</p>
- <h2 id="-a-name-memory-a-memory-usage"><a name="memory"></a> Utilisation de la mémoire</h2>
- <p>Les textures sont souvent la partie d'une application three.js qui utilise le plus de mémoire. Il est important de comprendre
- qu'<em>en général</em>, les textures prennent <code class="notranslate" translate="no">largeur * hauteur * 4 * 1.33</code> octets de mémoire.</p>
- <p>Notez que cela ne dit rien sur la compression. Je peux créer une image .jpg et régler sa compression très élevée.
- Par exemple, disons que je créais une scène d'une maison. À l'intérieur de la maison, il y a une table
- et je décide de mettre cette texture de bois sur la surface supérieure de la table</p>
- <div class="threejs_center"><img class="border" src="../resources/images/compressed-but-large-wood-texture.jpg" align="center" style="width: 300px"></div>
- <p>Cette image ne fait que 157k, elle se téléchargera donc relativement rapidement, mais <a href="resources/images/compressed-but-large-wood-texture.jpg">sa taille est en réalité
- de 3024 x 3761 pixels</a>.
- En suivant l'équation ci-dessus, cela donne</p>
- <pre class="prettyprint showlinemods notranslate notranslate" translate="no">3024 * 3761 * 4 * 1.33 = 60505764.5
- </pre><p>Cette image prendra <strong>60 MÉGAOCTETS DE MÉMOIRE !</strong> dans three.js.
- Quelques textures comme celle-là et vous serez à court de mémoire.</p>
- <p>Je soulève ce point car il est important de savoir que l'utilisation des textures a un coût caché.
- Pour que three.js puisse utiliser la texture, il doit la transmettre au GPU, et le
- GPU <em>en général</em> nécessite que les données de la texture soient décompressées.</p>
- <p>La morale de l'histoire est de rendre vos textures petites en dimensions, pas seulement petites
- en taille de fichier. Petite taille de fichier = téléchargement rapide. Petites dimensions = prend
- moins de mémoire. Quelle taille devraient-elles avoir ?
- Aussi petites que possible tout en conservant l'apparence dont vous avez besoin.</p>
- <h2 id="-a-name-format-a-jpg-vs-png"><a name="format"></a> JPG vs PNG</h2>
- <p>C'est à peu près la même chose qu'en HTML classique : les JPG ont une compression avec perte,
- les PNG ont une compression sans perte, donc les PNG sont généralement plus lents à télécharger.
- Mais les PNG supportent la transparence. Les PNG sont également probablement le format
- approprié pour les données non-image comme les normal maps et d'autres types de maps non-image que nous verrons plus tard.</p>
- <p>Il est important de se rappeler qu'un JPG n'utilise
- pas moins de mémoire qu'un PNG dans WebGL. Voir ci-dessus.</p>
- <h2 id="-a-name-filtering-and-mips-a-filtering-and-mips"><a name="filtering-and-mips"></a> Filtrage et Mips</h2>
- <p>Appliquons cette texture 16x16</p>
- <div class="threejs_center"><img src="../resources/images/mip-low-res-enlarged.png" class="nobg" align="center"></div>
- <p>À un cube</p>
- <div class="spread"><div data-diagram="filterCube"></div></div>
- <p>Dessinons ce cube très petit</p>
- <div class="spread"><div data-diagram="filterCubeSmall"></div></div>
- <p>Hmmm, je suppose que c'est difficile à voir. Agrandissons ce tout petit cube</p>
- <div class="spread"><div data-diagram="filterCubeSmallLowRes"></div></div>
- <p>Comment le GPU sait-il quelles couleurs donner à chaque pixel qu'il dessine pour le petit cube ?
- Que se passerait-il si le cube était si petit qu'il ne fasse qu'un ou deux pixels ?</p>
- <p>C'est à cela que sert le filtrage.</p>
- <p>Si c'était Photoshop, Photoshop ferait la moyenne de presque tous les pixels pour déterminer la couleur
- à donner à ces 1 ou 2 pixels. Ce serait une opération très lente. Les GPU résolvent ce problème
- en utilisant les mipmaps.</p>
- <p>Les mips sont des copies de la texture, chacune faisant la moitié de la largeur et la moitié de la hauteur du mip précédent,
- où les pixels ont été mélangés pour créer le mip suivant plus petit. Les mips sont créés
- jusqu'à ce que l'on arrive à un mip de 1x1 pixel. Pour l'image ci-dessus, tous les mips ressembleraient
- à ceci</p>
- <div class="threejs_center"><img src="../resources/images/mipmap-low-res-enlarged.png" class="nobg" align="center"></div>
- <p>Maintenant, lorsque le cube est dessiné si petit qu'il ne fait qu'un ou deux pixels, le GPU peut choisir
- d'utiliser uniquement le mip le plus petit ou le mip juste avant le plus petit pour décider de la couleur
- à donner au petit cube.</p>
- <p>Dans three.js, vous pouvez choisir ce qui se passe à la fois lorsque la texture est dessinée
- plus grande que sa taille d'origine et ce qui se passe lorsqu'elle est dessinée plus petite que sa
- taille d'origine.</p>
- <p>Pour définir le filtre lorsque la texture est dessinée plus grande que sa taille d'origine,
- vous définissez la propriété <a href="/docs/#api/en/textures/Texture#magFilter"><code class="notranslate" translate="no">texture.magFilter</code></a> sur <code class="notranslate" translate="no">THREE.NearestFilter</code> ou
- <code class="notranslate" translate="no">THREE.LinearFilter</code>. <code class="notranslate" translate="no">NearestFilter</code> signifie
- simplement choisir le pixel unique le plus proche de la texture d'origine. Avec une texture
- basse résolution, cela donne un aspect très pixélisé comme dans Minecraft.</p>
- <p><code class="notranslate" translate="no">LinearFilter</code> signifie choisir les 4 pixels de la texture qui sont les plus proches
- de l'endroit où nous devrions choisir une couleur et les mélanger dans les
- proportions appropriées par rapport à la distance entre le point réel et
- chacun des 4 pixels.</p>
- <div class="spread">
- <div>
- <div data-diagram="filterCubeMagNearest" style="height: 250px;"></div>
- <div class="code">Plus proche</div>
- </div>
- <div>
- <div data-diagram="filterCubeMagLinear" style="height: 250px;"></div>
- <div class="code">Linéaire</div>
- </div>
- </div>
- <p>Pour définir le filtre lorsque la texture est dessinée plus petite que sa taille d'origine,
- vous définissez la propriété <a href="/docs/#api/en/textures/Texture#minFilter"><code class="notranslate" translate="no">texture.minFilter</code></a> sur l'une des 6 valeurs suivantes.</p>
- <ul>
- <li><p><code class="notranslate" translate="no">THREE.NearestFilter</code></p>
- <p> identique à ci-dessus, choisir le pixel le plus proche dans la texture</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.LinearFilter</code></p>
- <p> identique à ci-dessus, choisir 4 pixels de la texture et les mélanger</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.NearestMipmapNearestFilter</code></p>
- <p> choisir le mip approprié puis choisir un pixel</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.NearestMipmapLinearFilter</code></p>
- <p> choisir 2 mips, choisir un pixel de chaque, mélanger les 2 pixels</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.LinearMipmapNearestFilter</code></p>
- <p> choisir le mip approprié puis choisir 4 pixels et les mélanger</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.LinearMipmapLinearFilter</code></p>
- <p>choisir 2 mips, choisir 4 pixels de chaque et mélanger les 8 en 1 pixel</p>
- </li>
- </ul>
- <p>Voici un exemple montrant les 6 paramètres</p>
- <div class="spread">
- <div data-diagram="filterModes" style="
- height: 450px;
- position: relative;
- ">
- <div style="
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- ">
- <div style="
- background: rgba(255,0,0,.8);
- color: white;
- padding: .5em;
- margin: 1em;
- font-size: small;
- border-radius: .5em;
- line-height: 1.2;
- user-select: none;">cliquer pour<br>changer la<br>texture</div>
- </div>
- <div class="filter-caption" style="left: 0.5em; top: 0.5em;">plus proche</div>
- <div class="filter-caption" style="width: 100%; text-align: center; top: 0.5em;">linéaire</div>
- <div class="filter-caption" style="right: 0.5em; text-align: right; top: 0.5em;">plus proche<br>mipmap<br>plus proche</div>
- <div class="filter-caption" style="left: 0.5em; text-align: left; bottom: 0.5em;">plus proche<br>mipmap<br>linéaire</div>
- <div class="filter-caption" style="width: 100%; text-align: center; bottom: 0.5em;">linéaire<br>mipmap<br>plus proche</div>
- <div class="filter-caption" style="right: 0.5em; text-align: right; bottom: 0.5em;">linéaire<br>mipmap<br>linéaire</div>
- </div>
- </div>
- <p>Une chose à remarquer est que le coin supérieur gauche et le milieu supérieur utilisant <code class="notranslate" translate="no">NearestFilter</code> et <code class="notranslate" translate="no">LinearFilter</code>
- n'utilisent pas les mips. De ce fait, ils scintillent au loin car le GPU sélectionne
- des pixels de la texture d'origine. À gauche, un seul pixel est choisi et
- au milieu, 4 sont choisis et mélangés, mais ce n'est pas suffisant pour obtenir une bonne
- couleur représentative. Les 4 autres bandes s'en sortent mieux,
- celle en bas à droite, <code class="notranslate" translate="no">LinearMipmapLinearFilter</code>, étant la meilleure.</p>
- <p>Si vous cliquez sur l'image ci-dessus, elle basculera entre la texture que nous avons utilisée ci-dessus
- et une texture où chaque niveau de mip est d'une couleur différente.</p>
- <div class="threejs_center">
- <div data-texture-diagram="differentColoredMips"></div>
- </div>
- <p>Cela rend plus clair
- ce qui se passe. Vous pouvez voir en haut à gauche et au milieu supérieur que le premier mip est utilisé jusqu'au loin.
- En haut à droite et au milieu inférieur, vous pouvez clairement voir où un mip différent
- est utilisé.</p>
- <p>En revenant à la texture d'origine, vous pouvez voir que celle en bas à droite est la plus lisse,
- de la plus haute qualité. Vous pourriez vous demander pourquoi ne pas toujours utiliser ce mode. La raison
- la plus évidente est que parfois vous voulez que les choses soient pixélisées pour un look rétro ou pour une autre raison.
- La raison suivante la plus courante est que lire 8 pixels et les mélanger est plus lent
- que de lire 1 pixel et de le mélanger. Bien qu'il soit peu probable qu'une seule texture
- fasse la différence entre rapide et lent, à mesure que nous progresserons dans ces articles,
- nous aurons finalement des matériaux qui utilisent 4 ou 5 textures en même temps.
- 4 textures * 8 pixels par texture, c'est rechercher 32 pixels pour chaque pixel rendu.
- Cela peut être particulièrement important à considérer sur les appareils mobiles.</p>
- <h2 id="-a-name-uvmanipulation-a-repeating-offseting-rotating-wrapping-a-texture"><a name="uvmanipulation"></a> Répétition, décalage, rotation, habillage d'une texture</h2>
- <p>Les textures ont des paramètres pour la répétition, le décalage et la rotation d'une texture.</p>
- <p>Par défaut, les textures dans three.js ne se répètent pas. Pour définir si une
- texture se répète ou non, il existe 2 propriétés : <a href="/docs/#api/en/textures/Texture#wrapS"><code class="notranslate" translate="no">wrapS</code></a> pour l'habillage horizontal
- et <a href="/docs/#api/en/textures/Texture#wrapT"><code class="notranslate" translate="no">wrapT</code></a> pour l'habillage vertical.</p>
- <p>Ils peuvent être définis sur l'une des valeurs suivantes :</p>
- <ul>
- <li><p><code class="notranslate" translate="no">THREE.ClampToEdgeWrapping</code></p>
- <p> le dernier pixel sur chaque bord est répété indéfiniment</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.RepeatWrapping</code></p>
- <p> la texture est répétée</p>
- </li>
- <li><p><code class="notranslate" translate="no">THREE.MirroredRepeatWrapping</code></p>
- <p> la texture est mise en miroir et répétée</p>
- </li>
- </ul>
- <p>Par exemple, pour activer l'habillage dans les deux directions :</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">someTexture.wrapS = THREE.RepeatWrapping;
- someTexture.wrapT = THREE.RepeatWrapping;
- </pre>
- <p>La répétition est définie avec la propriété [repeat] repeat.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const timesToRepeatHorizontally = 4;
- const timesToRepeatVertically = 2;
- someTexture.repeat.set(timesToRepeatHorizontally, timesToRepeatVertically);
- </pre>
- <p>Le décalage de la texture peut être effectué en définissant la propriété <code class="notranslate" translate="no">offset</code>. Les textures
- sont décalées avec des unités où 1 unité = 1 taille de texture. Autrement dit, 0 = pas de décalage
- et 1 = décalage d'une quantité de texture complète.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const xOffset = .5; // offset by half the texture
- const yOffset = .25; // offset by 1/4 the texture
- someTexture.offset.set(xOffset, yOffset);
- </pre>
- <p>La rotation de la texture peut être définie en définissant la propriété <code class="notranslate" translate="no">rotation</code> en radians
- ainsi que la propriété <code class="notranslate" translate="no">center</code> pour choisir le centre de rotation.
- Elle est par défaut à 0,0, ce qui correspond à une rotation depuis le coin inférieur gauche. Comme pour le décalage,
- ces unités sont en taille de texture, donc les définir à <code class="notranslate" translate="no">.5, .5</code> effectuerait une rotation
- autour du centre de la texture.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">someTexture.center.set(.5, .5);
- someTexture.rotation = THREE.MathUtils.degToRad(45);
- </pre>
- <p>Modifions l'exemple du haut ci-dessus pour jouer avec ces valeurs</p>
- <p>Tout d'abord, nous allons conserver une référence à la texture afin de pouvoir la manipuler</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const texture = loader.load('resources/images/wall.jpg');
- const material = new THREE.MeshBasicMaterial({
- - map: loader.load('resources/images/wall.jpg');
- + map: texture,
- });
- </pre>
- <p>Ensuite, nous utiliserons à nouveau <a href="https://github.com/georgealways/lil-gui">lil-gui</a> pour fournir une interface simple.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
- </pre>
- <p>Comme nous l'avons fait dans les exemples précédents avec lil-gui, nous utiliserons une classe simple pour
- donner à lil-gui un objet qu'il peut manipuler en degrés
- mais qui définira une propriété en radians.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">class DegRadHelper {
- constructor(obj, prop) {
- this.obj = obj;
- this.prop = prop;
- }
- get value() {
- return THREE.MathUtils.radToDeg(this.obj[this.prop]);
- }
- set value(v) {
- this.obj[this.prop] = THREE.MathUtils.degToRad(v);
- }
- }
- </pre>
- <p>Nous avons également besoin d'une classe qui convertira une chaîne de caractères comme <code class="notranslate" translate="no">"123"</code> en un
- nombre comme <code class="notranslate" translate="no">123</code>, car three.js nécessite des nombres pour les paramètres d'énumération
- comme <code class="notranslate" translate="no">wrapS</code> et <code class="notranslate" translate="no">wrapT</code>, mais lil-gui n'utilise que des chaînes de caractères pour les énumérations.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">class StringToNumberHelper {
- constructor(obj, prop) {
- this.obj = obj;
- this.prop = prop;
- }
- get value() {
- return this.obj[this.prop];
- }
- set value(v) {
- this.obj[this.prop] = parseFloat(v);
- }
- }
- </pre>
- <p>En utilisant ces classes, nous pouvons configurer une interface graphique simple pour les paramètres ci-dessus</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const wrapModes = {
- 'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
- 'RepeatWrapping': THREE.RepeatWrapping,
- 'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
- };
- function updateTexture() {
- texture.needsUpdate = true;
- }
- const gui = new GUI();
- gui.add(new StringToNumberHelper(texture, 'wrapS'), 'value', wrapModes)
- .name('texture.wrapS')
- .onChange(updateTexture);
- gui.add(new StringToNumberHelper(texture, 'wrapT'), 'value', wrapModes)
- .name('texture.wrapT')
- .onChange(updateTexture);
- gui.add(texture.repeat, 'x', 0, 5, .01).name('texture.repeat.x');
- gui.add(texture.repeat, 'y', 0, 5, .01).name('texture.repeat.y');
- gui.add(texture.offset, 'x', -2, 2, .01).name('texture.offset.x');
- gui.add(texture.offset, 'y', -2, 2, .01).name('texture.offset.y');
- gui.add(texture.center, 'x', -.5, 1.5, .01).name('texture.center.x');
- gui.add(texture.center, 'y', -.5, 1.5, .01).name('texture.center.y');
- gui.add(new DegRadHelper(texture, 'rotation'), 'value', -360, 360)
- .name('texture.rotation');
- </pre>
- <p>La dernière chose à noter à propos de l'exemple est que si vous changez <code class="notranslate" translate="no">wrapS</code> ou
- <code class="notranslate" translate="no">wrapT</code> sur la texture, vous devez également définir <a href="/docs/#api/en/textures/Texture#needsUpdate"><code class="notranslate" translate="no">texture.needsUpdate</code></a>
- afin que three.js sache qu'il doit appliquer ces paramètres. Les autres paramètres sont appliqués automatiquement.</p>
- <p></p><div translate="no" class="threejs_example_container notranslate">
- <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/textured-cube-adjust.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/textured-cube-adjust.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <p>Ce n'est qu'une étape dans le sujet des textures. À un moment donné, nous aborderons
- les coordonnées de texture ainsi que 9 autres types de textures qui peuvent être appliqués
- aux matériaux.</p>
- <p>Pour l'instant, passons aux <a href="lights.html">lumières</a>.</p>
- <!-- alpha ao env light specular bumpmap ? normalmap ? metalness roughness -->
- <p><link rel="stylesheet" href="../resources/threejs-textures.css"></p>
- <script type="module" src="../resources/threejs-textures.js"></script>
- </div>
- </div>
- </div>
- <script src="../resources/prettify.js"></script>
- <script src="../resources/lesson.js"></script>
- </body></html>
|