Skip to content

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".

vue
<script setup lang="ts">
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
</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

vue
//...

<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í

vue
//...

<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.

vue
//...

<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 🤩

vue
<script setup>
import { TresCanvas, useRenderLoop } from '@tresjs/core'
import { shallowRef } from 'vue'

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