Vue + threeJs, importando modelos
Jaimebboyjt
Posted on February 13, 2023
Hola, Este es el tercer post de Vuejs+ threeJS
- Si no has visto el primer post donde creamos un template te lo recomiendo, usaremos ese template como base para este post
Esta vez añadiremos un modelo 3D.
Puedes descargar modelos 3D desde alguno de estos sitios:
Nota: Como consideración importante, el peso del modelo es importante recuerda que el usuario lo va a tener q descargar desde su navegador, por lo que siempre modelos low Poly son recomendados, o optimizados para web
Yo elegiré este modelo link y el resultado final es este:
Formatos:
Existe una amplia variedad de formatos, incluso puedes crear uno nuevo.Entre los más comunes nos encontramos con:
- OBJ
- GLTF
- glb (mi favorito personal)
- 3DS (uno de los favoritos del maestro Bruno Simon)
- FBX
- Draco
ThreeJs viene con loaders para algunos de ellos, aunque no vienen importados en el “three” y tenemos que acceder al node_modules directamente para usarlos (esto se corregirá en futuras versiones de ThreeJs).
A codear
Importamos y probamos el loader
Lo primero será descargar un modelo, yo para este ejemplo descargar un modelo low poli de https://poly.pizza/m/iltq5bVNaV. en formato glb que además tiene una animación (la usaremos en un futuro post)
Ya conociendo el formato, podemos crear un composable, para rehusar lógica. Crearemos un nuevo archivo composables/useGltf
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// desconozco el motivo porque los loaders se encuentran dentro de examples
// en caso que tu modelo sea otro formato aca examples/jsm/loaders/ puedes revisar los loaders disponibles
export const useGltfModel = () => {
const loader = new GLTFLoader();
console.log(loader)
return;
};
// para testear la función coloquemos en el onMouted
// además añadamos async al ciclo de vida
Luego importamos la función en nuestro App.vue y certificamos que tengamos un log en la consola
onMounted(async () => { // añadimos el async al mounted
...
await useGltfModel();
...
Ahora subamos nuestro modelo, a nuestros assets, (si estás usando vite, te recomiendo subirlo dentro de la carpeta public, la importación es más fácil) usemos la función loadAsync
que recibirá la ruta a nuestro modelo (el path). Además transformemos nuestra función en una promesa
export const useGltfModel = async () => {
const loader = new GLTFLoader();
const _model = await loader.loadAsync("MODEL_PATH");
return _model.scene;
};
Y si todo ha ido bien podemos hacer un console.log en el mounted
Lo que yo recomiendo es crear un container de modelos, inicializarlos fuera y así tenerlos accesibles en nuestro App.vue
const modelContainer = {
rat: null,
};
...
onMounted(async () => {
...
modelContainer.rat = await useGltfModel();
console.log(modelContainer);
...
Añadir el modelo
Normalmente los modelos que son exportados en otros software más robustos como blender exportan un objeto que contiene varias propiedades como scene, scenes, animations etc. Para añadirlo a la escena normalmente necesitamos el .scene
Para añadir el modelo una forma es pasarle la escena directamente a la función y hacer el scene.add(_model.scene). Mientras hacemos este pequeño cambio añadamos otros parámetro que sea el path así nuestro useGltfModel quedará reutilizable.
export const useGltfModel = async (path, scene) => {
const loader = new GLTFLoader();
const _model = await loader.loadAsync(path);
scene.add(_model.scene);
return _model;
};
Con todo correcto debiésemos poder ver nuestro modelo completamente negro, si has llegado hasta aca sin remover el cubo del template podrás fijarte.
Lo que sucede es que los modelos trabajan con PRB (Phisical Based Rendering) y usan materiales como MeshStandardMaterial que reaccionan a la luz. Necesitamos agregar luz a nuestra escena para poder apreciar nuestro modelo.
Añadiendo luz
Para tener más control creemos un archivo separado, lights.js y colocaremos nuestras luces allí.
Nota: Al igual que las sombras las luces y sus tipos pueden impactar en tu rendimiento úsalas sabiamente (explicaremos más en un capítulo de performance tips)
Al igual que como en muchos objetos que nos proporciona threeJs existen muchos tipos de luces, dedicaremos un post entero a explicar como funcionan, por ahora vamos a añadir una simple directionalLight, que básicamente simula un sol y siempre apunta al centro de la escena.
import { DirectionalLight } from "three";
export const initDirectionalLight = (scene) => {
const directionalLight = new DirectionalLight(0xc0c0c0, 2.5);
//Params (color, intensidad)
scene.add(directionalLight);
return directionalLight;
};
Usémosla en nuestro App.vue
...
import { initDirectionalLight } from "./lights";
...
const light = initDirectionalLight(scene);
...
Y ya vemos que nuestro modelo reacciona pero…. solo se ve desde arriba…
y para solucionarlo podemos hacer dos cosas.
- Añadir rotación a la luz en nuestra función tick
- Añadir OrbicControls
- Bajar de position y nuestro modelo
Dedicaremos otro post al tema de los controls para definirlo en profundidad pero en realidad es bastante sencillo
Animando la luz
Esta parte puede ser un poco compleja de entender al principio, y también añadiré un post para explicarlo con más profundidad. Pero básicamente le indicaremos a nuestra luz que gire sobre su eje.
import { Scene, Clock } from "three";
...
// dentro del mounted y antes de nuestra funcion tick
const clock = new Clock();
// creamos un reloj que nos devolvera un tiempo
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// obtenemos la diferencia de tiempo que ha transcurrido entre el clock y el tick
const lightAngle = elapsedTime * 0.5;
// con el elapsedTime podemos crear un angulo,
// luego con las funciones de coseno y seno se convertiran en un circulo
light.position.x = Math.cos(lightAngle) * 4;
light.position.z = Math.sin(lightAngle) * 4;
Y ¡Listoya! tenemos nuestra luz girando sobre su propio eje y mostrando nuestro modelo
yo para efectos de mi modelo voy a ajustarlo un poco modelContainer.rat.scene.position.y = -1 pero puede que tu no lo necesites. (si lo deseas puedes eliminar el cube llegados a este punto)
y con esto estaríamos listos.
Conclusión
Hemos visto nuevos conceptos como:
- Light
- ElapsedTime
- Cómo cargar un modelo de manera asíncrona.
Todo esto nos servirá más adelante para nuestros futuros proyectos, threeJs es muy amplio pero a la vez tiene documentación muy buena.
Posted on February 13, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024