Récemment, le développement d'applications Web a connu un nombre croissant d'efforts pour améliorer l'expérience utilisateur en utilisant des graphiques. Avec React Three Fibre (R3F), vous pouvez facilement utiliser les fonctionnalités de trois.js comme composant React, ce qui permet à quiconque d'obtenir facilement des expressions attrayantes.
nous expliquerons en détail comment combiner la bibliothèque de wrapper drei et typescript, et implémenter l'art de pixel généré automatiquement à partir d'images
📌 De plus, cette implémentation n'utilisera aucun modèle 3D spécial et n'utilisera que la géométrie de base (boîte, plan, etc.) fournie par Three.js comme standard, pour créer des expressions rétro mais sophistiquées uniques à l'art pixel.
Les explications étape par étape sont faciles à comprendre même pour les débutants, et le contenu est pour que vous puissiez apprendre tout en travaillant sur vos mains, alors assurez-vous de l'essayer!
💡 Image terminée
📺 Regardez la démo sur YouTube : vous pouvez le regarder à partir de ce lien

Nous continuerons à créer des leçons et travaillent à partir de TypeScript X React Three Fibre à l'avenir!
Nous ferons une annonce sur YouTube, alors veuillez vous abonner à notre chaîne YouTube et attendre les notifications!
📺 Regardez YouTube : vous pouvez le regarder à partir de ce lien
Si vous souhaitez savoir ce que React Three Fibre peut faire, veuillez vous référer à ce qui suit!
Nous avons des travaux faciles à utiliser disponibles!
- J'ai essayé de faire marcher les ours avec React x Three.js!
- J'ai essayé de faire danser un vieil homme sur React x Three.js!
- J'ai essayé d'afficher un modèle 3D avec React x Three.js!
- J'ai fait un bouton 3D qui explose dans React x Three.js!
- Réagir trois fibres x drei x Introduction à TypeScript! Fond 3D de style Poke Poke fait avec des objets standard!
🚀Introduction aux éléments techniques: outils et bibliothèques à utiliser dans ce projet
Vous pouvez modifier les outils et les bibliothèques que vous utilisez pour un qui est facile à utiliser pour vous-même, mais ce projet expliquera cette hypothèse.
- Vscode
-
- Un éditeur de code gratuit fourni par Microsoft.
- Il n'a pas besoin d'être VSCODE, mais il y a de nombreuses extensions, donc je le recommande.
- Il est également recommandé d'inclure Eslint ou plus joli.
- Node.js
-
- Un runtime JavaScript construit sur le moteur JavaScript V8 de Chrome .
- Vous pouvez exécuter du code JavaScript en dehors de votre navigateur.
- Ceci est expliqué en fonction de l'hypothèse qu'il est déjà installé, veuillez donc le télécharger à partir de
https://nodejs.org/ja * Nous vous recommandons de télécharger la version stable à long terme de LTS.
- Vite
-
- Un outil de construction pour les projets Web modernes. Il se caractérise par sa rapide et légère
- Le "CRA (Create-React-App)" précédemment utilisé n'est pas répertorié sur le site officiel et est devenu une ancienne technologie.
- À partir de maintenant, Vite devrait être la meilleure option lors de la création d'applications avec React.
- Réagir
-
- Il s'agit d'une bibliothèque JavaScript pour la construction d'une interface interface (interface utilisateur). Il a été développé par Facebook et est toujours utilisé dans de nombreuses applications Web aujourd'hui.
- Trois.js
-
- Une bibliothèque JavaScript pour créer facilement des graphiques 3D. Il résume les opérations complexes de WebGL et permet un développement 3D intuitif.
- Il est facile de créer des graphiques 3D et est plus facile à utiliser que les opérations WebGL directes.
- Réagir trois fibres
-
- Il s'agit d'une bibliothèque qui permet à trois.js d'être utilisés avec React. Il combine la structure des composants de React avec le moteur 3D de Three.js.
- Trois.js peuvent être utilisés dans le style de développement de la réact, permettant un développement intuitif et efficace.
- Réagir trois drei
-
- Une collection de composants utilitaires utiles pour réagir trois fibres. Il est facile d'ajouter les fonctionnalités de trois.js couramment utilisées.
- Les fonctionnalités complexes trois.js peuvent être obtenues avec un code court, réduisant les coûts d'apprentissage.
🚀 Faire "Pixel Art" avec React Three Fibre × Drei × TypeScript!
📌La construction de l'environnement est expliquée dans cet article

📌Ce temps, nous n'utiliserons aucun modèle 3D spécial, mais n'utiliserons que des objets standard qui sont disponibles dans React Three Fiber et React Three Drei.
Si vous souhaitez en savoir plus sur les objets standard, veuillez également vous référer à cet article

Veuillez vérifier GitHub pour le code source complet que vous avez créé cette fois.
💾 Référentiel GitHub : vérifiez le code source de ce lien
💡Création de l'interface utilisateur pour le panneau de commande !!
Tout d'abord, le panneau de configuration crée une interface utilisateur pour que les utilisateurs puissent télécharger des images, définir des tailles de pixels et utiliser diverses animations.
// Importer React et Three.js Libraries associées à importer {USState} à partir de "réact"; // Paramètre constant: const default_pixel_size = 64; // - Default_pixel_size: Taille par défaut (nombre de pixels) lors de la rétrécissement d'une image // ==== // Composants de l'application: // - Gestion centrale de l'interface utilisateur (chargement d'image, paramètre de taille de pixels, opérations d'animation) // - Placez deux Canvas (scènes de pixels et scènes d'arrière usestate<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée Retour (<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> {/ * Sélectionnez le fichier image * /} <input type="file" accept="image/*" className="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" /> {/ * Field de saisie de la taille des pixels * /}<div className="flex items-center space-x-2"> <label className="text-sm text-gray-700">Taille des pixels:</label><input type="number" value={tempPixelSize} onChange={(e) => setMpIxelSize (nombre (e.target.value))} min = "1" max = "128" classname = "W-16 Border-Border-Gray-300 Arronded-MD PX-2 PY-1 Text-SM Focus: Ring-2 Focus: Ring-Blue-500 Focus: Outline-none" /></div> {/ * Bouton de redéplay * /} <button className="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 transition">Redisplay</button> {/ * Bouton de contrôle d'animation * /}<div className="flex flex-wrap gap-2"><button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">Vague</button><button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">d'explosion</button></div></div></div> )); }; Exporter l'application par défaut;

