| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- <!DOCTYPE html><html lang="fr"><head>
- <meta charset="utf-8">
- <title>Conseils</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 – Tips">
- <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>Conseils</h1>
- </div>
- <div class="lesson">
- <div class="lesson-main">
- <p>Cet article est une collection de petits problèmes que vous pourriez rencontrer
- en utilisant three.js, qui semblaient trop mineurs pour avoir leur propre article.</p>
- <hr>
- <p><a id="screenshot" data-toc="Faire une capture d'écran"></a></p>
- <h1 id="taking-a-screenshot-of-the-canvas">Faire une capture d'écran du Canvas</h1>
- <p>Dans le navigateur, il y a effectivement 2 fonctions qui permettent de prendre une capture d'écran.
- L'ancienne
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL"><code class="notranslate" translate="no">canvas.toDataURL</code></a>
- et la nouvelle, meilleure,
- <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob"><code class="notranslate" translate="no">canvas.toBlob</code></a></p>
- <p>On pourrait donc penser qu'il serait facile de prendre une capture d'écran en ajoutant simplement du code comme</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><canvas id="c"></canvas>
- +<button id="screenshot" type="button">Enregistrer...</button>
- </pre>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const elem = document.querySelector('#screenshot');
- elem.addEventListener('click', () => {
- canvas.toBlob((blob) => {
- saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
- });
- });
- const saveBlob = (function() {
- const a = document.createElement('a');
- document.body.appendChild(a);
- a.style.display = 'none';
- return function saveData(blob, fileName) {
- const url = window.URL.createObjectURL(blob);
- a.href = url;
- a.download = fileName;
- a.click();
- };
- }());
- </pre>
- <p>Voici l'exemple de <a href="responsive.html">l'article sur la réactivité</a>
- avec le code ci-dessus ajouté et un peu de CSS pour positionner le bouton</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/tips-screenshot-bad.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-screenshot-bad.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <p>Lorsque je l'ai essayé, j'ai obtenu cette capture d'écran</p>
- <div class="threejs_center"><img src="../resources/images/screencapture-413x313.png"></div>
- <p>Oui, c'est juste une image noire.</p>
- <p>Il est possible que cela ait fonctionné pour vous selon votre navigateur/OS mais en général,
- il est peu probable que cela fonctionne.</p>
- <p>Le problème est que, pour des raisons de performance et de compatibilité, par défaut, le navigateur
- efface le buffer de dessin d'un canvas WebGL après y avoir dessiné.</p>
- <p>La solution est d'appeler votre code de rendu juste avant la capture.</p>
- <p>Dans notre code, nous devons ajuster quelques éléments. D'abord, séparons
- le code de rendu.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const state = {
- + time: 0,
- +};
- -function render(time) {
- - time *= 0.001;
- +function render() {
- if (resizeRendererToDisplaySize(renderer)) {
- const canvas = renderer.domElement;
- camera.aspect = canvas.clientWidth / canvas.clientHeight;
- camera.updateProjectionMatrix();
- }
- cubes.forEach((cube, ndx) => {
- const speed = 1 + ndx * .1;
- - const rot = time * speed;
- + const rot = state.time * speed;
- cube.rotation.x = rot;
- cube.rotation.y = rot;
- });
- renderer.render(scene, camera);
- - requestAnimationFrame(render);
- }
- +function animate(time) {
- + state.time = time * 0.001;
- +
- + render();
- +
- + requestAnimationFrame(animate);
- +}
- +requestAnimationFrame(animate);
- </pre>
- <p>Maintenant que <code class="notranslate" translate="no">render</code> ne s'occupe que du rendu effectif,
- nous pouvons l'appeler juste avant de capturer le canvas.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const elem = document.querySelector('#screenshot');
- elem.addEventListener('click', () => {
- + render();
- canvas.toBlob((blob) => {
- saveBlob(blob, `screencapture-${canvas.width}x-${canvas.height}.png`);
- });
- });
- </pre>
- <p>Et maintenant, ça devrait marcher.</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/tips-screenshot-good.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-screenshot-good.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <p>Pour une solution différente, voir l'élément suivant.</p>
- <hr>
- <p><a id="preservedrawingbuffer" data-toc="Empêcher l'effacement du Canvas"></a></p>
- <h1 id="preventing-the-canvas-being-cleared">Empêcher l'effacement du canvas</h1>
- <p>Supposons que vous vouliez permettre à l'utilisateur de peindre avec un objet
- animé. Vous devez passer <code class="notranslate" translate="no">preserveDrawingBuffer: true</code> lorsque
- vous créez le <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>. Cela empêche le navigateur d'effacer
- le canvas. Vous devez également dire à three.js de ne pas effacer
- le canvas.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
- -const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
- +const renderer = new THREE.WebGLRenderer({
- + canvas,
- + preserveDrawingBuffer: true,
- + alpha: true,
- +});
- +renderer.autoClearColor = false;
- </pre>
- <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/tips-preservedrawingbuffer.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-preservedrawingbuffer.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <p>Notez que si vous étiez sérieux au sujet de la création d'un programme de dessin, ce ne serait pas une
- solution car le navigateur effacera toujours le canvas chaque fois que sa
- résolution change. Nous modifions sa résolution en fonction de sa taille d'affichage. Sa taille d'affichage
- change lorsque la fenêtre change de taille. Cela inclut lorsque l'utilisateur télécharge
- un fichier, même dans un autre onglet, et que le navigateur ajoute une barre d'état. Cela inclut également lorsque
- l'utilisateur tourne son téléphone et que le navigateur passe du mode portrait au mode paysage.</p>
- <p>Si vous vouliez vraiment créer un programme de dessin, vous devriez
- <a href="rendertargets.html">faire le rendu sur une texture en utilisant une cible de rendu</a>.</p>
- <hr>
- <p><a id="tabindex" data-toc="Obtenir la saisie clavier d'un Canvas"></a></p>
- <h1 id="getting-keyboard-input">Obtenir la saisie clavier</h1>
- <p>Tout au long de ces tutoriels, nous avons souvent attaché des écouteurs d'événements au <code class="notranslate" translate="no">canvas</code>.
- Bien que de nombreux événements fonctionnent, un qui ne fonctionne pas par défaut est l'événement
- clavier.</p>
- <p>Pour obtenir les événements clavier, définissez le <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/tabIndex"><code class="notranslate" translate="no">tabindex</code></a>
- du canvas à 0 ou plus. Par exemple :</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><canvas tabindex="0"></canvas>
- </pre>
- <p>Cela finit cependant par causer un nouveau problème. Tout élément ayant un <code class="notranslate" translate="no">tabindex</code> défini
- sera mis en évidence lorsqu'il aura le focus. Pour résoudre ce problème, définissez son contour de focus CSS
- à none (aucun)</p>
- <pre class="prettyprint showlinemods notranslate lang-css" translate="no">canvas:focus {
- outline:none;
- }
- </pre>
- <p>Pour démontrer, voici 3 canvas</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><canvas id="c1"></canvas>
- <canvas id="c2" tabindex="0"></canvas>
- <canvas id="c3" tabindex="1"></canvas>
- </pre>
- <p>et un peu de css juste pour le dernier canvas</p>
- <pre class="prettyprint showlinemods notranslate lang-css" translate="no">#c3:focus {
- outline: none;
- }
- </pre>
- <p>Notez que vous ne pouvez pas faire en sorte que le premier canvas accepte les saisies clavier.
- Le deuxième canvas le peut, mais il est mis en évidence. Le 3ème
- canvas a les deux solutions appliquées.</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/tips-tabindex.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-tabindex.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <hr>
- <p><a id="transparent-canvas" data-toc="Rendre le Canvas Transparent"></a></p>
- <h1 id="making-the-canvas-transparent">Rendre le Canvas Transparent</h1>
- <p>Par défaut, THREE.js rend le canvas opaque. Si vous voulez que le
- canvas soit transparent, passez <a href="/docs/#api/en/renderers/WebGLRenderer#alpha"><code class="notranslate" translate="no">alpha:true</code></a> lorsque vous créez
- le <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a></p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
- -const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
- +const renderer = new THREE.WebGLRenderer({
- + canvas,
- + alpha: true,
- +});
- </pre>
- <p>Vous voudrez probablement aussi lui dire que vos résultats <strong>n'utilisent pas</strong> l'alpha prémultiplié</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const canvas = document.querySelector('#c');
- const renderer = new THREE.WebGLRenderer({
- canvas,
- alpha: true,
- + premultipliedAlpha: false,
- });
- </pre>
- <p>Three.js utilise par défaut <a href="/docs/#api/en/renderers/WebGLRenderer#premultipliedAlpha"><code class="notranslate" translate="no">premultipliedAlpha: true</code></a> pour le canvas,
- mais par défaut, les matériaux génèrent <a href="/docs/#api/en/materials/Material#premultipliedAlpha"><code class="notranslate" translate="no">premultipliedAlpha: false</code></a>.</p>
- <p>Si vous souhaitez mieux comprendre quand utiliser ou non l'alpha prémultiplié,
- voici <a href="https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre">un bon article à ce sujet</a>.</p>
- <p>En tout cas, configurons un exemple simple avec un canvas transparent.</p>
- <p>Nous avons appliqué les paramètres ci-dessus à l'exemple de <a href="responsive.html">l'article sur la réactivité</a>.
- Rendons également les matériaux plus transparents.</p>
- <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function makeInstance(geometry, color, x) {
- - const material = new THREE.MeshPhongMaterial({color});
- + const material = new THREE.MeshPhongMaterial({
- + color,
- + opacity: 0.5,
- + });
- ...
- </pre>
- <p>Et ajoutons un peu de contenu HTML</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><body>
- <canvas id="c"></canvas>
- + <div id="content">
- + <div>
- + <h1>Cubes-R-Us !</h1>
- + <p>Nous fabriquons les meilleurs cubes !</p>
- + </div>
- + </div>
- </body>
- </pre>
- <p>ainsi qu'un peu de CSS pour placer le canvas devant</p>
- <pre class="prettyprint showlinemods notranslate lang-css" translate="no">body {
- margin: 0;
- }
- #c {
- width: 100%;
- height: 100%;
- display: block;
- + position: fixed;
- + left: 0;
- + top: 0;
- + z-index: 2;
- + pointer-events: none;
- }
- +#content {
- + font-size: 7vw;
- + font-family: sans-serif;
- + text-align: center;
- + width: 100%;
- + height: 100%;
- + display: flex;
- + justify-content: center;
- + align-items: center;
- +}
- </pre>
- <p>Notez que <code class="notranslate" translate="no">pointer-events: none</code> rend le canvas invisible aux événements de souris
- et tactiles afin que vous puissiez sélectionner le texte en dessous.</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/tips-transparent-canvas.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-transparent-canvas.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- <hr>
- <p><a id="html-background" data-toc="Utiliser three.js comme fond en HTML"></a></p>
- <h1 id="making-your-background-a-three-js-animation">Faire de votre arrière-plan une animation three.js</h1>
- <p>Une question courante est de savoir comment faire en sorte qu'une animation three.js serve d'arrière-plan à
- une page web.</p>
- <p>Il y a 2 façons évidentes.</p>
- <ul>
- <li>Définir la propriété CSS <code>position</code> du canvas sur <code>fixed</code> comme dans</li>
- </ul>
- <pre class="prettyprint showlinemods notranslate lang-css" translate="no">#c {
- position: fixed;
- left: 0;
- top: 0;
- ...
- }
- </pre>
- <p>Vous pouvez voir cette solution exacte dans l'exemple précédent. Il suffit de définir <code>z-index</code> à -1
- et les cubes apparaîtront derrière le texte.</p>
- <p>Un petit inconvénient de cette solution est que votre JavaScript doit s'intégrer à la page
- et si vous avez une page complexe, vous devez vous assurer qu'aucun des scripts JavaScript de votre
- visualisation three.js n'entre en conflit avec le JavaScript effectuant d'autres tâches dans la page.</p>
- <ul>
- <li>Utiliser une <code>iframe</code></li>
- </ul>
- <p>C'est la solution utilisée sur <a href="/">la page d'accueil de ce site</a>.</p>
- <p>Dans votre page web, insérez simplement une iframe, par exemple :</p>
- <pre class="prettyprint showlinemods notranslate lang-html" translate="no"><iframe id="background" src="responsive.html">
- <div>
- Votre contenu ici.
- </div>
- </pre>
- <p>Ensuite, stylisez l'iframe pour qu'elle remplisse la fenêtre et soit en arrière-plan,
- ce qui est essentiellement le même code que nous avons utilisé ci-dessus pour le canvas,
- sauf que nous devons également définir <code>border</code> à <code>none</code> car les iframes ont
- une bordure par défaut.</p>
- <pre class="prettyprint showlinemods notranslate notranslate" translate="no">#background {
- position: fixed;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- z-index: -1;
- border: none;
- pointer-events: none;
- }
- </pre><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/tips-html-background.html"></iframe></div>
- <a class="threejs_center" href="/manual/examples/tips-html-background.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
- </div>
- <p></p>
- </div>
- </div>
- </div>
- <script src="../resources/prettify.js"></script>
- <script src="../resources/lesson.js"></script>
- </body></html>
|