Check out the full course!
TresJS is a Vue custom renderer for ThreeJS that allows you to create 3D scenes declarative by using Vue components and composables.
Using vanilla ThreeJS can be intimidating for new developers, and code can get spaghetti :spaghetti: really quickly making the DX often unpleasant. TresJS aims to reduce this gap by offering users a way of building interactive 3D scenes with a familiar workflow using their favorite framework.
In this tip, we are going to learn how to use the TresJS starter with ViteJS:
- Creating a new scene from scratch with TresCanvas
- Add an object with its geometry and material
- Transform objects using position, rotation, scale
- Animate objects using Vue template refs and useRenderLoop composable
Transcript
To create a 3D project using Vue and Thread.cs, we're going to use one of the starters that we have in our organization, which contains the latest versions of the core and also the latest version from 3GS. So we're going to copy and paste this command right here, the npx digit, which is the one that is going to copy the template and initialize a new project. So npx digit, trace.js starter and the name of your project. Hit enter. Once it's cloned, let's go inside of the project by using CD and then inside of it, let's install the dependencies by using pnpm install.
Once it's done, let's check that everything is working as expected. Then run npm run, This is an alias for NPM run def If everything went well, we should see a scene with a cube rotating Once we open our recently created a project in VS Code, we're going to see a common Vite plus Vue app, which contains an App.Vue. And in this App.Vue I'm importing a component, which is called Experience, that is containing the scene that you just saw Since we are going to create it from scratch. Let's just remove the experience and We are going to create our scene from scratch here The first thing that we're going to need is to import the TressCanvas component from the core package. So, TressCanvas from TressESCore.
We're going to add it to the template, using TraceCanvas as any other view component. This component is special because it contains the custom renderer API and all the context for your 3D scene. That means that everything that you want to put inside of the scene needs to be inside of the Trace Canvas. To check that it works, let's add some props. First, let's tell the Trace Canvas component to occupy the full width and height.
Then, let's add a clear color. The clear color is just basically the background of our render. I'm gonna add this value and hit save. If we refresh, now we have an empty scene with a color in the background This means that everything is working Notice that we are able to see our scene Even if we didn't strictly pass a camera to the trace canvas component That's because the trace canvas contains a default camera if none is passed Well, if we want to customize it we can always add a trace Perspective camera and pass the position so all the objects 3d objects or like components in 3ds has the position and then pass an array with the X value the Y value and the Zeta value. In this case to differentiate from the default camera we're gonna set it in a position of 999.
Let's close the component and also we need to tell the camera where to look at. In this case, we're going to point it to the middle of the scene, in the center. Let's click Save. And now you can notice that the camera is a little bit far than before. The perspective camera is the most common use because it closely mimics how the human eye perceives the world.
It also works similar to how the movie or photography cameras work. It resembles a natural vision with objects appearing smaller as they get further away, creating a sense of depth and realism. We can transform our object in different ways by passing properties into the Trace Mesh. One way we can modify it is by translating it into the 3D space by using the Position prop. Similar of the Trace perspective camera where we use the position to fix the camera in a different place But to be able to see Where it goes we're gonna use a tres axis helper That is gonna live in the middle of the scene and is going to point out where the center is So now let's use the position to translate our cube in the 3d space We're gonna set it to 2 on the x-axis left or right Let's put 4 on the y-axis the height and in the depth let's use minus 1.
So now you can see that our cube has been translated from the center of the scene. Let's reduce the position here to see a little bit closer. If we use a scale in a similar way of how the position works we can pass three numbers. We can pass the scale in the x-axis, meaning that we could do it wider, for example. We can set on the y-axis if we want it to be a little bit taller.
And if we want to modify the depth, let's say we want to have this cube a little bit thinner, we can do it like this. Last but not least, we can set the rotation. So the rotation works in a similar way, we have three numbers, so we can rotate it on the x-axis and for this we're gonna use degrees. So the best way of doing it is by using Math.p and then for example half. This will be half a turn.
And with this we have our cube rotated in the x-axis, so in the red one, by half a turn. Let's modify for example the zeta axis and say, I don't know, something like a quarter of P, but negative. And now it's gonna be translated on the zeta axis. This is how you can translate, scale and also rotate your objects in Trace.js. To animate an object inside of the 3D scene, we're going to use the UseRenderLoop composable available on the Tri-CS core.
This composable is going to give us some useful methods like the onLoop that we're going to call with a function that is going to serve as the callback. So this callback is going to be triggered every frame per second. So every time the browser generates a new render frame this is going to be triggered. It could be tempting to animate the rotation of the cube for example by using a reactive variable that we pass as a prop. So if we use box rotation here and we say this is a reactive object that contains the initial values for the rotation and then We pass this to the truss mesh as a prop so rotation Equal to box rotation And then inside of the loop, every frame will try to modify the first value, which is the x, but a certain value.
So even if this might work, The problem is that the reactivity system of Vue uses proxies under the hood, which using it in a context like every frame per second can lead to performance issues because it's not as performant as modifying a plain object. So if you're doing a heavy operation like requesting a trigger every frame per second, meaning that you're going to have at least 60 times this function being called every second, this might affect the performance of your scene. So what you need to do instead is create a template ref. So we're going to use view, the ref, we're going to remove this here, We need to import this from view, okay, and we might just remove the reactive. And instead of passing the rotation as a prop, What we're gonna use is ref and pass the box ref.
So in this variable, whenever this is mounted initialize, it's gonna give us exactly the plain object of this box, which is inside of the scene. Once we have it we can do something with it like animate. So in the on loop I'm gonna first check if the box graph has a value if it doesn't we just return. But if it does have it, let's modify the rotation in the X value by a certain value. In this case, since this is running a lot, we're gonna use a small value like 0.0.
Let's hit save and now we can see that our object is being animated in rotation of the x-axis. This way is going to be completely performant and you're going to have the same frame per second rate every time. The onLoop method callback gives us an object with certain properties that we can use to animate our scene. One is the delta, and the other one is the lapse. The delta is just the difference between two frames, which is going to be a really small number.
And the lapse set is just the time that has passed since the beginning of the callback, the first time it was registered. So why is it better to use the delta when animated or objects into the 3D scene. It's because all the devices and different monitors have different rates for frames per seconds, so it means that in some devices they might run faster and in other ones can be slower. That leads to an inconsistent experience in animations between your users. So by using the Delta we're ensuring that we are using the same speed every time because this is calculated between the different frames.
If we use the Lapsed, it's something that is going to be similar So we're going to use here box ref value Rotation and now let's rotate on the z-axis But instead of using the plus equal we are just going to equal this to the elapsed time. This is going to achieve a similar result as the delta with the plus equal sign. So now we're rotating our cube into axis. And This is how you can create a 3D object and animate it inside of your 3D scene by using Vue and Trace.js.