Cette fois, je veux créer quelque chose de simple, donc je vais le laisser comme ça comme une interface utilisateur.
L'explosion et l'onde sont utilisées pour animer l'art des pixels.
Je pense que l'avantage de créer de l'art de pixels avec React Three Fibre est que vous pouvez ajouter l'animation à l'art de pixels.
💡Création d'un événement de panneau de commande !!
Je vais mettre l'événement dans l'interface utilisateur que je viens de créer.
handleFileChange
HandleFileChange est le processus lorsqu'une image est sélectionnée.
La sélection d'une image mettra à jour la taille des pixels, puis mettra à jour la source d'image.
// Importer React et Three.js Libraries associées à importer {USState} à partir de "réact"; // Paramètre constant: const default_pixel_size = 64; // - Default_pixel_size: Taille par défaut (nombre de pixels) lors de la rétrécissement d'une image // ==== // Composants de l'application: // - Gestion centrale de l'interface utilisateur (chargement d'image, paramètre de taille de pixels, opérations d'animation) // - Placez deux Canvas (scènes de pixels et scènes d'arrière usestate<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [pixelsize, setPixelSize] = useState<number> (temppixelSize); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [imagesrc, setimagesrc] = useState<string | null> (nul); // - ImagesRC: URL de données de l'image importée // ---- // Que faire lorsqu'un fichier image est sélectionné: // - Chargez le fichier, convertissez-le en URL de données et définissez-les dans imagesrc // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<HTMLInputElement> ) => {const file = e.target.files ?. [0]; if (! fichier) renvoyer; const Reader = new FileReader (); reader.onload = (ev) => {const url = ev.target?.result; if (typeof url! == "String") return; // Mettez à jour la taille du pixel, puis définissez la source d'image setPixelSize (temppixelSize); setImagesRc (URL); }; Reader.ReadAsDataurl (fichier); }; retour (<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> {/ * Sélectionnez le fichier image * /} <input type="file" accept="image/*" onChange={handleFileChange} className="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" /> {/ * Field de saisie de la taille des pixels * /} ...</div></div> )); }; Exporter l'application par défaut;
reloadimage
Ensuite, l'événement du bouton Redisplay.
Ceci est utilisé lors de la mise à jour de la taille des pixels et de la rediffusion de la taille des pixels.
Il s'agit d'une forme qui reflète TemPpixelSize dans PixelSize.
// Importer React et Three.js Libraries associées à importer {USState} à partir de "réact"; // Paramètre constant: const default_pixel_size = 64; // - Default_pixel_size: Taille par défaut (nombre de pixels) lors de la rétrécissement d'une image // ==== // Composants de l'application: // - Gestion centrale de l'interface utilisateur (chargement d'image, paramètre de taille de pixels, opérations d'animation) // - Placez deux Canvas (scènes de pixels et scènes d'arrière usestate<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [pixelsize, setPixelSize] = useState<number> (temppixelSize); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [imagesrc, setimagesrc] = useState<string | null> (nul); // - ImagesRC: URL de données de l'image importée // ---- // Que faire lorsqu'un fichier image est sélectionné: // - Chargez le fichier, convertissez-le en URL de données et définissez-les dans imagesrc // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<HTMLInputElement> ) => {...}; // ----- // Traitement lorsque vous appuyez sur le bouton "Review": // - redessinez l'image en reflétant la valeur de TemPPixelSize dans PixelSize // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> ... {/ * Bouton de redéplay * /} <button className="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 transition" onClick={reloadImage} >Redisplay</button> {/ * Bouton de contrôle d'animation * /}<div className="flex flex-wrap gap-2"><button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">Vague</button><button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">d'explosion</button></div></div></div> )); }; Exporter l'application par défaut;
Controlexplosionanimation et contrôlewaveanimation
L'événement du bouton de contrôle d'animation ressemblera à ceci:
puisque j'ai défini Animation_time comme constante, je me animerai en ce nombre de secondes, annulez le même nombre de secondes et reviendrai en mode par défaut.
// Importer React et Three.Js Libraries liées à l'importer {UseState} à partir de "React"; // Paramètre constant: const default_pixel_size = 64; // - default_pixel_size: taille par défaut (en pixels) lors de la réduction de l'image const Animation_time = 3; // - Animation_time: Temps (en secondes) à l'animation // ==== // Composants d'application: // - Management de l'interface utilisateur centrale (chargement d'image, dimensionnement des pixels, opérations d'animation) // - Arrange 2 Canvas (scène pixel et scène de fond) // ===== const = () => {// State Management: const [temPPPPIXELSIZE<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [pixelsize, setPixelSize] = useState<number> (temppixelSize); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [imagesrc, setimagesrc] = useState<string | null> (nul); // - ImagesRc: URL de données de l'image importée const [animation, setAnimation] = UseState ("par défaut"); // - Animation: Mode d'animation actuel // ---- // Que faire lorsqu'un fichier image est sélectionné: // - Chargez le fichier, convertissez-le en URL de données et définissez-le dans imagesrc // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<HTMLInputElement> ) => {...}; // ----- // Traitement lorsque vous appuyez sur le bouton "Review": // - Repreint l'image en reflétant la valeur de temppixelSize dans pixelsize // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Contrôle d'animation: // - Démarrer, fin et annuler l'explosion séquentiellement avec le délai d'attente // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- setAnimation ("par défaut"); }, Animation_time * 2000); }; // ----- // Control Wave Animation: // - Démarrer, fin et annul les vagues d'exécuter séquentiellement le délai d'attente // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- setAnimation ("wave_end"); }, Animation_time * 1000); setTimeout (() => {setAnimation ("Default");}, animation_time * 2000); }; retour (<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> ... {/ * Bouton de contrôle d'animation * /}<div className="flex flex-wrap gap-2"> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlWaveAnimation} >Vague</button> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlExplosionAnimation} >d'explosion</button></div></div></div> )); }; Exporter l'application par défaut;
💡La source globale actuelle est là
// Importer React et Three.Js Libraries liées à l'importer {UseState} à partir de "React"; // Paramètre constant: const default_pixel_size = 64; // - default_pixel_size: taille par défaut (en pixels) lors de la réduction de l'image const Animation_time = 3; // - Animation_time: Temps (en secondes) à l'animation // ==== // Composants d'application: // - Management de l'interface utilisateur centrale (chargement d'image, dimensionnement des pixels, opérations d'animation) // - Arrange 2 Canvas (scène pixel et scène de fond) // ===== const = () => {// State Management: const [temPPPPIXELSIZE<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [pixelsize, setPixelSize] = useState<number> (temppixelSize); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [imagesrc, setimagesrc] = useState<string | null> (nul); // - ImagesRc: URL de données de l'image importée const [animation, setAnimation] = UseState ("par défaut"); // - Animation: Mode d'animation actuel // ---- // Que faire lorsqu'un fichier image est sélectionné: // - Chargez le fichier, convertissez-le en URL de données et définissez-le dans imagesrc // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<HTMLInputElement> ) => {const file = e.target.files ?. [0]; if (! fichier) renvoyer; const Reader = new FileReader (); reader.onload = (ev) => {const url = ev.target?.result; if (typeof url! == "String") return; // Mettez à jour la taille des pixels une fois, puis définissez la source d'image setPixelSize (temppixelSize); setImagesRc (URL); }; Reader.ReadAsDataurl (fichier); }; // ----- // Action en appuyant sur le bouton "Review": // - Redessinez l'image en reflétant la valeur de temppixelsize dans pixelsize // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- // Contrôle de l'animation de l'onde: // - Démarrer, fin et annuler les vagues séquentiellement avec le délai d'attente // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- => {setAnimation ("Default"); }, Animation_time * 2000); }; retour (<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> {/ * Sélectionnez le fichier image * /} <input type="file" accept="image/*" onChange={handleFileChange} className="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" /> {/ * Field de saisie de la taille des pixels * /}<div className="flex items-center space-x-2"> <label className="text-sm text-gray-700">Taille des pixels:</label><input type="number" value={tempPixelSize} onChange={(e) => setMpIxelSize (nombre (e.target.value))} min = "1" max = "128" classname = "W-16 Border-Border-Gray-300 Arronded-MD PX-2 PY-1 Text-SM Focus: Ring-2 Focus: Ring-Blue-500 Focus: Outline-none" /></div> {/ * Bouton de redéplay * /} <button className="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 transition" onClick={reloadImage} >Redisplay</button> {/ * Bouton de contrôle d'animation * /}<div className="flex flex-wrap gap-2"> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlWaveAnimation} >Vague</button> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlExplosionAnimation} >d'explosion</button></div></div></div> )); }; Exporter l'application par défaut;
💡 Créez des données de pixels à partir d'images !!
Cette fois, nous chargerons l'image, générerons les données de pixels et afficherons l'écran.
Créons donc un processus qui génère des données de pixels à partir d'une image.
* Aux fins d'explication, des fichiers, etc. ne sont pas séparés. Je pense qu'il serait préférable de séparer les fichiers au niveau des composants pour être plus lisibles.
Création d'une fonction CreatePixeldata
// Importer React et Three.Js Libraries liées à l'importer {UseState} à partir de "React"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position (x, y, z) et couleur (trois.color) de chaque pixel // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- x: numéro; y: numéro; z: numéro; Couleur: trois.color; }; // Paramètre constant: const default_pixel_size = 64; // - default_pixel_size: taille par défaut (en pixels) lors de la réduction de l'image const Animation_time = 3; // - Animation_time: le temps pris à l'animation (secondes) // ===== // Composants de l'App: // - Management de l'UI central (chargement d'image, dimensionnement des pixels, opérations d'animation) // - Arrangez deux toiles (scène de pixels et scène de fond) // ===== const = () => {...}; Exporter l'application par défaut; // ===== // / CreatePixelData Fonction: // - Obtenez des données de pixels à partir de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== const CreatePixelData = (img: htMlimageElement, TargetWidth: Number, Targetheight) et Sett il à la taille constante const canvas = document.CreateElement ("canvas"); canvas.width = TargetWidth; canvas.height = targetheight; const ctx = canvas.getContext ("2d"); if (! ctx) lancer une nouvelle erreur ("aucun contexte 2D disponible"); // dessinez une image sur Canvas et obtenez des informations sur les pixels CTX.DrawImage (IMG, 0, 0, TargetWidth, TargeTheight); const imgdata = ctx.getImagedata (0, 0, ciblewidth, targetheight); const data = imgdata.data; Résultat const: pixelinfo [] = []; Soit idx = 0; // Pour chaque pixel de l'image, obtenez la valeur RGBA et convertissez-la en pixelinfo pour (laissez y = 0; y <TargeTheight; y ++) {pour (laissez x = 0; x <ciblewidth; x ++) {const r = data [idx], g = data [idx + 1], b = data [idx + 2], a a = data [idx + 3]; idx + = 4; // ignorer les pixels de transparence faible (si A <30) si (a <30) continuent; Result.push ({// ajuster x, y coordonne de sorte que le centre de l'image soit l'origine x: x - ciblewidth / 2, y: -y + targetheight / 2, z: 0, // créer trois.color en convertissant la valeur RGB en gamme 0 en 1 couleur: nouveau trois.color (r / 255, g / 255, b / 255),}); }} Retour Résultat; };
Le processus est le suivant: le processus est un peu compliqué, mais je pense que ce que je fais est simple.
- Obtenez l'image et la taille des pixels
- Dessinez l'image sur toile pour obtenir des informations sur les pixels
- Obtient des informations RGBA pour les pixels et les stocke en pixelinfo
Créer une pièce d'appel (useEFFECT)
Étant donné que les données de pixels sont mises à jour lorsque la taille de l'image ou du pixel change, utilisez Effet () pour surveiller [pixelsize, imagesrc].
// Importer React et Three.js Libraries liées à l'importer {UseState, useEffect} depuis "React"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position (x, y, z) et couleur (trois.color) de chaque pixel // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- x: numéro; y: numéro; z: numéro; Couleur: trois.color; }; // Paramètre constant: const default_pixel_size = 64; // - default_pixel_size: taille par défaut (en pixels) lors de la réduction de l'image const Animation_time = 3; // - Animation_time: temps passé à l'animation (secondes) // ===== // Composants de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - Placez deux toiles (scène de pixels et scène de fond) // ===== const)<PixelInfo[] | null> (nul); // - Pixels: tableau d'informations sur les pixels générées à partir de l'image const [filechangeCount, setFileChangeCount] = UseState<number> (0); // - FileChangeCount: nombre de modifications à l'image (utilisée pour déclencher un rechargement) const [temppixelSize, setMpIxelSize] = usestate<number> (Default_pixel_size); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [pixelsize, setPixelSize] = useState<number> (temppixelSize); // - temppixelSize: Taille temporaire des pixels sur le formulaire d'entrée const [imagesrc, setimagesrc] = useState<string | null> (nul); // - ImagesRc: URL de données de l'image importée const [animation, setAnimation] = UseState ("par défaut"); // - Animation: Mode d'animation actuel ... // ---- // Générez des données de pixels à partir de l'image lorsque l'image ou PixelSize change // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- déclenchez lorsque l'image modifie SetFileChangeCount ((prev) => prev + 1); // Chargez une nouvelle image et générez des données de pixels avec l'événement Onload const IMG = new Image (); img.onload = () => {const pixel = createPixelData (img, pixelsize, pixelsize); setPixels (pix); }; img.src = imagesrc; }, [pixelsize, imagesrc]); retour (<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------</div> )); }; Exporter l'application par défaut; // ==== // Fonction CreatePixelData: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== CONCEPIXELDATA = (IMG: HTMLIMAGEELlement, TargetWidth: Number, TARGETHEight: Number) la taille constante const canvas = document.CreateElement ("canvas"); canvas.width = TargetWidth; canvas.height = targetheight; const ctx = canvas.getContext ("2d"); if (! ctx) lancer une nouvelle erreur ("aucun contexte 2D disponible"); // dessinez l'image sur Canvas et obtenez des informations sur les pixels CTX.DrawImage (IMG, 0, 0, TargetWidth, TargeTheight); const imgdata = ctx.getImagedata (0, 0, ciblewidth, targetheight); const data = imgdata.data; Résultat const: pixelinfo [] = []; Soit idx = 0; // Pour chaque pixel de l'image, obtenez la valeur RGBA et convertissez-la en pixelinfo pour (laissez y = 0; y <TargeTheight; y ++) {pour (laissez x = 0; x <ciblewidth; x ++) {const r = data [idx], g = data [idx + 1], b = data [idx + 2], a a = data [idx + 3]; idx + = 4; // ignorer les pixels avec une faible transparence (a <30) si (a <30) continue; result.push ({// ajuster les coordonnées x, y, donc le centre de l'image est l'origine x: x - ciblewidth / 2, y: -y + targetheight / 2, z: 0, // créer trois.color en convertissant la valeur RGB en gamme 0 en 1 couleur: new trois.color (r / 255, g / 255, b / 255),}); }} Retour Résultat; };
💡A Canvas est disponible pour l'affichage Pixel !!
Placez d'abord la toile et préparez votre appareil photo, votre éclairage, etc.
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position (x, y, z) et couleur (trois.color) de chaque pixel // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Temps pris en quelques secondes à l'animation // ==== // Composants d'application: // - Management de l'interface utilisateur centrale (chargement d'image, dimensionnement des pixels, opérations d'animation) // - Arrangez deux toiles (scène de pixels et scène d'arrière<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /})}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // Fonction CreatePixelData: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixeldata = (img: htmlimageElement, TargetWidth: Number, TARGETHEight: nombre): pixelinfo [] = {... Retournet; };
💡 Afficher les pixels !!
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position (x, y, z) et couleur (trois.color) de chaque pixel // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Temps pris en quelques secondes à l'animation // ==== // Pixelgrid Component: // - Rend les groupes de données de pixels, et // - contrôle l'animation affichage (élargissement progressif) et en mouvement d'animation (explosion / wave) // ==== Type pixelgridProps = {pixelsize: nombre; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // Placez chaque composant PixelBox dans un groupe géré par GroupRef pour rendre le retour (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={1} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // CreatePixelData Fonction: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixelData = (img: htmlimageElement, TargetWidth: Number, Targetheight: Number): Pixelinfo [] => {};
Je pense que l'art des pixels est affiché de cette manière.
C'est bien, mais comme je le fais avec React Three Fibre, j'ajouterai des animations et plus encore.
💡 Ajout d'animation d'affichage
Je vais essayer de recréer l'animation d'affichage car il est progressivement dessiné.
C'est une image d'augmenter progressivement l'échelle de pixels de 0 à 1.
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas, useFrame} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: position de chaque pixel (x, y, z) et couleur (trois.color) // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Animation_time: Temps (en secondes) à l'animation // ==== // Pixelgrid Component: // - Rende des groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et animation en mouvement (explosion / wave) // ==== Type PixelGridProps = {pixelsize: nombre; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // ---- // Afficher l'animation: Traitement des pixels affichés en étapes // ---- // Gérer l'état d'échelle pour chaque pixel (l'état initial est tout 0 = caché) const [échelles, setsscales] = useState<number[]> (Array (pixels.length) .fill (0)); // ScaleProgressRef: continue de progresser l'affichage (temps accumulé) pour chaque constant const ScaleProgressRef = useRef (0); // BatchIndexref: gère le numéro de lot actuellement affiché const batchIndexref = useRef (0); // useFrame pour mettre à jour chaque image et afficher les pixels étape par étape useframe ((_, delta) => {// si tous les lots sont affichés, aucun traitement supplémentaire n'est effectué si (batchIndexref.current> pixels.length / pixelsize) return; // ajoute le temps depuis le cadre de la trame précédente pour afficher le current + = delta; // Calcule à faire thermalfold to the curning. const threshold = batchIndexref.current * (animation_time / (pixels.length / pixelsize); Appartenant au lot actuel startIndex = BatchIndexref.current * pixelsize; const endIndex = math.min (startIndex + pixelsize, pixels.length); SetScales (NewsCales); // Placez chaque composant Pixelbox dans un groupe géré par GroupRef et rendez-le (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // CreatePixelData Fonction: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixelData = (img: htmlimageElement, TargetWidth: Number, Targetheight: Number): Pixelinfo [] => {};
💡 prend en charge le rechargement de l'image !!
Si cela se poursuit, l'animation d'affichage ne fonctionnera pas lorsque l'image est rechargée et sera affichée immédiatement.
Ajoutez USEEFFECT pour réinitialiser l'état lors du rechargement d'une image ou de la modification de la taille des pixels.
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas, useFrame} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: position de chaque pixel (x, y, z) et couleur (trois.color) // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Animation_time: Temps (en secondes) à l'animation // ==== // Pixelgrid Component: // - Rende des groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et animation en mouvement (explosion / wave) // ==== Type PixelGridProps = {pixelsize: nombre; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // ---- // Afficher l'animation: Traitement des pixels affichés en étapes // ---- // Gérer l'état d'échelle pour chaque pixel (l'état initial est tout 0 = caché) const [échelles, setsscales] = useState<number[]> (Array (pixels.length) .fill (0)); // ScaleProgressRef: continue de progresser l'affichage (temps accumulé) pour chaque constant const ScaleProgressRef = useRef (0); // BatchIndexref: gère le numéro de lot actuellement affiché const batchIndexref = useRef (0); // une référence pour déterminer si un fichier d'image a été modifié constarichangeCounTref = useRef (fileChangeCount); // réinitialise l'état d'affichage (échelle) de tous les pixels lors du rechargement d'une image use effecte (() => {if (fileChangeCount! == PrevFilechangeCounTref.current) {// réinitialiser l'échelle à 0 pour masquer tous les pixels setsScales (array (pixels.length). ScalProgressRef.current = 0; BatchIndexref.current = 0; // useFrame pour mettre à jour chaque trame et afficher les pixels étape par étape useframe delta) => {// aucun traitement supplémentaire n'est effectué si tous les lots sont visibles si (BatchIndexref.Current> pixels.length / pixelsize) return; // Ajouter du temps depuis le cadre précédent ScalProgressRef.current + = delta; // Calculez le seuil de temps pour afficher le constant constant constant de lots = BatchIndexref.current * (animation_time / (pixels.length / pixelsize)); // Lorsque le temps écoulé dépasse le seuil, commencez à afficher des pixels pour le lot suivant if (scaleProgressRef.current> threshold) {// Créer une copie de l'état de l'échelle actuel const newscales = [... échelles]; // Calculez la plage d'index des pixels appartenant au lot actuel const startIndex = batchIndexref.current * pixelSize; const endIndex = math.min (startIndex + pixelsize, pixels.length); // Affichez l'échelle de pixel correspondante à 1 pour (Soit i = startIndex; i <endIndex; i ++) {newsCales [i] = 1; } // Définir les sets à l'échelle mis à jour (NewsCales); // Passez au prochain BatchIndexref.current + = 1; }}); // Chaque composant Pixelbox est placé dans un groupe géré par GroupRef pour rendre le retour (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // CreatePixelData Fonction: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixelData = (img: htmlimageElement, TargetWidth: Number, Targetheight: Number): Pixelinfo [] => {};
Vous pouvez maintenant voir que cela fonctionne correctement même si vous rechargez l'image.
PixelSize est également surveillé, donc même si vous mettez à jour la taille des pixels, il sera à nouveau affiché.
Animation d'explosion adressée !!
Ensuite, ajoutez une animation d'explosion.
Ce que nous faisons est assez simple: calculez d'abord les coordonnées aléatoires, puis utilisez useFrame pour les déplacer vers cette position. Lorsque vous revenez à la normale, vous pouvez faire le contraire.
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas, useFrame} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: position de chaque pixel (x, y, z) et couleur (trois.color) // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Animation_time: Temps (en secondes) à l'animation // ==== // Pixelgrid Component: // - Rende des groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et animation en mouvement (explosion / wave) // ==== Type PixelGridProps = {pixelsize: nombre; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // ---- // Afficher l'animation: traitement des pixels affichés en étapes // ----- ... // ----- // Animation mobile: modifiez la position des pixels avec des effets d'explosion ou d'onde // ---- // une référence pour comparer avec l'état d'animation précédente et réinitialiser les progrès s'il y a un changement const LastaniMationRef = UseRef (animation); // Gérer les progrès de l'animation (0 à 1) const AnimationProgressRef = useRef (0); // générer des coordonnées de destination de diffusion aléatoire pour chaque pixel (pour les effets d'explosion) constatroposipos de const. // régénérer les coordonnées de diffusion aléatoire lorsque les données d'image ou de pixels sont mises à jour usageEffected (() => {ScatterPositionSref.Current = Pixels.map (() => ({x: (math.random () - 0,5) * 100, y: (math.random () - 0,5) * 100, z: (math.random () - 0,5) * 100,}); [pixels]); // Mette à jour la position de chaque pixel chaque trame avec useFrame pour correspondre à l'animation Progress useFrame ((_, delta) => {// réinitialiser la progression si l'état d'animation modifie if (animation! == LasanimationRef.current) {LastanimationRef.Current = Animation; AnimationProgrand "par défaut") Retour; // Mettez à jour les progrès de l'animation (normalisés avec Animation_Time) if (AnimationProgressRef.current <1) {AnimationProgressRef.current> 1) Animation / Animation_ Math.Sin ((AnimationProgressRef.Current * Math.pi) / 2); Position de diffusion aléatoire if (animation === "Explosion_start") {TargetX = ScatterPositionSref.current [i] .x * smoothprogress + pixel.x * (1 - smoothprogress); * SmoothProgress + Pixel.z * (1 - SmoothProgress);} // Fin de l'explosion: retour de la position de diffusion à la position d'origine if (animation === "Explosion_end") {TargetX = ScatterPositionSref.current [i] .x * (1 - SmoothProgress) + pixel.x *. SmoothProgress) + pixel.y * smoothProgress; // Placez chaque composant PixelBox dans un groupe géré par GroupRef pour rendre le retour (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // CreatePixelData Fonction: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixelData = (img: htmlimageElement, TargetWidth: Number, Targetheight: Number): Pixelinfo [] => {};
Bien que ce soit simple, je pense qu'il semble avoir le sentiment de se séparer par Pixel !!
💡 Ajout de l'animation des vagues !!
Ajoutons également des animations de vagues.
Je pense que je peux essentiellement l'ajouter de la même manière qu'une animation d'explosion.
// Importer React et Three.js Libraries liées à l'importer {orbitControls} de "@ react-trois / drei"; import {canvas, useFrame} de "@ react-trois / fibre"; import {useState, useEffecte, useref} de "react"; import * comme trois de "trois"; // ----- // Type de pixelinfo: position de chaque pixel (x, y, z) et couleur (trois.color) // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Animation_time: Temps (en secondes) à l'animation // ==== // Pixelgrid Component: // - Rende des groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et animation en mouvement (explosion / wave) // ==== Type PixelGridProps = {pixelsize: nombre; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // ---- // Afficher l'animation: traitement des pixels affichés en étapes // ----- ... // ----- // Animation mobile: modifiez la position des pixels avec des effets d'explosion ou d'onde // ---- // une référence pour comparer avec l'état d'animation précédente et réinitialiser les progrès s'il y a un changement const LastaniMationRef = UseRef (animation); // Gérer les progrès de l'animation (0 à 1) const AnimationProgressRef = useRef (0); // générer des coordonnées de destination de diffusion aléatoire pour chaque pixel (pour les effets d'explosion) constatroposipos de const. // régénérer les coordonnées de diffusion aléatoire lorsque les données d'image ou de pixels sont mises à jour usageEffected (() => {ScatterPositionSref.Current = Pixels.map (() => ({x: (math.random () - 0,5) * 100, y: (math.random () - 0,5) * 100, z: (math.random () - 0,5) * 100,}); [pixels]); // Mette à jour la position de chaque pixel chaque trame avec useFrame pour correspondre à l'animation Progress useFrame ((_, delta) => {// réinitialiser la progression si l'état d'animation modifie if (animation! == LasanimationRef.current) {LastanimationRef.Current = Animation; AnimationProgrand "par défaut") Retour; // Mettez à jour les progrès de l'animation (normalisés avec Animation_Time) if (AnimationProgressRef.current <1) {AnimationProgressRef.current> 1) Animation / Animation_ Math.Sin ((AnimationProgressRef.Current * Math.pi) / 2); Position de diffusion aléatoire if (animation === "Explosion_start") {TargetX = ScatterPositionSref.current [i] .x * smoothprogress + pixel.x * (1 - smoothprogress); * SmoothProgress + Pixel.z * (1 - SmoothProgress);} // Fin de l'explosion: retour de la position de diffusion à la position d'origine if (animation === "Explosion_end") {TargetX = ScatterPositionSref.current [i] .x * (1 - SmoothProgress) + pixel.x *. SmoothProgress) + pixel.y * smoothProgress; pixel.z + animationProgressRef.current * 10) * 0,3) * 5 * Smootor SmoothProgress);} // Mettez à jour la position de maillage du groupe Pixel correspondant. // Placez chaque composant PixelBox dans un groupe géré par GroupRef pour rendre le retour (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div></div> )); }; Exporter l'application par défaut; // ==== // CreatePixelData Fonction: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixelData = (img: htmlimageElement, TargetWidth: Number, Targetheight: Number): Pixelinfo [] => {};
Je pense que cela peut exprimer le sentiment ondulant.
CHEF ADADDED !!
Cela n'en a pas besoin, mais j'étais un peu seul, donc j'ajouterai aussi un fond.
React Three Drei a une étoile et un nuage, donc je vais les combiner d'une manière agréable.
// Importer React et Three.js Librares liées à importer React, {UseState, Useref, Memo, useEffecte} de "React"; import {canvas, useFrame} de "@ react-trois / fibre"; Importer {cloud, orbitControls, étoiles} de "@ react-trois / drei"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position de chaque pixel (x, y, z) et couleur (trois.color) // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Default_pixel_size = 64; const Animation_time = 3; // ==== // PixelGrid Component: // - Rend les groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et en mouvement d'animation (explosion / wave) // ==== Type PixelGridProps = {pixelSize: numéro; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {... // / placer chaque composant Pixelbox dans un groupe géré par groupef<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'application: // - gestion centrale de l'interface utilisateur (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière-plan) // ===== const applic = () => {... return (<div style={{ width: "100vw", height: "100vh" }}> {/ * ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[-1]"><Canvas camera={{ position: [0, 5, 15], fov: 50 }} style={{ background: "black" }} ><ambientLight intensity={0.5} /><pointLight position={[10, 10, 10]} intensity={0.5} color="white" /><BackgroundScene /></Canvas></div></div> )); }; // ==== // Fonction CreatePixelData: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== ContePixeldata = (img: htmlimageElement, TargetWidth: Number, TARGETHEight: nombre): pixelinfo [] = {... Retournet; }; // ==== // BackgroundScene Component: // - un composant pour afficher le ciel étoilé et les nuages en arrière-plan // - Enveloppement avec un mémo pour éviter les redémarrages inutiles // ===== const BackgroundScene = Memo (() => {return (<> {/ * représente le ciel étoilé avec des composants d'étoiles * /} <Stars radius={100} // 星が存在する空間の半径 depth={50} // 星の配置される深さの範囲 count={5000} // 表示する星の総数 factor={6} // 星の大きさ調整用の係数 saturation={1} // 色の鮮やかさ fade // 遠くの星がフェードアウトする効果 /> {/ * Express Clouds avec des composants de nuage * /} <Cloud position={[0, 0, 0]} // 雲の中心位置 opacity={0.1} // 雲の不透明度(低いほど透明) speed={0.2} // 雲の動く速度 scale={[10, 10, 10]} // 雲全体のサイズ segments={20} // 雲を構成するパーティクルの数 /></> )); }); Exporter l'application par défaut;
Il peut être difficile de le dire à partir de la vidéo, mais il a l'impression que la fumée augmente et ça fait du bien.
Code source final !!
💾 Référentiel GitHub : vérifiez le code source de ce lien
// Importer React et Three.js Librares liées à importer React, {UseState, Useref, Memo, useEffecte} de "React"; import {canvas, useFrame} de "@ react-trois / fibre"; Importer {cloud, orbitControls, étoiles} de "@ react-trois / drei"; import * comme trois de "trois"; // ----- // Type de pixelinfo: gérer la position de chaque pixel (x, y, z) et couleur (trois.color) // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Default_pixel_size = 64; const Animation_time = 3; // ==== // PixelGrid Component: // - Rend les groupes de données de pixels, et // - Contrôle Afficher l'animation (élargissement progressif) et en mouvement d'animation (explosion / wave) // ==== Type PixelGridProps = {pixelSize: numéro; Pixels: PixeLinfo []; Animation: String; FileChangeCount: numéro; }; const pixelgrid = ({pixelsize, pixels, animation, fileChangeCount,}: pixelgridProps) => {// une référence à l'objet de groupe dans trois.js. Utilisé pour regrouper tous les pixels const GroupRef = useref<THREE.Group> (nul); // ---- // Afficher l'animation: Traitement des pixels affichés en étapes // ---- // Gérer l'état d'échelle pour chaque pixel (l'état initial est tout 0 = caché) const [échelles, setsscales] = useState<number[]> (Array (pixels.length) .fill (0)); // ScaleProgressRef: continue de progresser l'affichage (temps accumulé) pour chaque constant const ScaleProgressRef = useRef (0); // BatchIndexref: gère le numéro de lot actuellement affiché const batchIndexref = useRef (0); // une référence pour déterminer si un fichier d'image a été modifié constarichangeCounTref = useRef (fileChangeCount); // réinitialise l'état d'affichage (échelle) de tous les pixels lors du rechargement d'une image use effecte (() => {if (fileChangeCount! == PrevFilechangeCounTref.current) {// réinitialiser l'échelle à 0 pour masquer tous les pixels setsScales (array (pixels.length). ScalProgressRef.current = 0; BatchIndexref.current = 0; // useFrame pour mettre à jour chaque trame et afficher les pixels étape par étape useframe delta) => {// aucun traitement supplémentaire n'est effectué si tous les lots sont visibles si (BatchIndexref.Current> pixels.length / pixelsize) return; // Ajouter du temps depuis le cadre précédent ScalProgressRef.current + = delta; // Calculez le seuil de temps pour afficher le constant constant constant de lots = BatchIndexref.current * (animation_time / (pixels.length / pixelsize)); // Lorsque le temps écoulé dépasse le seuil, commencez à afficher des pixels pour le lot suivant if (scaleProgressRef.current> threshold) {// Créer une copie de l'état de l'échelle actuel const newscales = [... échelles]; // Calculez la plage d'index des pixels appartenant au lot actuel const startIndex = batchIndexref.current * pixelSize; const endIndex = math.min (startIndex + pixelsize, pixels.length); // Affichez l'échelle de pixel correspondante à 1 pour (Soit i = startIndex; i <endIndex; i ++) {newsCales [i] = 1; } // Définir les sets à l'échelle mis à jour (NewsCales); // Passez au prochain BatchIndexref.current + = 1; }}); // ---- // Animation mobile: modifiez la position des pixels avec des effets d'explosion ou d'onde // ---- // Référence pour comparer avec l'état d'animation précédent et réinitialiser la progression s'il y a un changement const latanimationref = useref (animation); // Gérer les progrès de l'animation (0-1) const AnimationProgressRef = useRef (0); // génère des coordonnées de diffusion aléatoires pour chaque pixel (pour les effets d'explosion) const DispositionSref = useRef (pixels.map (() => ({x: (math.random () - 0.5) * 100, y: (math.random () - 0,5) * 100, z: (math.random () - 0.5) * 100,}))); // régénérer les coordonnées de diffusion aléatoire lorsque les données d'image ou de pixels sont mises à jour usageEffecte (() => {ScatterPositionSref.Current = Pixels.map (() => ({x: (math.random () - 0,5) * 100, y: (math.random () - 0.5) * 100, z: (math.random () - 0,5) * 100,}); [pixels]); // Mette à jour la position de chaque pixel chaque trame avec useFrame pour correspondre à la progression de l'animation useframe ((_, delta) => {// réinitialiser la progression si l'état d'animation change si (animation! == LastanimationRef.current) {LastanimationRef.Current = Animation; AnimationPrograndsRef.Current = 0; === "par défaut") RETOUR; = Math.sin ((animationProgressRef.current * math.pi) / 2); à la position de diffusion aléatoire if (animation === "explosion_start") {TargetX = ScatterPositionSref.current [i] .x * smoothprogress + pixel.x * (1 - smoothprogress); ScatterPositionSref.current [i] .Z * SmoothProgress + Pixel.z * (1 - Smootor ScatterPositionSref.Current [i] .y * (1 - SmoothProgress) + Pixel.y * SmoothProgress; "wave_start") {targetz = math.sin ((pixel.x + pixel.z + animationProgressRef.current * 10) * 0,3) * 5 * Smootor AnimationProgressRef.current) * 10) * 0,3) * 5 * (1 - Smootor // Placez chaque composant PixelBox dans un groupe géré par GroupRef pour rendre le retour (<group ref={groupRef}> {pixels.map ((pixel, i) => (<PixelBox key={i} pixel={pixel} scale={scales[i]} /> ))}</group> )); }; // ==== // PixelBox Component: // - un composant pour dessiner un seul pixel (box) // ==== type pixelboxprops = {pixel: pixelinfo; Échelle: numéro; }; const pixelbox = ({pixel, échelle}: pixelboxprops) => {// mail: utilisez la géométrie et le matériau de la boîte avec l'emplacement et le retour d'échelle ( <mesh position={[pixel.x, pixel.y, pixel.z]} scale={[scale, scale, scale]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={pixel.color} /></mesh> )); }; // ==== // Composant de l'App: // - Management de l'interface utilisateur centrale (chargement d'image, dimensionnement des pixels, opérations d'animation) // - organiser deux toiles (scène de pixels et scène d'arrière PixelSize: Taille de pixel réelle appliquée // - FileChangeCount: Nombre de modifications à l'image (utilisée pour déclencher un rechargement) // - ImagesRc: URL de données de l'image importée // - Animation: mode d'animation actuel const [pixels, setPixels] = useState<PixelInfo[] | null> (nul); const [temppixelSize, settempPixelSize] = UseState<number> (Default_pixel_size); const [pixelsize, setPixelSize] = useState<number> (temppixelSize); const [fileChangeCount, setFileChangeCount] = Usestate<number> (0); const [imagesrc, setimagesrc] = usestate<string | null> (nul); const [animation, setAnimation] = useState ("par défaut"); // ----- // Que faire lorsqu'un fichier image est sélectionné: // - Chargez le fichier, convertissez-le en URL de données et définissez-le dans imagesrc // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<HTMLInputElement> ) => {const file = e.target.files ?. [0]; if (! fichier) renvoyer; const Reader = new FileReader (); reader.onload = (ev) => {const url = ev.target?.result; if (typeof url! == "String") return; // Mettez à jour la taille des pixels une fois, puis définissez la source d'image setPixelSize (temppixelSize); setImagesRc (URL); }; Reader.ReadAsDataurl (fichier); }; // ----- // Traitement lorsque vous appuyez sur le bouton "Review": // - redessinez l'image en reflétant la valeur de TemPPixelSize dans PixelSize // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- }, [pixelsize, imagesrc]); // ----- // Control Explosion Animation: // - Démarrer, fin et annuler l'explosion exécute séquentiellement le délai d'attente // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- setAnimation ("explosion_end"); }, Animation_time * 1000); setTimeout (() => {console.log ("default"); setAnimation ("Default");}, animation_time * 2000); }; // ----- // Contrôle de l'animation d'onde: // - Démarrer, fin et annemi les vagues exécutives séquentiellement // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div style={{ width: "100vw", height: "100vh" }}> {/ * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<div className="absolute top-4 left-4 bg-white shadow-lg p-4 rounded-lg z-10 w-64 space-y-4"> {/ * Sélectionnez le fichier image * /} <input type="file" accept="image/*" onChange={handleFileChange} className="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" /> {/ * Field de saisie de la taille des pixels * /}<div className="flex items-center space-x-2"> <label className="text-sm text-gray-700">Taille des pixels:</label><input type="number" value={tempPixelSize} onChange={(e) => setMpIxelSize (nombre (e.target.value))} min = "1" max = "128" classname = "W-16 Border-Border-Gray-300 Arronded-MD PX-2 PY-1 Text-SM Focus: Ring-2 Focus: Ring-Blue-500 Focus: Outline-none" /></div> {/ * Bouton de redéplay * /} <button className="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 transition" onClick={reloadImage} >Redisplay</button> {/ * Bouton de contrôle d'animation * /}<div className="flex flex-wrap gap-2"> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlWaveAnimation} >Vague</button> <button className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition" onClick={controlExplosionAnimation} >d'explosion</button></div></div> {/ * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[1]"><Canvas camera={{ far: 5000, position: [0, 0, 100] }}> {/ * Paramètres d'éclairage de base * /}<ambientLight intensity={1} /><directionalLight position={[100, 200, 100]} intensity={1} /> {/ * OrbitControls qui vous permet de faire pivoter la scène avec le fonctionnement de la souris * /}<OrbitControls /> {/ * Rendre Pixelgrid uniquement si les données de pixel sont présentes * /} {pixels && ( <PixelGrid pixelSize={pixelSize} pixels={pixels} animation={animation} fileChangeCount={fileChangeCount} /> )}</Canvas></div> {/ * ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- <div className="absolute top-0 left-0 w-full h-full z-[-1]"><Canvas camera={{ position: [0, 5, 15], fov: 50 }} style={{ background: "black" }} ><ambientLight intensity={0.5} /><pointLight position={[10, 10, 10]} intensity={0.5} color="white" /><BackgroundScene /></Canvas></div></div> )); }; // ==== // Fonction CreatePixelData: // - Obtenez des données de pixels de l'image spécifiée à l'aide de Canvas et convertissez-la en un tableau de type pixelinfo // ===== CONCEPIXELDATA = (IMG: HTMLIMAGEELlement, TargetWidth: Number, TARGETHEight: Number) la taille constante const canvas = document.CreateElement ("canvas"); canvas.width = TargetWidth; canvas.height = targetheight; const ctx = canvas.getContext ("2d"); if (! ctx) lancer une nouvelle erreur ("aucun contexte 2D disponible"); // dessinez l'image sur Canvas et obtenez des informations sur les pixels CTX.DrawImage (IMG, 0, 0, TargetWidth, TargeTheight); const imgdata = ctx.getImagedata (0, 0, ciblewidth, targetheight); const data = imgdata.data; Résultat const: pixelinfo [] = []; Soit idx = 0; // Pour chaque pixel de l'image, obtenez la valeur RGBA et convertissez-la en pixelinfo pour (laissez y = 0; y <TargeTheight; y ++) {pour (laissez x = 0; x <ciblewidth; x ++) {const r = data [idx], g = data [idx + 1], b = data [idx + 2], a a = data [idx + 3]; idx + = 4; // ignorer les pixels avec une faible transparence (a <30) si (a <30) continue; Result.push ({// ajuster x, y coordonne de sorte que le centre de l'image soit l'origine x: x - ciblewidth / 2, y: -y + targetheight / 2, z: 0, // créer trois.color en convertissant la valeur RGB en gamme 0 en 1 couleur: nouveau trois.color (r / 255, g / 255, b / 255),}); }} Retour Résultat; }; // ===== // BackgroundScene Component: // - un composant pour afficher le ciel étoilé et les nuages en arrière-plan // - un emballage avec un mémo pour éviter des redesins inutiles // ===== const BackgroundScene = memo (() => {return (<> {/ * représentant le ciel étoilé avec des composants d'étoiles * /} <Stars radius={100} // 星が存在する空間の半径 depth={50} // 星の配置される深さの範囲 count={5000} // 表示する星の総数 factor={6} // 星の大きさ調整用の係数 saturation={1} // 色の鮮やかさ fade // 遠くの星がフェードアウトする効果 /> {/ * Express Clouds avec des composants de nuage * /} <Cloud position={[0, 0, 0]} // 雲の中心位置 opacity={0.1} // 雲の不透明度(低いほど透明) speed={0.2} // 雲の動く速度 scale={[10, 10, 10]} // 雲全体のサイズ segments={20} // 雲を構成するパーティクルの数 /></> )); }); Exporter l'application par défaut;
dernièrement
Cette fois, nous avons utilisé React Three Fiber pour créer des pixels et des animations dynamiques d'images, et utilisé React Three Fiber et React Three Drei pour animer l'art de pixels et l'art de pixel !!
Quant à l'animation, je pense que vous pouvez créer quelque chose de plus cool si vous augmentez librement le nombre d'implémentations, alors assurez-vous de l'essayer!
Vous pouvez obtenir une compréhension détaillée des mouvements réels en regardant le YouTube ci-dessous!
📺 Regardez la démo sur YouTube : vous pouvez le regarder à partir de ce lien

