DEV Community

Cover image for Build 3D Scenes Declaratively with TresJS using Vue
Alvaro Saburido
Alvaro Saburido

Posted on • Originally published at alvarosaburido.dev

Build 3D Scenes Declaratively with TresJS using Vue

For a more interactive experience, read this article here alvarosaburido.dev.

What if I tell you that this scene right here:

Low Poly Planet Scene

It's entirely done using Vue components, yes, Vue components 🤯.

<script setup lang="ts">
import { useGLTF, useTweakPane } from '@tresjs/cientos'
import { useRenderLoop } from '@tresjs/core'
import { shallowRef, watch } from 'vue'
import Airplane from './Airplane.vue'
import Cloud from './Cloud.vue'

const { scene: planet } = await useGLTF(
  'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/low-poly/planet.gltf',
)

const { pane } = useTweakPane()

const planetRef = shallowRef()

planet.traverse(child => {
  if (child.isMesh) {
    child.receiveShadow = true
  }
})

watch(
  () => planetRef.value,
  planet => {
    if (!planet) return
    pane.addInput(planetRef.value, 'visible', { label: 'Planet' })
  },
)

const { onLoop } = useRenderLoop()

onLoop(({ delta }) => {
  if (!planet) return
  planet.rotation.y += delta * 0.04
  planet.rotation.z += delta * 0.02
  planet.rotation.x += delta * 0.05
  planet.updateMatrixWorld()
})
</script>
<template>
  <TresMesh ref="planetRef" v-bind="planet" />
  <Airplane :planet="planetRef" />
  <Cloud v-for="cloud of [1, 2, 3, 4, 5, 6, 7, 8, 9]" :key="cloud" :planet="planetRef" />
</template>

Enter fullscreen mode Exit fullscreen mode

That's the magic of TresJS, a declarative way of using ThreeJS with Vue components! If you've ever tried to create 3D experiences on the web with ThreeJS, you know how powerful it is but also how complex it can be. TresJS aims to simplify the process and make it more approachable by leveraging the power of Vue's declarative syntax.

Whether you're a seasoned developer or a beginner, TresJS can help you create stunning 3D visuals with less code and less hassle. In this tutorial, we'll cover the basics of TresJS and show you how to create your first 3D scene using Vue components.

By the end of this tutorial, you'll have a solid understanding of how TresJS works and how to use it to create 3D scenes with ease. So, let's get started and see what TresJS can do for you!

You can find the documentation here.

The mighty getting started step

pnpm add three @tresjs/core -D
Enter fullscreen mode Exit fullscreen mode

You can install TresJS as any other Vue plugin

import { createApp } from 'vue'
import App from './App.vue'

import Tres from '@tresjs/core'

export const app = createApp(App)

app.use(Tres)
app.mount('#app')
Enter fullscreen mode Exit fullscreen mode

Setting up the experience Canvas

Before we can create a Scene, we need somewhere to display it. Using plain ThreeJS we would need to create a canvas HTML element to mount the WebglRenderer :

const canvas = document.querySelector('canvas'):

const renderer = new THREE.WebGLRenderer(canvas);
Enter fullscreen mode Exit fullscreen mode

With TresJS you only need to add the default component <TresCanvas /> to the template of your Vue component.

<template>
  <TresCanvas> // Your scene is going to live here 
  </TresCanvas>
</template
Enter fullscreen mode Exit fullscreen mode

The TresCanvas component is going to do some setup work behind the scene:

  • It creates a WebGLRenderer that automatically updates every frame.

  • It sets the render loop to be called on every frame based on the browser refresh rate.

Creating a scene

Scene diagram

We need 3 core elements to create a 3D experience:

With plain ThreeJS we would initialise a scene and a camera instance and then pass them to the renderer method render

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

// And then we render a frame
renderer.render( scene, camera );
Enter fullscreen mode Exit fullscreen mode

With TresJS you can create a Scene using the <TresScene /> component.

<template>
  <TresCanvas>
    <TresScene>
      <!-- Your scene goes here -->
    </TresScene>
  </TresCanvas>
