Skip to content

Light-shadows

This guide will help you get started with simple light and shadows in TresJS.

We will build a simple scene with three meshes and a plane but only two will have shadows.

Setting up the scene (optional)

We import all the modules that we need, for comfort we can use the orbit-controls from cientos, check here to know how.

Let's put four objects in our scene, one will be the plane that receive shadows, two of them will cast shadows and the last one will not cast any shadow at all.

I'm going to use MeshToonMaterial. Simply because we can see the "soft shadow" easily.

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

Lights (explanation)

As you know every instance in ThreeJs is available in TresJs so are all the light types, we just need to add the Tres prefix to use them.

But not all lights can cast shadows, this definition comes directly from ThreeJs and makes sense, for example the purpose of an ambientLight is to iluminate everysingle side of your scene, so it makes no sense for it to cast shadows, on the contrary, a DirectionalLight immitating the sun can and should cast shadows.

Shadows (explanation)

There are also many types of shadows, for example the "soft shadow" is generated automatially when an object receives more light from one side, but in summary a "ThreeJS default shadow" that is directed towards another surface needs to be cast by a mesh and another mesh needs to receive it. As we see in our example, the Plane is receiving a shadow but not casting it. Please note that not all materials can cast or receive shadows.

Internally, ThreeJS automatically generates a new mesh with a ShadowMaterial which gets updated in each frame, that is why if you apply animations, the shadow also is animated, but also why you have to use shadows carefully, because they could slow your performance down.

WARNING

The overuse of shadows in this way could drop your performance. However, there are ways to increase your performance, for more information please check out this video

Enabling shadows

We could divide this into three steps:

Activate shadows on the renderer

vue
//...

<template>
  <TresCanvas
    clear-color="#111"
    shadows
    window-size
  />
  //...
</template>

Set the light to cast shadows

We can simply add the boolean cast-shadow, Vue understands this as a prop with a value of true.

The AmbientLight doesn't generate any type of shadow here

vue
//...

<template>
  <TresAmbientLight :intensity="1" />
  <TresDirectionalLight
    cast-shadow
    :position="[0, 2, 0]"
    :intensity="1"
  />

  //...
</template>

Set the objects to cast or receive shadows

Similarly to the previous step, we set the mesh that we want to cast shadow (our sphere) with the cast-shadow prop, and set the object to receive shadow (our plane) with the receive-shadow prop.

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>

Now we have all the necessary steps to add shadows to our scene, and if we apply what we learned in basic animations, and we add movement to our cube, you will see the shadow is animated as well. 🤩

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

Note that I intentionally did not apply cast-shadow to the Cone so it doesn't cast any shadow