📌Le code que j'ai créé cette fois est publié sur github, alors veuillez le vérifier aussi!
💾 Référentiel GitHub : vérifiez le code source de ce lien
📌Si vous utilisez le maillage et le remplacez par un objet 3D, vous pouvez même vous rapprocher de votre idéal !!
Meshy est un service qui vous permet de générer facilement des objets 3D à l'aide de l'IA.
En utilisant cela, vous pouvez facilement créer votre objet 3D idéal, donc je pense que vous pouvez vous rapprocher encore de votre idéal!
📺 Vérifiez le maillage : vous pouvez le vérifier sur la page officielle à partir de ce lien

Si vous avez trouvé cela utile, veuillez vous abonner à notre chaîne!
Nous continuerons à créer des leçons et travaillent à partir de TypeScript X React Three Fibre à l'avenir!
Nous ferons une annonce sur YouTube, alors veuillez vous abonner à notre chaîne YouTube et attendre les notifications!
📺 Regardez YouTube : vous pouvez le regarder à partir de ce lien
Si vous souhaitez savoir ce que React Three Fibre peut faire, veuillez vous référer à ce qui suit!
Nous avons des travaux faciles à utiliser disponibles!
- J'ai essayé de faire marcher les ours avec React x Three.js!
- J'ai essayé de faire danser un vieil homme sur React x Three.js!
- J'ai essayé d'afficher un modèle 3D avec React x Three.js!
- J'ai fait un bouton 3D qui explose dans React x Three.js!
- Réagir trois fibres x drei x Introduction à TypeScript! Fond 3D de style Poke Poke fait avec des objets standard!