Three.js is a lightweight JavaScript library used to generate 3D graphics in the browser. It is essentially a wrapper for WebGL, a low-level graphics library that has been standardized for the web and is widely integrated by most web browsers today.
In the case a browser does not support WebGL, Three.js does have the option to fallback to software rendering.
I was inspired to learn more about 3D rendering and game design after watching some of the homebrew demos of games created by a certain Tom van den Boogaart on YouTube.
The 3D graphics are crudely drawn but are consistent in style, with some attention to detail. Overall there is an eerie retro vibe evoked from these worlds. Check out this one, aptly titled 'sea and a boat'.
Wonderfully atmospheric.
Feeling thus inspired, I set off to venture and create a new world with 3D graphics, using Vim, my browser and Three.js to sculpt and shape. Here is how I set out.
I'm going to try to depict a simple but signature landscape with my first Three.js project: the desert.
$ mkdir the-desert && cd the-desert
$ npm install generator-threejs
$ yo threejs
I am using the Yeoman generator for three.js because it provides an automatically-configured blank slate. And most enticing of all, live-reload is included.
If yeoman did not run npm install
like it should have, go ahead and run it. (I did have to do this.)
Once that is complete, run grunt
to kick off the default build task. It should build the files, start the server and open up a browser window where you will see a red cube rotating slowly against a black backdrop.
The first thing I want to change is the bleak black background. Say that three times fast. Anyways, I will have to add some configuration to my `renderer` object.
// app/js/main.js
function init() {
( ... )
renderer.setClearColor(0xb2f0ff);
( ... )
}
The background color of the scene is painted by setting the 'clear color' of the renderer object. This is the color the renderer will use to clear the scene before it renders. This only happens when autoClear
is set to true (which is default).
To add the ground, I first removed the few lines of code written for the cube. Specifically:
// from init()
var geometry, material, mesh;
geometry = new THREE.BoxGeometry( 200, 200, 200 );
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// from animate()
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
Then I added the following inside of the init
function:
// Geometry: floor
var floor = new THREE.Mesh(
new THREE.CubeGeometry(10000, 10, 10000),
new THREE.MeshLambertMaterial({color: 0xe1bf16})
);
scene.add(floor);
I am creating a Mesh object and adding it to the scene.
A Mesh object is comprised of both a Geometry object and a Material object. Think of the Geometry object as being the wireframe of the model, and the Material being the surface of it.
The Material of a model has properties that include its color, texture, and how it reacts to light, among other things.
So I made my cube really long and really wide but not really tall so that it would act like the ground in my scene. I also set the color to a dirt/muddy kind of color.
There were two more things I had to do: 1) reposition the camera and 2) introduce some lighting.
camera.position.y = 50;
This was necessary because by default the camera will start at the origin, meaning that it would be inside of the floor that I just created. Positioning the camera at y: 50 raises it well enough so that we can see the new floor model we created.
You will notice that the floor at this point is pitch black. That is because it is of Lambert material which requires lighting to be seen properly. Add the following to your init
function.
// Lighting
var directionalLight1 = new THREE.DirectionalLight( 0xF7EFBE, 0.7 );
directionalLight1.position.set( 0, 1, 0 );
scene.add( directionalLight1 );
A Directional Light is a light source that does not come from one point but rather is like a wall of light, that is infinitely far away and casts an even distribution of light on the objects it illuminates. So here I have created a Directional Light that is coming from above, as denoted by the positive Y value.
(*Some of the code here was taken from an excellent tutorial written by Issac Sukin on how to make an FPS in Three.js*)
So everything should be working so far; our very basic ground and sky.
Using an image I can paint the surface of a Mesh object with something more interesting than a solid color.
After searching the web for desert texture images, I finally selected one and saved it to 'app/img/desert.jpg'. Then I made the following change to our floor
object:
var floor = new THREE.Mesh(
new THREE.CubeGeometry(10000, 10, 10000),
new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('/img/desert.jpg')
})
);
Now we have a real desert (albeit a little blurry)!
In order to move and look around in this world we will need to capture User Input and translate it into movement of our camera object.
Luckily, three.js comes with several pre-made control implementations, located in its GitHub repo, that take care of translating input to movement. They are not extensive but are intended for basic or demonstrative uses.
I am going to use 'OrbitControls' since it allows me to look around, pan and zoom in or out of the picture.
$ cd app/js
$ wget https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js
Add the new js file to index.html.
// app/index.html
...
<script src="js/vendor/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/main.js"></script>
And make the necessary additions to main.js.
// app/js/main.js
var controls, clock;
function init() {
( ... )
clock = new THREE.Clock();
controls = new THREE.OrbitControls(camera);
( ... )
}
function animate() {
( ... )
controls.update(clock.getDelta());
( ... )
}
Now we are able to look (left-mouse button + drag), pan (right mouse button + drag) and zoom (mouse-wheel) with OrbitControls.
In conclusion, Three.js is a powerful and versatile tool for creating 3D graphics in the browser. It is based on WebGL, which is widely integrated by most web browsers, and has the option to fallback to software rendering in case a browser does not support WebGL. With Three.js, users can create amazing 3D worlds and environments using JavaScript and a variety of pre-made controls.
This article provides a simple but effective guide on how to use Three.js to create a desert landscape, complete with a sky blue background, a dirt/muddy colored ground, and an interesting desert texture. Additionally, it shows how to add movement to the world using the pre-made control 'OrbitControls.'
Overall, Three.js is an excellent tool for game design and 3D rendering on the web, and this article serves as a great starting point for beginners looking to learn more about it.