Como cargar un modelo 3D en tu pagina Web con React ⚛️
Kevincarlosqa

Kevincarlosqa

Aug 26, 2023

Como cargar un modelo 3D en tu pagina Web con React ⚛️

Vamos a aprender como subir un modelo 3D usando React Three Fiber/Drei, el modelo sera un componente de React y podremos reutilizarlo donde queramos. 🖥️


Primero tenemos que elegir un modelo que nos agrade para poder utilizarlo en nuestra pagina Web, entramos a 🔗https://sketchfab.com/3d-models/popular, esta pagina es un repositorio con muchos modelos 3D hechos por la comunidad, elegimos la opcion Downloadable para descargar los modelos gratuitos, para el ejemplo utilizaremos un Fenix, el modelo podras encontrarlo en mi github para poder descargarlo.


💡 RECOMENDACION Usualmente los modelos 3D tienen texturas en formato .png, pero estos pesan mucho al momento de cargarlos en un dispositivo movil y puede afectar el tiempo de carga, tambien afectaria la experiencia de usuario, por lo que mi recomendacion es transformar las texturas a formato .webp dado que este formato esta hecho especialmente para la web y puede reducir en mas de 50% el tamaño del archivo manteniendo la calidad de imagen.

Instalando Dependencias


Usaremos Three.js que es una biblioteca para mostrar gráficos animados por computadora en 3D en un navegador Web, en React se creo React Three Drei y React Three Fiber, este ultimo es un reenderizador de Three.js para React y la biblioteca Drei es una biblioteca de helpers para facilitar varias propiedades que tienen los modelos 3D.


$ npm install three
$ npm install @react-three/fiber
$ npm install @react-three/drei


Obteniendo el Componente en React de nuestro modelo 3D


La manera mas facil de obtener el componente de React de nuestro modelo 3D es usando una biblioteca llamada gltfjsx, puedes revisar el proyecto en github para profundizar mas 🔗https://github.com/pmndrs/gltfjsx


Esta biblioteca leera nuestro archivo .gltf y nos dara el componente en React del modelo para usarlo, es muy sencillo utilizarla.


Primero nos dirigimos a la carpeta donde descargamos el modelo y entramos mediante la terminal, una vez dentro corremos el siguiente codigo:


$ npx gltfjsx [Model.gltf]


Si por ejemplo nuestro archivo se llama Phoenix.gltf nosotros debemos escribir en la terminal npx gltfjsx Phoenix.gltf, esto nos devuelve un componente en React llamado Scene.jsx que vamos a copiar y llevar a nuestro proyecto.


En mi caso me entrego este codigo que puedes copiar directamente para poder probarlo:


// Scene.jsx
import React, { useRef, useEffect } from "react";
import { useGLTF, useAnimations } from "@react-three/drei";

export function Model(props) {
  const group = useRef();
  const { nodes, materials, animations } = useGLTF("/phoenix_bird/scene.gltf");
  const { actions } = useAnimations(animations, group);
  useEffect(() => {
    // Luego veremos esto para cargar animaciones
  }, [actions]);
  return (
    <group
      ref={group}
      {...props}
      dispose={null}
      position={[10, -3, 0]}
      rotation={[0, 0, 0]}
    >
      <group name="Sketchfab_Scene">
        <group
          name="Sketchfab_model"

          rotation={[-Math.PI / 2, 0, 0.053]}
        >
          <group
            name="5f59736c86d4457fa045aec4aea6b7e0fbx"
            rotation={[Math.PI / 2, 0, 0]}
          >
            <group name="Object_2">
              <group name="RootNode">
                <group name="Object_4">
                  <primitive object={nodes._rootJoint} scale={0.04} />
                  <group name="Object_6" rotation={[-Math.PI / 2, 0, 0]} />
                  <group
                    name="AMesh_Ride_FengHuang_01"
                    rotation={[-Math.PI / 2, 0, 0]}
                  />
                  <skinnedMesh
                    name="Object_7"
                    geometry={nodes.Object_7.geometry}
                    material={materials.MatI_Ride_FengHuang_01a}
                    skeleton={nodes.Object_7.skeleton}
                  />
                  <skinnedMesh
                    name="Object_8"
                    geometry={nodes.Object_8.geometry}
                    material={materials.MatI_Ride_FengHuang_01b}
                    skeleton={nodes.Object_8.skeleton}
                  />
                </group>
              </group>
            </group>
          </group>
        </group>
      </group>
    </group>
  );
}

