Tecnologías 3D en la Web
Web Graphics Library, es una API de Javascript para implementar gráficos 2D y 3D en el navegador, es una tecnología acelerada por hardware, es decir que se alimenta de la potencia computacional de la maquina, especialmente la tarjeta grafica o GPU, utilizada para implementar sitios web interactivos en 3D o videojuegos en el navegador haciendo uso de la etiqueta “Canvas”
Algunos ejemplos del uso de WebGL puede verse en Google Maps o Google Earth o para visualización de datos, también puede encontrarse comúnmente en páginas de marcas para mostrar sus productos como autos o dispositivos móviles o incluso en Unity para crear experiencias 3D más interactivas en la Web.
Easing WebGL Implementation: Three.js and React Three Fiber
Existen librerías como Three.js y React Three Fiber que facilitan la implementación de WebGL al proporcionar abstracciones de alto nivel y componentes de React para crear y mostrar gráficos 2D y 3D en el navegador de manera más modular y fácil de entender.
Three.js es una librería de código abierto que se puede utilizar en múltiples navegadores web y está escrita en Javascript, lo cual, la hace accesible a desarrolladores que utilizan cualquier librería o framework de Javascript, React Three Fiber, por otro lado, es una librería basada en Three.js y proporciona componentes de React para renderizar los gráficos 2D y 3D de forma más modular y sencilla.
Optimización de gráficos y rendimiento en WebGL
Es importante destacar que trabajar con WebGL puede ser exigente en términos de recursos de hardware, por lo que es importante optimizar los gráficos y el rendimiento para garantizar una experiencia fluida y eficiente en el navegador.
Aplicaciones prácticas de WebGL
WebGL también se utiliza para mostrar apartamentos en 3D de manera dinámica, proporcionando una experiencia más atractiva e interactiva para los posibles clientes. Con WebGL, los usuarios pueden ver un apartamento en 3D, rotar la cámara para ver el espacio desde diferentes ángulos e incluso caminar virtualmente a través del espacio.
Las vistas de productos de 360 grados pueden ser una herramienta poderosa para sitios web de comercio electrónico, ya que permiten a los clientes obtener una mejor idea del diseño y la funcionalidad del producto. También pueden ayudar a los clientes a tomar decisiones de compra más informadas al proporcionar una vista más detallada del producto.
Design the next Iphone / neal.fun
Creación de escenas 3D con Three.js y React Three Fiber: tutorial paso a paso
En los últimos años, ha habido un aumento en la popularidad de la creación de animaciones 3D en el navegador. Una de las herramientas más populares para lograr esto es React Three Fiber, que proporciona un conjunto de componentes de React para construir escenas 3D utilizando Three.js. En esta sección, aprenderemos a crear una sencilla escena 3D que incluye el sol, la tierra y algunas estrellas.
Creamos un proyecto de Vite con React
npm create vite@latest earth-sun-system
Instalamos dependencias necesarias
npm i @react-three/fiber @react-three/drei @react-three/postprocessing three
En el componente main.jsx importamos el componente Canvas desde @react-three/fiber y lo instanciamos alrededor de App
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { Canvas } from '@react-three/fiber'; ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <Canvas> <App /> </Canvas> </React.StrictMode> );
Desde el componente App creamos un componente Mesh alrededor de una geometría de esfera con un material básico.
El mesh puede verse como la composición de un esqueleto y su piel, siendo la geometría esférica el esqueleto y el material básico con la prop de valor red su piel.
import React from 'react'; import './App.css'; const App = () => { return ( <> <mesh> <sphereGeometry /> <meshBasicMaterial color='red' /> </mesh> </> ); }; export default App;
Con esto es suficiente para generar algo en pantalla, pero antes, en el App.css vamos a establecer estilos para que nuestro canvas ocupe toda la pantalla. Recuerda importarlo en App.jsx
* { box-sizing: border-box; } html, body, #root { width: 100%; height: 100%; margin: 0; padding: 0; }
Ejecutamos
npm run dev
Podemos ver un canvas estático con una esfera roja en 3D en la pantalla, aunque aún no podremos orbitar la cámara.
Ahora podemos importar las texturas que usaremos, @react-three/drei nos permite importar texturas de manera sencilla.
Importamos la librería y las texturas, tendremos en cuenta que la dirección de las texturas es public/textures/..., el hook useTexture ya determina por defecto la ruta public, una vez importadas, cambiaremos el material de nuestro mesh de meshBasicMaterial a meshStandardMaterial y le asignamos la textura daymap mediante el prop map, este material soporta las texturas que usaremos, todo queda de la siguiente manera.
Las imagenes se pueden encontrar el Repositorio
import { useTexture } from '@react-three/drei'; import React from 'react'; import './App.css'; const App = () => { const [daymap, cloudMap, bump] = useTexture([ 'textures/daymap.jpg', 'textures/cloudmap.jpg', 'textures/elevation.jpg', ]); return ( <> <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} /> </mesh> </> ); }; export default App;
Ahora vemos una esfera oscura en pantalla, esto es debido a que el material meshStandardMaterial es afectado por la luz, y aun no hay luz en la escena.
Procedemos a crear una luz ambiental con una intensidad de 0.5 debajo del mesh.
Tambien importaremos y agregaremos el componente OrbitControls para mover nuestra escena con el cursor.
import { OrbitControls, useTexture } from '@react-three/drei'; import React from 'react'; import './App.css'; const App = () => { const [daymap, cloudMap, bump] = useTexture([ 'textures/daymap.jpg', 'textures/cloudmap.jpg', 'textures/elevation.jpg', ]); return ( <> <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} /> </mesh> <ambientLight intensity={0.5} /> <OrbitControls /> </> ); }; export default App;
Ya comienza a tener forma.
Procedemos a agregar la textura de relieve al meshStandardMaterial y una escala de relieve
//... <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} bumpMap={bump} bumpScale={0.7} /> </mesh> //...
Si te diste cuenta, no ha hecho ninguna diferencia, esto es porque esta textura es reactiva a la luz, sin embargo la luz ambiental no es suficiente para activar el efecto, por lo que debemos agregar una luz con dirección, como pointLight
//... <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} bumpMap={bump} bumpScale={0.7} /> </mesh> <ambientLight intensity={0.5} /> <pointLight intensity={2} position={[5, 5, 5]} /> //...
Ahora podemos ver que se ve mucho mas detallado e iluminado no uniformemente ya que la luz pointLight llega una dirección especifica, como el sol.
Para la implementación de las nubes no lo haremos directamente en la Tierra sino que crearemos un nuevo mesh con el mapa de textura de las nubes y con una transparencia y opacidad definida, además con un radio un poco mayor al de la tierra, pero con el mismo centro, para cree la ilusión correctamente.
//.. <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} bumpMap={bump} bumpScale={0.7} /> </mesh> <mesh> <sphereGeometry scale={1.025} /> <meshStandardMaterial transparent opacity={0.22} map={cloudMap} /> </mesh> <ambientLight intensity={0.5} /> <pointLight intensity={2} position={[5, 5, 5]} /> //..
Ahora se pueden ver las nubes.
Ahora agregaremos un fondo mas oscuro con el componente color, debajo de pointLight lo instanciamos asi.
//.. <pointLight intensity={2} position={[5, 5, 5]} /> <color args={['black']} attach="background" /> //..
con la propiedad attach indicamos que este se va a adherir a la propiedad background del Canvas ya que este es el Parent de color
Ahora es momento de agregar la estrellas, lo cual @react-three/drei hace que sea bastante simple, con el componente Stars y algunos props lo instanciamos rápidamente.
import { Stars, OrbitControls, useTexture } from '@react-three/drei'; //... <Stars radius={100} depth={200} count={5000} factor={6} saturation={0} color='green' fade speed={1} />; //...
Ahora procederemos a agregar el Sol, para el sol crearemos una esfera y además, la pointLight que creamos antes estará en la misma posición que el Sol, para que así la luz venga en esa dirección, a su vez aumentaremos su intensidad a 4 ya que estará más alejada y le agregaremos el mismo color.
//... { /* Sol */ } <mesh position={[-100, 45, 0]} scale={1.5}> <sphereGeometry /> <meshStandardMaterial color={[1, 1, 0]} /> </mesh>; { /* Luz generada por el Sol */ } <pointLight intensity={4} position={[-100, 45, 0]} color={'#e5b04d'} />; //...
Ademas, bajaremos la intensidad de la luz ambiental para dar un efecto mas inmersivo, ya que la otra cara de la tierra es demasiado clara.
//... <ambientLight intensity={0.1} /> //...
Parece que el Sol esta demasiado apagado. Para el toque final agregaremos un efecto de Post-procesado, con un Capa de Bloom, esta capa genera un efecto de "Encandelillamiento" que hará ver nuestra escena mucho mejor.
Los Efectos de Post-Procesado pueden afectar bastante el rendimiento de una aplicación, y por cada capa que se agregue puede ser aun mas exigente para el Hardware.
Para agregar el Bloom, desde la librería @react-three/postprocessing importamos el Compositor y el efecto Bloom
Además, vamos a saturar los colores del material correspondiente al Sol y a agregar propiedades emisivas para que se vea afectado por el Bloom.
Queda de la siguiente manera
..// {/* Sol */} <mesh position={[-100, 45, 0]} scale={4.5}> <sphereGeometry /> <meshStandardMaterial color={[100, 100, 0]} emissiveIntensity={100} //Intensidad emisiva emissive={'#e5b04d'} //Color de emision toneMapped={false} //Mapeo de tono /> </mesh> {/* Compositor y capa de Bloom */} <EffectComposer> <Bloom mipmapBlur intensity={0.1} luminanceThreshold={0} /> </EffectComposer> //...
Resultado final:
Y Código final de App
import { OrbitControls, useTexture, Stars } from '@react-three/drei'; import { Bloom, EffectComposer } from '@react-three/postprocessing'; import React from 'react'; import './App.css'; const App = () => { const [daymap, cloudMap, bump] = useTexture([ 'textures/daymap.jpg', 'textures/cloudmap.jpg', 'textures/elevation.jpg', ]); return ( <> {/* Tierra */} <mesh> <sphereGeometry /> <meshStandardMaterial map={daymap} bumpMap={bump} bumpScale={0.7} /> </mesh> {/* Nubes */} <mesh scale={1.025}> <sphereGeometry /> <meshStandardMaterial transparent opacity={0.22} map={cloudMap} /> </mesh> {/* Estrellas */} <Stars radius={100} depth={200} count={5000} factor={6} saturation={0} color='green' fade speed={1} /> {/* Sol */} <mesh position={[-100, 45, 0]} scale={4.5}> <sphereGeometry /> <meshStandardMaterial color={[100, 100, 0]} emissiveIntensity={100} emissive={'#e5b04d'} toneMapped={false} /> </mesh> {/* Luz generada por el Sol */} <pointLight intensity={4} position={[-100, 45, 0]} color={'#e5b04d'} />;{/* Compositor y capa de Bloom */} <EffectComposer> <Bloom mipmapBlur intensity={0.1} luminanceThreshold={0} /> </EffectComposer> {/* Luz ambiental */} <ambientLight intensity={0.1} /> {/* Controles */} <OrbitControls /> {/* Fondo */} <color args={['black']} attach='background' /> </> ); }; export default App;
Repositorio de Github
Proyecto desplegado
Conclusiones
En conclusión, tecnologías como WebGL, Three.js y React Three Fiber, permiten a los desarrolladores crear gráficos 2D y 3D en el navegador de manera más fácil y modular, lo que ha llevado a una mayor cantidad de sitios web interactivos en 3D y videojuegos en línea. Aunque es importante tener en cuenta que trabajar con WebGL puede ser exigente en términos de recursos de hardware, la optimización del rendimiento garantiza una experiencia fluida y eficiente en el navegador. En general, el uso de estas tecnologías ha llevado a una experiencia más atractiva e interactiva en la web.
Articulo Elaborado Por:
Santiago Velasquez
Desarrollador de software en
I.A.S. Ingeniería, Aplicaciones y Soluciones S.A.S.