Luces y sombras
Esta guía te ayudará a comenzar con luces y sombras simples en TresJS.
Construiremos una escena simple con tres mallas y un plano, pero solo dos tendrán sombras.
Configurando la escena (opcional)
Importamos todos los módulos que necesitamos, para mayor comodidad podemos usar orbit-controls de cientos, ver aquí para saber cómo.
Coloquemos cuatro objetos en nuestra escena, uno será el plano que recibirá sombras, dos de ellos proyectarán sombras y el último no proyectará ninguna sombra en absoluto.
Voy a usar MeshToonMaterial. Simplemente porque podemos ver fácilmente el "sobreado suave".
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
</script>
<template>
<TresCanvas
clear-color="#111"
window-size
>
<OrbitControls />
<TresPerspectiveCamera :position="[5, 7.5, 7.5]" />
<TresMesh
:position="[-2, 2, 0]"
:rotation="[0, Math.PI, 0]"
>
<TresConeGeometry :args="[1, 1.5, 3]" />
<TresMeshToonMaterial color="#82DBC5" />
</TresMesh>
<TresMesh
:position="[0, 0, 0]"
>
<TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
<TresMeshToonMaterial color="#4F4F4F" />
</TresMesh>
<TresMesh
:position="[2, -2, 0]"
>
<TresSphereGeometry />
<TresMeshToonMaterial color="#FBB03B" />
</TresMesh>
<TresMesh
:position="[0, -3, 0]"
:rotation="[-Math.PI / 2, 0, 0]"
>
<TresPlaneGeometry :args="[10, 10, 10, 10]" />
<TresMeshStandardMaterial color="#f7f7f7" />
</TresMesh>
</TresCanvas>
</template>
Luces (explicación)
Como sabes, cada instancia en ThreeJs está disponible en TresJs, por lo que todos los tipos de luces también están disponibles, solo necesitamos agregar el prefijo Tres
para usarlos.
Pero no todas las luces pueden generar sombras, esta definición proviene directamente de ThreeJs y tiene sentido. Por ejemplo, el propósito de una ambientLight es iluminar todos los lados de tu escena, por lo que no tiene sentido que genere sombras. En cambio, una DirectionalLight que imita al sol puede y debe generar sombras.
Sombras (explicación)
También existen muchos tipos de sombras, por ejemplo, la "sombra suave" se genera automáticamente cuando un objeto recibe más luz de un lado, pero en resumen, una "sombra predeterminada de ThreeJS" que se dirige hacia otra superficie debe ser proyectada por una malla y otra malla debe recibirla. Como vemos en nuestro ejemplo, el Plano
está recibiendo una sombra pero no la está proyectando. Ten en cuenta que no todos los materiales pueden proyectar o recibir sombras.
Internamente, ThreeJS genera automáticamente una nueva malla con un ShadowMaterial que se actualiza en cada fotograma, por eso si aplicas animaciones, la sombra también se anima, pero también es por eso que debes usar las sombras con cuidado, ya que pueden ralentizar el rendimiento.
WARNING
El uso excesivo de sombras de esta manera puede afectar el rendimiento. Sin embargo, existen formas de mejorar el rendimiento. Para obtener más información, consulta este video
Habilitando las sombras
Podemos dividir esto en tres pasos:
Activar las sombras en el renderizador
//...
<template>
<TresCanvas
clear-color="#111"
shadows
window-size
/>
//...
</template>
Configurar la luz para proyectar sombras
Podemos simplemente agregar el booleano cast-shadow
, Vue lo interpreta como una prop
con valor true
.
La luz ambiental no genera ningún tipo de sombra aquí
//...
<template>
<TresAmbientLight :intensity="1" />
<TresDirectionalLight
cast-shadow
:position="[0, 2, 0]"
:intensity="1"
/>
//...
</template>
Establecer los objetos para proyectar o recibir sombras
De manera similar al paso anterior, configuramos la malla que queremos que proyecte sombra (nuestra esfera) con la propiedad cast-shadow
, y configuramos el objeto para recibir sombra (nuestro plano) con la propiedad receive-shadow
.
//...
<template>
<TresMesh
cast-shadow
:position="[2, -2, 0]"
>
<TresSphereGeometry />
<TresMeshToonMaterial color="#FBB03B" />
</TresMesh>
<TresMesh
receive-shadow
:position="[0, -3, 0]"
:rotation="[-Math.PI / 2, 0, 0]"
>
<TresPlaneGeometry :args="[10, 10, 10, 10]" />
<TresMeshStandardMaterial color="#f7f7f7" />
</TresMesh>
//...
</template>
Ahora tenemos todos los pasos necesarios para agregar sombras a nuestra escena, y si aplicamos lo que aprendimos en animaciones básicas, y agregamos movimiento a nuestro cubo, verás que la sombra también se anima 🤩
<script setup>
import { shallowRef } from 'vue'
import { TresCanvas, useRenderLoop } from '@tresjs/core'
const boxRef = shallowRef()
const { onLoop } = useRenderLoop()
onLoop(() => {
if (boxRef.value) {
boxRef.value.rotation.y += 0.01
}
})
</script>
<template>
//...
<TresMesh
ref="boxRef"
cast-shadow
:position="[0, 0, 0]"
>
<TresBoxGeometry :args="[1.5, 1.5, 1.5]" />
<TresMeshToonMaterial color="#4F4F4F" />
</TresMesh>
//...
</template>
Nota que intencionalmente no apliqué cast-shadow
al Cone
para que no proyecte ninguna sombra