Cours 09 - useState et R3F
État d’une composante
Section intitulée « État d’une composante »Le hook useState doit être importé depuis le package React et permet de déclarer un getter et un setter d’une variable que l’on voudra afficher et modifier à l’intérieur de la composante.
L’utilisation du setter lancera un nouveau rendu de la composante pour mettre à jour son jsx. Comme ces getters/setters sont retournés dans un tableau, il est d’usage d’utiliser la syntaxe de décomposition pour les déclarer:
'use client';
import {useState} from 'react';
const UneComposante = (props) => {
// useState nous retourne le getter puis le setter dans un tableau // on passe la valeur initiale en paramètre // le getter est passé en premier dans le tableau // le setter est passé en deuxième dans le tableau
/* const tableauNomState = useState('Jimmy'); //on passe la valeur initiale en paramètre const nom = tableauNomState[0]; // le getter est passé en premier dans le tableau const setNom = tableauNomState[1]; // le setter est passé en deuxième dans le tableau */
// On utilisera la décomposition d'un tableau pour réduire la taille du code utilisé const [currentNom, setNom] = useState('Jimmy'); // remplace les 3 lignes de code ci-haut
const onClickHandler = () => { setNom('Bob'); };
return ( <div> <h3>{currentNom}</h3> <button onClick={onClickHandler}>Clic!</button> </div> );};Deux syntaxes pour mettre l’état à jour
Section intitulée « Deux syntaxes pour mettre l’état à jour »Selon ce qui est à faire, le développeur sera appelé à utiliser l’une ou l’autre des deux syntaxes à suivre pour mettre l’état à jour.
Si l’utilisateur souhaite remplacer la valeur de l’état sans utiliser la valeur précédente:
'use client';
import {useState} from 'react';
const UneComposante = (props) => { const [currentNom, setNom] = useState('Jimmy');
const onClickHandler = () => { setNom('Bob'); // La valeur précédente, Jimmy, n'est pas nécessaire ici };
return ( <div> <h3>{currentNom}</h3> <button onClick={onClickHandler}>Clic!</button> </div> );};Si l’utilisateur souhaite remplacer la valeur de l’état en utilisant la valeur précédente:
'use client';
import {useState} from 'react';
const UneComposante = (props) => { const [compteur, setCompteur] = useState(1);
const onClickHandler = () => { // On utilise ici la valeur précédente de l'état pour l'incrémenter // On passe une fonction qui reçoit la valeur précédente // et retourne la nouvelle valeur setCompteur(currentVal => currentVal + 1); };
return ( <div> <h3>{compteur}</h3> <button onClick={onClickHandler}>Clic!</button> </div> );};Three.js et React-three-fiber (R3F)
Section intitulée « Three.js et React-three-fiber (R3F) »Three.js
Section intitulée « Three.js »Three.js est une librairie Javascript permettant facilement d’exploiter les APIs Webgl et WebGPU du navigateur afin de faire le rendu et de créer des expériences 3D interactives. Le code y est rédigé de façon impérative et nécessite beaucoup de travail manuel afin de créer une scène (instantiation et configuration d’un renderer, d’une scène, d’une caméra…). Ex:
import * as THREE from 'three';
// Initialisation de la scène, caméra et rendererconst scene = new THREE.Scene();const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);
// Création d'un meshconst geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshBasicMaterial({ color: 0x4caf50 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);
camera.position.z = 5;
// onUpdatefunction animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera);}animate();
// Redimensionnement du navigateurwindow.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);});React-three-fiber (R3F)
Section intitulée « React-three-fiber (R3F) »R3F est une librairie supplémentaire développée par le collectif Poimandres permettant de déclarer le contenu d’une scène à l’aide de composantes R3F en plus d’initialiser automatiquement la plupart des éléments nécessaires. Tout demeure cependant du Three.js sous le capot.
Voici le code rédigé ci-haut en version R3F:
import React, { useRef } from 'react';import { Canvas, useFrame } from '@react-three/fiber';
const Cube = () => { const meshRef = useRef();
// onUpdate useFrame(() => { meshRef.current.rotation.x += 0.01; meshRef.current.rotation.y += 0.01; });
return ( <mesh ref={meshRef}> <boxGeometry args={[1, 1, 1]} /> <meshBasicMaterial color="#4caf50" /> </mesh> );};
export default function App() { // la caméra, le renderer et l'autoresize sont déjà gérées // en utilisant la composante Canvas return ( <Canvas camera={{ position: [0, 0, 5] }}> <Cube /> </Canvas> );}Installation
Section intitulée « Installation »Les librairies Drei et Leva seront installées en plus de Three.js et R3F afin de profiter de différents outils utiles au développement.
npm i three @react-three/fiber @react-three/drei levaAssemblage
Section intitulée « Assemblage »Tous les éléments propres à Three.js/R3F doivent être insérés dans des composantes client et dans une seule composante <Canvas>.
Vous pourrez remplacer cette composante par <CanvasTIM> (déposée sur Teams dans _ressources).
Props de CanvasTIM
Section intitulée « Props de CanvasTIM »- showAxes: (booléen,
truepar défaut): Affiche les axes et leur sens dans la scène. - showGrid: (booléen,
truepar défaut): Affiche une grille de positionnement depuis l’origine. - useOrbitControls: (booléen,
truepar défaut): Permet de se déplacer et zoomer librement dans la scène. Utilise la librairie Drei.
Il vous est ensuite conseillé d’utiliser une composante différente pour la scène dans laquelle seront ajoutés les mesh 3D et l’éclairage:
"use client";
import CanvasTIM from "./CanvasTIM";
const ComposanteClient = () => { return ( <div className="ClientWrapper"> <div> <CanvasTIM> <Scene /> </CanvasTIM> </div> </div> );};
const Scene = () => { return ( <> { /* Regrouper les éléments de la scène ici */ } </> );};
export default ComposanteClient;Mesh (maillage) 3D
Section intitulée « Mesh (maillage) 3D »Les meshes sont assemblés par imbrication en utilisant une composante <mesh> contenant habituellement une géométrie (forme) et un material (aspect visuel).
<mesh> <boxGeometry/> <meshBasicMaterial/> </mesh>Les éléments qui composent la scène peuvent également être regroupés (comme on le ferait dans un logiciel 3D) en utilisant la composante <group>:
<group> <mesh> <boxGeometry/> <meshBasicMaterial/> </mesh>
<mesh> <boxGeometry/> <meshBasicMaterial/> </mesh> </group>Propriétés courantes d’un mesh
Section intitulée « Propriétés courantes d’un mesh »Les propriétés des mesh peuvent être retrouvés dans la documentation de la classe Mesh ainsi que, par héritage, de la classe Object3D.
position:
Section intitulée « position: »Tableau de 3 valeurs (x, y, z):
<mesh position={[0, 2, 1]}>
rotation:
Section intitulée « rotation: »Tableau de 3 valeurs en radians sachant que 360 degrés = 2 * Math.PI.
<mesh rotation={[Math.PI / 4, 0, 0]}>
Tableau de 3 valeurs sachant que la taille actuelle de l’objet est égale à 1.
<mesh scale={[1.5, 1.5, 1.5]}>
Valeur booléenne. Active la visibilité de l’objet sans le détruire.
écouteurs d’événements
Section intitulée « écouteurs d’événements »R3F rend possible l’utilisation d’écouteurs d’événements sans utiliser de Raycast manuellement.
- onClick
- onContextMenu: Right click ou long press sur mobile
- onDoubleClick
- onPointerUp: Bouton gauche ou droit
- onPointerDown: Bouton gauche ou droit
- onPointerOver & onPointerEnter
- onPointerMove
- onPointerMissed: Lancé si on clique à l’extérieur de l’objet qui écoute l’événement. Peut aussi être utilisé directement sur Canvas pour détecter n’importe quel clic (release) à l’intérieur sans ajouter un eventListener aux objets.
Modification
Section intitulée « Modification »Comme tous les éléments de la scène 3d, la plupart des propriétés du mesh peuvent être déclarées lors de son instantiation (en les ajoutant dans le jsx).
Elles pourront être modifiées ensuite par programmation en les reliant à un ref (en utilisant useRef). On pourrait aussi appeler les méthodes de cette façon.
const MonMesh = () => { const meshRef = useRef();
const clickHandler = () => { meshRef.current.position.x = 3; // ou meshRef.current.position.set(0, 3, 0); };
return ( <mesh ref={meshRef} position={[0, 1, 0]} onClick={clickHandler}> { /* ... */} </mesh> ); };Constructeur
Section intitulée « Constructeur »En Three.js, les objets sont créés par instantiation en utilisant leur méthode constructeur. Ex:
const geometry = new Three.BoxGeometry(1, 1, 1);Selon la documentation du constructeur de BoxGeometry, les paramètres correspondent, dans l’ordre à la largeur, la hauteur et la profondeur de la géométrie.
En R3F, les paramètres sont passés au constructeur en utilisant toujours la prop args en lui passant les valeurs dans l’ordre sous la forme d’un tableau:
<mesh> <boxGeometry args={[1, 1, 1]}/> // 1m * 1m * 1m</mesh>Géométries
Section intitulée « Géométries »- BoxGeometry
- PlaneGeometry
- CircleGeometry
- ConeGeomtry
- CylinderGeometry
- RingGeometry
- TorusGeometry
- TorusKnotGeometry
- DodecahedronGeometry
- OctahedronGeometry
- TetrahedronGeometry
- IcosahedronGeometry
- SphereGeometry
- ShapeGeometry: Basé sur les courbes
- TubeGeometry
- ExtrudeGeometry
- LatheGeometry
- TextGeometry
Matériaux
Section intitulée « Matériaux »Les matériaux sont utilisés pour appliquer une couleur sur chaque “pixel” visible d’une géométrie.
Les algorithmes décidant de la couleur à appliquer se nomme des Shaders. ThreeJs a plusieurs matériaux et shaders pré-faits.
Propriétés de base d’un matériaux (qu’on utilise comme props en R3F)
Section intitulée « Propriétés de base d’un matériaux (qu’on utilise comme props en R3F) »color: Instance de la classe color (new THREE.Color(‘red’))map: Permet d’appliquer la texturewireframe: booléentransparent: booléenopacity: float la propriété transparent doit être à truealphamap: Texture alpha
Les plus courants
Section intitulée « Les plus courants »Applique la couleur de façon uniforme, sans tenir compte de la lumière (donc complètement plat, sans ombre ni relief).
Applique un couleur en fonction des normales sur un objet 3d. Utile pour le déboggage, mais peut être utilisé tel quel parce que c’est joli.
Le plus performant utilisant la lumière. Supporte les mêmes propriétés que le MeshBasicMaterial, mais nécessite de la lumière pour fonctionner. DIfficile d’obtenir un rendu réaliste. Permet le rendu o’objets mats et non brillants.
Performance meilleure que pour le MeshStandardMaterial, mais moins que le MeshLambertMaterial. Permet la simulation de la brillance sur les surfaces. Propriétés supplémentaires:
shininess: (float) contrôle l’intensité de la réflexion de la lumièrespecular: (couleur) contrôle la couleur de la réflexion de la lumière. Les valeurs sont un peu abstraites, non réalistes.
Pour faire du cellshading. Par défaut on a une coloration en deux parties. Une pour les ombres et une pour la partie éclairée.
Pour ajouter plus d’étapes, on peut utiliser une texture gradient sur la propriété gradientMap. P
ar défaut, les pixels sont étirés, on utilisera NearestFilter sur minFilter et magFilter et on désactivera le mipmapping.
Un standard, basé sur la physique et réagissant à la lumière de l’environnement.
Utilise les textures PBR:
map: Albedo / couleur de baseroughnessMap: En niveaux de gris, contrôle la rugosité de la surface (blanc = rugueux, noir = lisse)metalnessMap: En niveaux de gris, détermine quelles zones de la surface sont métalliques (blanc) ou plastiques (noir).normalMap: En RVB, simule des reliefs (micro) et détails comme des crevasses ou des bosses.aoMap(ambient occlusion): En niveaux de gris, assombrit les recoins ou zones ou la lumière pénètre difficilement.displacementMap: En niveaux de gris, déplace les sommets de la géométrie en 3d (nécessite de la subdivision).bumpMap: Plus simple quenormalMap, utilisant une carte de hauteur en niveau de gris.emissiveMap: En RVB, détermine les zones émettant de la lumière ou brillant dans le noir.alphaMap: En niveaux de gris, gère la transparence de la surface. Mettre la propriététransparentàtrue.envMap: Utilisé pour les reflets du monde autour de l’objet.
Une extension de MeshStandardMaterial, supporte d’autres effets comme:
- clearcoat (float) et clearcoatRoughness (float): Ajoutent une mince couche de vernis sur le matériau. Possède ses propres propriétés de réflexion. Affecte la performance.
- sheen (float), sheenRoughness (float), sheenColor (color): Ajoute un reflet au matériau quand il est vu depuis un angle aigu. Souvent utilisé sur du tissus (chatoiement?).
- iridescence (float), iridescenceIOR (float), iridescenceThicknessRange ([min, max]): Crée un reflet de couleur comme sur une flaque d’essence, du savon, un disque laser…
- transmission (float), ior (index de réfraction, float), thickness (float): Permet à la lumière de traverser le matériau. Contrairement à l’opacité, l’image derrière le matériau avec transmission est déformée. Pour le ior, utiliser la valeurs absolues (Eau: 1.333, Air: 1.000293, Diamant: 2.417)
Lumières
Section intitulée « Lumières »Lumière omnidirectionelle, uniforme. Tous les objets sont éclairés de la même façon. Solution à faible coût pour simuler un éclairage indirect. On l’utilise presque à tous coups pour ajouter une couleur de base aux objets et très couramment en combinaison avec une lumière DirectionalLight.
Paramètres du constructeur
Section intitulée « Paramètres du constructeur »- couleur
- intensité
Lumière semblable au soleil. Comme si les rayons se déplaçaient en parallèle.
Paramètres du constructeur
Section intitulée « Paramètres du constructeur »- couleur
- intensité
import { useRef } from 'react'import { useHelper } from '@react-three/drei'import { DirectionalLightHelper } from 'three'
const SceneLight = () => { const dirLightRef = useRef();
// useHelper(reference, helperConstructor, size, color) useHelper(dirLightRef, DirectionalLightHelper, 2, 'red')
return ( <> <directionalLight ref={dirLightRef} position={[5, 5, 5]} intensity={1.5} /> </> )}Une lumière émise dans toutes les directions depuis un point précis. Utilisée souvent pour remplacer une ampoule. Cette lumière peut émettre des ombres.
Paramètres du constructeur
Section intitulée « Paramètres du constructeur »- couleur
- intensité
- distance
- decay (désintégration): Vitesse à laquelle la vitesse s’atténue avec la distance.
import { useRef } from 'react'import { useHelper } from '@react-three/drei'import { PointLightHelper } from 'three'
const Scene = () => { const pointLightRef = useRef()
useHelper(pointLightRef, PointLightHelper, 0.5, 'blue')
return ( <> <pointLight ref={pointLightRef} position={[-3, 3, 2]} intensity={2} /> </> )};Une lumière émise dans une direction depuis un point précis. Elle est diffusée sous la forme d’un cône qui s’élargit en s’éloignant de son origine. Cette lumière peut émettre des ombres.
Paramètres du constructeur
Section intitulée « Paramètres du constructeur »- couleur
- intensité
- distance
- angle: ouverture en radians
- pénombre: la finesse des bordures du cône
Propriétés
Section intitulée « Propriétés »target: Par défaut le SpotLight pointera vers l’origine (0, 0, 0). La modification de sa rotation ne fonctionnera pas à le changer. Il faut modifier sa propriété target en pointant vers un objet de la scène (en utilisant son ref). Il est possible d’utiliser unobject3d(un peu comme un GameObject vide) comme cible.
import { useRef } from 'react'import { useFrame } from '@react-three/fiber'import { useHelper } from '@react-three/drei'import { SpotLightHelper } from 'three'
const SpotLightScene = () => { const spotLightRef = useRef()
const helper = useHelper(spotLightRef, SpotLightHelper, 'teal')
// Forcer la mise à jour du helper si la lumière ou sa cible bouge useFrame(() => { if (helper.current) { helper.current.update() } })
return ( <> <spotLight ref={spotLightRef} position={[0, 8, 0]} angle={Math.PI / 6} penumbra={0.5} intensity={3} /> </> )};Une source lumineuse positionnée directement au dessus de la scène avec un dégradé entre une couleur pour le ciel et une autre pour la sol. Ne permet pas de projeter des ombres:
Paramètres du constructeur
Section intitulée « Paramètres du constructeur »- couleur du ciel
- couleur du sol
- intensité
import { useRef } from 'react';import { Canvas, useHelper } from '@react-three/drei';import { HemisphereLightHelper } from 'three';
const SceneWithHelper = () => { const hemiLightRef = useRef();
useHelper(hemiLightRef, HemisphereLightHelper, 2);
return ( <> <hemisphereLight ref={hemiLightRef} args={['#ff0055', '#00aaff', 1.5]} position={[0, 10, 0]} />
<mesh position={[0, 0, 0]}> <sphereGeometry args={[1, 32, 32]} /> <meshStandardMaterial roughness={0.3} /> </mesh> </> )};Éclairages les plus courants (suggérés par un ami à moi)
Section intitulée « Éclairages les plus courants (suggérés par un ami à moi) »La combinaison minimale
Section intitulée « La combinaison minimale »const Eclairage = () => { return ( <> <ambientLight intensity={0.5} /> <directionalLight position={[5, 5, 5]} intensity={1.0} /> </> )};Combinaison en trois points
Section intitulée « Combinaison en trois points »Permet de détacher un objet du fond sans laisser de zones noires
const Eclairage = () => { return ( <> <directionalLight position={[5, 5, 5]} intensity={1.5} castShadow shadow-mapSize={[2048, 2048]} />
<directionalLight position={[-5, 3, 5]} intensity={0.4} />
<directionalLight position={[0, 5, -5]} intensity={2.0} />
<ambientLight intensity={0.1} /> </> )}Montage natiruel, extérieur
Section intitulée « Montage natiruel, extérieur »const Eclairage = () => { return ( <> {/* Lumière du ciel : Ciel bleu clair et sol */} <hemisphereLight args={['#87ceeb', '#2c1d11', 0.6]} />
{/* Lumière jaune/blanche chaude très puissante pour reproduire le soleil */} <directionalLight position={[10, 12, 8]} intensity={2.5} castShadow shadow-mapSize={[2048, 2048]} shadow-bias={-0.0001} /> </> )}Lumière douce (style studio)
Section intitulée « Lumière douce (style studio) »const Eclairage = () => { return ( <> <ambientLight intensity={0.7} />
<directionalLight position={[4, 8, 4]} intensity={0.8} />
<directionalLight position={[-4, 8, 4]} intensity={0.8} />
<directionalLight position={[0, 10, 0]} intensity={0.5} castShadow /> </> )}Il y a trois étapes à suivre afin de permettre la projection d’ombres dans une scène dans R3F.
- Pour permettre les ombres la prop
shadowsdoit être activée sur la composante<Canvas>(à l’intérieur de<CanvasTIM>dans votre cas):Activer les ombres sur le canvas <Canvasshadows{/* d'autres props */}>{/* ... */}</Canvas> - Les lumières devant émettre des ombres (et les supportant) doivent porter le prop
castShadow. Les lumières qui le supportent sont les<directionalLight/>,<spotLight/>et<pointLight/>.Activer l'émission d'ombres sur les lumières <directionalLightcastShadowposition={[-5, 3, 5]}intensity={0.4}/> - Les meshes doivent aussi permettre d’émettre des ombres (
castShadow) et/ou afficher celles qui sont projetées sur lui (receiveShadow).Permettre aux meshes de recevoir et/ou émettre une ombre <mesh position={[0, 1, 0]} castShadow receiveShadow><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color="royalblue" /></mesh>
Différent hooks de R3F
Section intitulée « Différent hooks de R3F »useThree
Section intitulée « useThree »Il donne accès à l’état interne de l’application. Il permet donc de récupérer la référence de la caméra active, la taille de l’écran, le renderer ou la scène globale.
Ne pas l’utiliser pour animer quoi que ce soit. Utiliser plutôt useFrame.
import { useThree } from '@react-three/fiber'
const CameraController = () => { // Extraction des éléments clés du state const { camera, size, gl, scene } = useThree()
const clickHandler = () => { // Change la position de la caméra au clic camera.position.set(0, 5, 10) camera.updateProjectionMatrix() }
return <mesh onClick={clickHandler} />};useFrame
Section intitulée « useFrame »Boucle d’animation. Semblable au onUpdate de Unity. Exécutée en générale en 60 et 120 fois par secondes.
useFrame reçoit le state de useThree ainsi que le delta (le temps écoulé en secondes depuis le dernier update) en paramètre.
On multiplie donc souvent les modifications par delta afin d’obtenir des animations fluides.
import { useRef } from 'react'import { useFrame } from '@react-three/fiber'
const CubeRotatif = () => { const meshRef = useRef()
useFrame((state, delta) => { meshRef.current.rotation.y += 1 * delta; // 1 radian par seconde
const elapsedTime = state.clock.getElapsedTime(); meshRef.current.position.y = Math.sin(elapsedTime); })
return ( <mesh ref={meshRef}> <boxGeometry /> <meshStandardMaterial /> </mesh> )};useLoader
Section intitulée « useLoader »Utilisé pour charger des ressources externes (modèles, textures, fichiers audio).
import { useLoader } from '@react-three/fiber';import * as THREE from 'three';
const TexturedCube = () => { const texture = useLoader(THREE.TextureLoader, '/textures/wood_color.jpg');
// Optionnel : Configurer la répétition de la texture // texture.wrapS = THREE.RepeatWrapping; // texture.wrapT = THREE.RepeatWrapping; // texture.repeat.set(2, 2)
return ( <mesh castShadow receiveShadow> <boxGeometry args={[2, 2, 2]} /> <meshStandardMaterial map={texture} roughness={0.4} metalness={0.1} /> </mesh> )};useGLTF (DREI)
Section intitulée « useGLTF (DREI) »Voir plutôt l’outil GLTF > R3F de Poimandres.
useAnimations (DREI)
Section intitulée « useAnimations (DREI) »Permet de lancer les différentes animations d’un modèle. Souvent obtenu depuis l’utilisation de useGLTF.
const { actions, names } = useAnimations(animations, group);- actions est un objet ayant le nom des différentes actions comme propriété
- names est une liste contenant les actions sous forme de string
On lance une animation par:
actions['nom-action'].play();Si on lance plus d’une animation en séquence, celles-ci se combineront plutôt que d’effectuer une transition. On procède donc ainsi:
- Appeler la fonction
fadeOut()sur l’action en cours. - Appeler
reset().fadeIn().play()sur la nouvelle action.
Dans un useEffect:
// Dans cet exemple, newAnimation serait un string // correspondant au nom de la nouvelle animation à jouer useEffect(() => { const action = actions[newAnimation]; if (!action) { return; } action.reset().fadeIn(0.3).play();
return () => { action.fadeOut(0.3); }; }, [newAnimation])Leva est une librairie développée par Poimandres permettant d’afficher des panneaux GUI à l’écran afin de débogguer et faire le réglage de certains paramètres des objets 3d. On pourrait y reproduire quelque peu le comportement des propriétés sérialisées de Unity.
On l’utilisera en phase de prototypage pour appliquer ensuite définitivement les valeurs trouvées. La modification des valeurs du GUI déclenchent un nouveau rendu à chaque fois et ont donc un impact significatif sur les performances.
Utilisation
Section intitulée « Utilisation »Pour ajouter des contrôles, on utiliser tout simplement useControls depuis la composante ciblée en donnant des noms aux propriétés à ajuster sous la forme d’un objet:
import { useControls } from 'leva';
const Cube = () => {
const { position, color, wireframe } = useControls({ // Type Vecteur/Position (génère 3 inputs X, Y, Z) position: { value: { x: 0, y: 0, z: 0 }, step: 0.1, },
// Type Couleur (génère un color picker) color: '#ff0055',
// Type Booléen (génère une checkbox) wireframe: false,})
return ( <mesh position={position}> <boxGeometry /> <meshStandardMaterial color={color} wireframe={wireframe} /> </mesh>)};Configuration avancée
Section intitulée « Configuration avancée »On peut également utiliser des valeurs minimales/maximales (min, max), ajouter une étiquette (label) ainsi que contrôler la valeur de chaque augmentation/réduction pour chaque propriété (step):
const { intensity, scale } = useControls({intensity: { value: 1.5, min: 0, max: 5, step: 0.1, label: 'Intensité'},scale: { value: 1, options: [1, 2, 3] // Menu déroulant},
reset: button(() => console.log('Il faut importer button!'))});Organisation
Section intitulée « Organisation »Un nom optionnel peut être passé comme premier paramètre de useControls:
const { intensity, scale } = useControls('Lumière et intensité', { intensity: {/*...*/}, scale: { /* ... */}});Des sous-dossiers peuvent également être ajoutés en utilisant un folder (qui doit être importé):
const { intensity, scale } = useControls('Lumière et intensité', { intensity: {/*...*/}, scale: { /* ... */}, Apparence: folder({ color: '#ff0055', wireframe: false, })});Drei est une librairie d’extensions et d’outils permettant le développement plus agréable. En plus de l’utilisation démontrée dans les exemples précédents, il peut être amusant d’aller s’aventurer dans la liste de leur ajouts et d’en essayer plusieurs.