</template>
Enter fullscreen mode Exit fullscreen mode

Then you can add a PerspectiveCamera using the <TresPerspectiveCamera /> component.

<template>
  <TresCanvas>
    <TresPerspectiveCamera />
    <TresScene>
      <!-- Your scene goes here -->
    </TresScene>
  </TresCanvas>
</template>
Enter fullscreen mode Exit fullscreen mode

But wait! What if I want to initialize the camera with some default parameters, like the field of view (fov) THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

Arguments

Some ThreeJS objects have arguments, for example, the PerspectiveCamera constructor has the following arguments:

  • fov - Camera frustum vertical field of view.
  • aspect - Camera frustum aspect ratio.
  • near - Camera frustum near plane.
  • far - Camera frustum far plane.

To pass these arguments to the TresPerspectiveCamera component, you can use the args prop:

<template>
  <TresCanvas>
    <TresPerspectiveCamera :args="[45, 1, 0.1, 1000]" />
    <!-- Your scene goes here -->
  </TresCanvas>
</template>
Enter fullscreen mode Exit fullscreen mode

Adding a Donut 🍩

That scene looks a little empty, let's add a basic object. If we where using plain ThreeJS we would need to create a Mesh object and attach to it a Material and a Geometry like this:

const geometry = new THREE.TorusGeometry(1, 0.5, 16, 32)
const material = new THREE.MeshBasicMaterial({ color: 'orange' })
const donut = new THREE.Mesh(geometry, material)
scene.add(donut)
Enter fullscreen mode Exit fullscreen mode

A Mesh is a basic scene object in three.js, and it's used to hold the geometry and the material needed to represent a shape in 3D space.

Now let's see how we can easily achieve the same with TresJS. To do that we are going to use <TresMesh /> component, and between the default slots, we are going to pass a <TresTorusGeometry /> and a <TresMeshBasicMaterial />.

<template>
  <TresCanvas>
    <TresPerspectiveCamera :args="[45, 1, 0.1, 1000]" />
    <TresScene>
      <TresMesh>
        <TresTorusGeometry />
        <TresMeshBasicMaterial color="orange" />
      </TresMesh>
    </TresScene>
  </TresCanvas>
</template>
Enter fullscreen mode Exit fullscreen mode

Notice that we don't need to import anything, thats because TresJS automatically generate a Vue Component based of the Three Object you want to use in CamelCase with a Tres prefix. For example, if you want to use a AmbientLight you would use <TresAmbientLight /> component.

Cheff kiss

Props

You can also pass props to the component, for example, the TresAmbientLight has a intensity property, so you can pass it to the component like this:

<TresAmbientLight :intensity="0.5" />
Enter fullscreen mode Exit fullscreen mode

Set

All properties whose underlying object has a .set() the method has a shortcut to receive the value as an array. For example, the TresPerspectiveCamera has a position property, which is a Vector3 object, so you can pass it to the component like this:

<TresPerspectiveCamera :position="[1, 2, 3]" />
Enter fullscreen mode Exit fullscreen mode

Scalar

Another shortcut you can use is to pass a scalar value to a property that expects a Vector3 object, using the same value for the rest of the Vector:

<TresPerspectiveCamera :position="5" /><TresPerspectiveCamera :position="[5, 5, 5]" />
Enter fullscreen mode Exit fullscreen mode

Color

You can pass colors to the components using the color prop, which accepts a string with the color name or a hex value:

<TresAmbientLight color="teal" /><TresAmbientLight color="#008080" />
Enter fullscreen mode Exit fullscreen mode

And with that, you have everything to get started with TresJS and its cool features. Stay tuned for more articles where we will discover more awesome stuff.

FAQ

Is TresJS open source?

Not yet, but it will be soon, we are still figuring out proper CI/CD and better Typing support

Is there a Nuxt module?

Not yet, but is planned for earlier this year (2023). For now, you can extend nuxtApp.vueApp context with a Nuxt plugin

Can I contribute?

Yeeees 🔥! Just drop me a DM on Twitter @alvarosabu

Video

If you prefer a video format for this tutorial, you can visit it here

Top comments (0)