useGLTF.preload("/scene.gltf");


Esto solo nos crea un Modelo, pero aun no tiene controles, luces ni un Loader, el siguiente paso es crear un Loader que se podra utilizar para cualquier modelo que queramos cargar.


Componente Loader


Siempre al cargar un modelo 3D requiere un tiempo para que la pc lo procese, por lo que crearemos un componente Loader que se mostrara mientras el modelo aun esta en carga, lo que dara una mejor experiencia de usuario.


import { Html, useProgress } from "@react-three/drei"


En esta línea, se están importando dos elementos de la biblioteca @react-three/drei. Html es un componente que permite renderizar contenido HTML en un entorno 3D. useProgress es un hook que proporciona información sobre el progreso de la carga de los recursos.


const { progress } = useProgress()


Utilizamos el hook useProgress para obtener la información sobre el progreso de carga. El progreso se almacena en la variable progress.


{progress.toFixed(2)}%


◻️ Dentro del párrafo, se muestra el progreso actual de carga utilizando la variable progress.


◻️ progress.toFixed(2) redondea el valor de progreso a dos decimales.


◻️ Luego, se concatena el signo de porcentaje (%) para indicar que se trata de un valor de porcentaje.



Este seria el componente completo que es reutilizable para cualquier modelo 3D, este mostrara la carga del modelo en porcentaje:


// Loader.jsx
import { Html, useProgress } from "@react-three/drei";

const CanvasLoader = () => {
  const { progress } = useProgress();
  return (
    <Html>

      <p
        style={{
          fontSize: 14,
          color: "#f1f1f1",
          fontWeight: 800,
          marginTop: 40,
        }}
      >
        {progress.toFixed(2)}%
      </p>
    </Html>
  );
};

export default CanvasLoader;


Creamos el componente Canvas para cargar el modelo y utilizarlo en nuestra pagina web


Una vez ya tenemos la Escena(modelo .gltf) y nuestro Loader podemos cargarlo sobre un componente canvas que nos ayudara a poner luces y controles a nuestro escenario.


<Canvas>...</Canvas>

El componente Canvas se utiliza para crear el contexto de renderizado 3D. Dentro de este bloque se define la escena 3D.


<OrbitControls>...</OrbitControls>


Agregamos el componente OrbitControls para permitir la interacción del usuario con la escena 3D, como la rotación y el zoom utilizando los controles de órbita.


<directionalLight>, <ambientLight>, <pointLight>


Agregamos diferentes fuentes de luz a la escena para iluminar los objetos 3D en la escena.


<Suspense fallback={<CanvasLoader />}>...</Suspense>


Utilizamos el componente Suspense para manejar la carga asincrónica de recursos, como el modelo 3D. Mientras el modelo se está cargando, se mostrará el componente CanvasLoader como respaldo.



Este seria nuestro componente completo, recuerda que las importaciones pueden cambiar dependiendo de la estructura de tu proyecto


import React, { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { Model } from "./Scene";
import CanvasLoader from "./canvas/Loader";

const Phoenix = () => {
  return (
    <Canvas
      shadows
      camera={{
        fov: 45,
        near: 0.2,
        far: 200,
        position: [-60, 0, 0],
        rotation: [0, Math.PI / 2, 0],
      }}
    >
      <OrbitControls
        // autoRotate
        enableZoom={false}
        maxPolarAngle={Math.PI / 2}
        minPolarAngle={Math.PI / 2}
      />
      <directionalLight intensity={0.5} />
      <ambientLight intensity={0.5} />
      <pointLight intensity={2} />
      <Suspense fallback={<CanvasLoader />}>
        <Model />
      </Suspense>
    </Canvas>
  );
};

export default Phoenix;


asdas


https://www.kevincarlosqa.dev/



Kevincarlosqa

Kevincarlosqa

Apasionado por la tecnología y su capacidad transformadora en todos los aspectos de la vida ⚡. Desde una temprana edad he estado inmerso en el mundo de la tecnología comenzando con estudios para convertirme en técnico de computadoras. Más tarde mi pasión me llevó a obtener un título en Ingeniería Mecatrónica donde tuve la oportunidad de explorar la programación.

Leave a Reply

0 Comments

Related Posts

Categories