c02 Basic Components That Make Up a Three.js Scene

In the previous chapter, you learned the basics of Three.js. We showed a couple of examples, and you created your first complete Three.js scene. In this chapter, we’ll dive a bit deeper into Three.js and explain the basic components that make up a Three.js scene. In this chapter, you’ll explore the following topics:

En el capítulo anterior, aprendiste los conceptos básicos de Three.js. Vimos algunos ejemplos y creaste tu primera escena completa de Three.js. En este capítulo, profundizaremos un poco más en Three.js y explicaremos los componentes básicos que conforman una escena de Three.js. En este capítulo, explorarás los siguientes temas:

  • The components that are used in a Three.js scene

  • What you can do with the THREE.Scene object

  • How geometries and meshes are related

  • The difference between the orthographic and perspective cameras

We start with looking at how you can create a scene and add objects.

Comenzaremos viendo cómo puedes crear una escena y añadir objetos.

Creating a scene

In the previous chapter, you created THREE.Scene, so you already know the basics of Three.js. We saw that for a scene to show anything, we need three types of components:

En el capítulo anterior, creaste THREE.Scene, así que ya conoces los conceptos básicos de Three.js. Vimos que para que una escena muestre algo, necesitamos tres tipos de componentes:

ComponentDescription CameraThis determines what is rendered on the screen. LightsThese have an effect on how materials are shown and used when ObjectsThese are the main objects that are rendered from the perspective of the camera: cubes, spheres, and the like. creating shadow effects (discussed in detail in Chapter 3, Working with the Different Light Sources Available in Three.js).Basic Components That Make Up a Three.js Scene

THREE.Scene serves as the container for all these different objects. This object itself doesn’t have that many options and functions.

THREE.Scene sirve como contenedor para todos estos objetos diferentes. Este objeto en sí no tiene muchas opciones ni funciones.

THREE.Scene is a structure that is sometimes also called a scene graph. A scene graph is a structure that can hold all necessary information of a graphical scene. In Three.js, this means that THREE.Scene contains all the objects, lights, and other objects necessary for rendering. What is interesting to note is that a scene graph, as the name implies, isn’t just an array of objects; a scene graph consists of a set of nodes in a tree structure. Each object you can add to the scene in Three.js, and even THREE.Scene itself, extends from a base object named THREE.Object3D. A THREE. Object3D object can also have its own children, which you can use to create a tree of objects that Three.js will interpret and render.

THREE.Scene es una estructura que a veces también se denomina grafo de escena. Un grafo de escena es una estructura que puede contener toda la información necesaria de una escena gráfica. En Three.js, esto significa que THREE.Scene contiene todos los objetos, luces y demás elementos necesarios para la renderización. Es interesante destacar que un grafo de escena, como su nombre indica, no es simplemente una matriz de objetos; un grafo de escena consiste en un conjunto de nodos en una estructura de árbol. Cada objeto que se puede añadir a la escena en Three.js, e incluso el propio THREE.Scene, hereda de un objeto base llamado THREE.Object3D. Un objeto THREE.Object3D también puede tener sus propios nodos hijos, que se pueden usar para crear un árbol de objetos que Three.js interpretará y renderizará.

Basic functionality of a scene

The best way to explore the functionality of a scene is by looking at an example. In the source code for this chapter, you can find the 01-basic-scene.html example. I’ll use this example to explain the various functions and options a scene has. When we open this example in the browser, the output will look somewhat like what’s shown in the next screenshot:

La mejor manera de explorar la funcionalidad de una escena es mediante un ejemplo. En el código fuente de este capítulo, encontrará el ejemplo 01-basic-scene.html. Usaré este ejemplo para explicar las distintas funciones y opciones que tiene una escena. Al abrir este ejemplo en el navegador, el resultado será similar al que se muestra en la siguiente captura de pantalla:

This looks pretty much like the examples we saw in the previous chapter. Even though the scene looks pretty empty, it already contains a couple of objects. Looking at the following source, we can see that we used the scene.add(object) function from the THREE.Scene object to add THREE.Mesh (the ground plane you see), THREE.SpotLight, and THREE.AmbientLight. The THREE.Camera object is added automatically by Three.js when you render the scene, but it is good practice to add it to the scene manually, especially when you’re working with multiple cameras. Take a look at the following source code for this scene:

Esto se parece bastante a los ejemplos que vimos en el capítulo anterior. Aunque la escena parece bastante vacía, ya contiene un par de objetos. Si observamos el siguiente código fuente, podemos ver que usamos la función scene.add(object) del objeto THREE.Scene para agregar THREE.Mesh (el plano del suelo que se ve), THREE.SpotLight y THREE.AmbientLight. El objeto THREE.Camera se agrega automáticamente por Three.js al renderizar la escena, pero es recomendable agregarlo manualmente, especialmente cuando se trabaja con varias cámaras. Eche un vistazo al siguiente código fuente de esta escena:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth
/ window.innerHeight, 0.1, 1000);
scene.add(camera);
...
var planeGeometry = new THREE.PlaneGeometry(60,40,1,1);
var planeMaterial = new THREE.MeshLambertMaterial({color:
0xffffff});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
...
scene.add(plane);
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
...
var spotLight = new THREE.SpotLight( 0xffffff );
...
scene.add( spotLight );

Before we look deeper into the THREE.Scene object, I’ll first explain what you can do in the demo, and after that, we’ll look at some code. Open the 01-basic-scene.html example in your browser and look at the controls in the upper-right corner, as you can see in the following screenshot:

Antes de profundizar en el objeto THREE.Scene, primero explicaré qué se puede hacer en la demostración y, a continuación, veremos algo de código. Abre el ejemplo 01-basic-scene.html en tu navegador y observa los controles en la esquina superior derecha, como puedes ver en la siguiente captura de pantalla:

With these controls, you can add a cube to the scene, remove the cube that was last added to the scene, and show all the current objects that the scene contains in the console of your browser. The last entry in the controls section shows the current number of objects in the scene. What you’ll probably notice when you start up the scene is that there are already four objects in the scene. These are the ground plane, the ambient light, and the spotlight, as well as the camera we mentioned earlier. We’ll look at each of the functions in the control section and start with the easiest one, addCube, as follows:

Con estos controles, puedes añadir un cubo a la escena, eliminar el último cubo añadido y visualizar todos los objetos presentes en la escena en la consola de tu navegador. La última entrada de la sección de controles muestra el número actual de objetos en la escena. Al iniciar la escena, probablemente notarás que ya hay cuatro objetos: el plano del suelo, la luz ambiental, el foco y la cámara que mencionamos anteriormente. Analizaremos cada una de las funciones de la sección de controles, comenzando por la más sencilla: addCube.

this.addCube = function() {
var cubeSize = Math.ceil((Math.random() * 3));
var cubeGeometry = new THREE.BoxGeometry
(cubeSize,cubeSize,cubeSize);
var cubeMaterial = new THREE.MeshLambertMaterial({color:
Math.random() * 0xffffff });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
cube.name = "cube-" + scene.children.length;
cube.position.x=-30 + Math.round(Math.random() *
planeGeometry.width));
cube.position.y= Math.round((Math.random() * 5));
cube.position.z=-20 + Math.round((Math.random() *
planeGeometry.height));
scene.add(cube);
this.numberOfObjects = scene.children.length;
};

This piece of code should already be pretty easy to read by now. Not many new concepts are introduced here. When you hit the addCube button, a new THREE. BoxGeometry object is created whose width, height, and depth are set to a random value between 1 and 3. Besides a random size, the cube also gets a random color and a random position.

Este fragmento de código ya debería ser bastante fácil de leer. No se introducen muchos conceptos nuevos. Al pulsar el botón addCube, se crea un nuevo objeto THREE.BoxGeometry cuyo ancho, alto y profundidad se establecen en un valor aleatorio entre 1 y 3. Además de un tamaño aleatorio, el cubo también recibe un color y una posición aleatorios.

A new element that we introduce here is that we also give the cube a name using its name attribute. Its name is set to cube-, appended with the number of objects currently in the scene (scene.children. length). A name is very useful for debugging purposes but can also be used to directly access an object from your scene. If you use the THREE. Scene.getObjectByName(name) function, you can directly retrieve a specific object and, for instance, change its location without having to make the JavaScript object a global variable. You might wonder what the last line does. The numberOfObjects variable is used by our control GUI to list the number of objects in the scene. So, whenever we add or remove an object, we set this variable to the updated count.

Un nuevo elemento que introducimos aquí es que también le damos un nombre al cubo usando su atributo name. Su nombre se establece como cube-, seguido del número de objetos actualmente en la escena (scene.children. length). Un nombre es muy útil para fines de depuración, pero también puede usarse para acceder directamente a un objeto de su escena. Si usa la función THREE. Scene.getObjectByName(name), puede recuperar directamente un objeto específico y, por ejemplo, cambiar su ubicación sin tener que hacer que el objeto JavaScript sea una variable global. Puede que se pregunte qué hace la última línea. La variable numberOfObjects es utilizada por nuestra GUI de control para listar el número de objetos en la escena. Entonces, cada vez que agregamos o eliminamos un objeto, establecemos esta variable al recuento actualizado.

The next function we can call from the control GUI is removeCube. As the name implies, clicking on the removeCube button removes the last added cube from the scene. In code, it looks like this:

La siguiente función que podemos llamar desde la interfaz gráfica de control es removeCube. Como su nombre indica, al hacer clic en el botón removeCube se elimina el último cubo añadido a la escena. En código, se ve así:

this.removeCube = function() {
var allChildren = scene.children;
var lastObject = allChildren[allChildren.length-1];
if (lastObject instanceof THREE.Mesh) {
scene.remove(lastObject);
this.numberOfObjects = scene.children.length;
}
}

To add an object to the scene, we use the add function. To remove an object from the scene, we use, not very surprisingly, the remove function. Since Three.js stores its children as a list (new ones are added at the end), we can use the children property, which contains an array of all the objects in the scene, from the THREE.Scene object to get the last object that was added. We also need to check whether that object is a THREE.Mesh object to avoid removing the camera and the lights. After we’ve removed the object, we once again update the GUI property, numberOfObjects, that holds the number of objects in the scene.

Para añadir un objeto a la escena, usamos la función add. Para eliminar un objeto de la escena, usamos, como era de esperar, la función remove. Dado que Three.js almacena sus elementos secundarios como una lista (los nuevos se añaden al final), podemos usar la propiedad children, que contiene un array con todos los objetos de la escena, del objeto THREE.Scene para obtener el último objeto añadido. También debemos comprobar si ese objeto es un objeto THREE.Mesh para evitar eliminar la cámara y las luces. Después de eliminar el objeto, actualizamos la propiedad de la interfaz gráfica numberOfObjects, que indica el número de objetos en la escena.

The final button on our GUI is labeled outputObjects. You probably already clicked on this and nothing seemed to happen. This button prints out all the objects that are currently in our scene to the web browser console, as shown in the following screenshot:

El último botón de nuestra interfaz gráfica se llama outputObjects. Probablemente ya hiciste clic en él y no pareció suceder nada. Este botón imprime todos los objetos que se encuentran actualmente en nuestra escena en la consola del navegador web, como se muestra en la siguiente captura de pantalla:

The code to output information to the console log makes use of the built-in console object:

El código para mostrar información en el registro de la consola utiliza el objeto de consola integrado:

this.outputObjects = function() {
console.log(scene.children);
}

This is great for debugging purposes, and especially when you name your objects, it’s very useful to find issues and problems with a specific object in your scene. For instance, the properties of cube-17 look like this (if you already know the name beforehand, you could also use console.log(scene. getObjectByName(“cube-17”) to output only that single object):

Esto es genial para depurar código, y especialmente cuando nombras tus objetos, es muy útil para encontrar problemas con un objeto específico en tu escena. Por ejemplo, las propiedades de cube-17 se ven así (si ya conoces el nombre de antemano, también puedes usar console.log(scene.getObjectByName(“cube-17”) para mostrar solo ese objeto):

__webglActive: true
__webglInit: true
_listeners: Object
_modelViewMatrix: THREE.Matrix4
_normalMatrix: THREE.Matrix3
castShadow: true
children: Array[0]
eulerOrder: (...)
frustumCulled: true
geometry: THREE.BoxGeometryid: 8
material: THREE.MeshLambertMaterial
matrix: THREE.Matrix4
matrixAutoUpdate: true
matrixWorld: THREE.Matrix4
matrixWorld
NeedsUpdate: false
name: "cube-17"
parent: THREE.Scene
position: THREE.Vector3
quaternion: THREE.Quaternion
receiveShadow: false
renderDepth: null
rotation: THREE.Euler
rotationAutoUpdate: true
scale: THREE.Vector3
type: "Mesh"
up: THREE.Vector3
useQuaternion: (...)
userData: Object
uuid: "DCDC0FD2-6968-44FD-8009-20E9747B8A73"
visible: true

Until now, we’ve seen the following scene-related functionality:

  • THREE.Scene.Add: This adds an object to the scene

  • THREE.Scene.Remove: This removes an object from the scene

  • THREE.Scene.children: This gets a list of all the children in the scene

  • THREE.Scene.getObjectByName: This gets a specific object, by name, from the scene

These are the most important scene-related functions, and most often, you won’t need any more than this. There are, however, a couple of helper functions that could come in handy, and I’d like to show them based on the code that handles the cube rotation.

Estas son las funciones más importantes relacionadas con la escena, y en la mayoría de los casos, no necesitarás más. Sin embargo, existen un par de funciones auxiliares que podrían resultarte útiles, y me gustaría mostrarlas basándome en el código que gestiona la rotación del cubo.

As you saw in the previous chapter, we used a render loop to render the scene. Let’s look at that loop for this example:

Como viste en el capítulo anterior, utilizamos un bucle de renderizado para renderizar la escena. Veamos ese bucle para este ejemplo:

function render() {
stats.update();
scene.traverse(function(obj) {
if (obj instanceof THREE.Mesh && obj != plane ) {
obj.rotation.x+=controls.rotationSpeed;
obj.rotation.y+=controls.rotationSpeed;
obj.rotation.z+=controls.rotationSpeed;
}
});
requestAnimationFrame(render);
renderer.render(scene, camera);
}

Here, we see the THREE.Scene.traverse() function being used. We can pass a function to the traverse() function that will be called for each child of the scene. If a child itself has children, remember that a THREE.Scene object can contain a tree of objects. The traverse() function will also be called for all the children of that object. You traverse through the complete scene graph.

Aquí vemos cómo se utiliza la función THREE.Scene.traverse(). Podemos pasarle una función que se ejecutará para cada elemento hijo de la escena. Si un elemento hijo tiene a su vez otros elementos hijos, recordemos que un objeto THREE.Scene puede contener un árbol de objetos. La función traverse() también se ejecutará para todos los elementos hijos de ese objeto. De esta forma, se recorre todo el grafo de la escena.

We use the render() function to update the rotation for each of the cubes (note that we explicitly ignore the ground plane). We could also have done this by iterating ourselves over the children property array using a for loop since we’ve only added objects to THREE.Scene and haven’t created a nested structure.

Usamos la función render() para actualizar la rotación de cada uno de los cubos (nótese que ignoramos explícitamente el plano del suelo). También podríamos haberlo hecho iterando sobre el array de propiedades children usando un bucle for, ya que solo hemos añadido objetos a THREE.Scene y no hemos creado una estructura anidada.

Before we dive into the details of THREE.Mesh and THREE.Geometry, I’d like to show two interesting properties that you can set on the THREE.Scene object: fog and overrideMaterial.

Antes de adentrarnos en los detalles de THREE.Mesh y THREE.Geometry, me gustaría mostrar dos propiedades interesantes que se pueden configurar en el objeto THREE.Scene: fog y overrideMaterial.

Adding fog to the scene

The fog property lets you add a fog effect to the complete scene; the farther off an object is, the more it will be hidden from sight, as shown in the following screenshot:

La propiedad niebla permite añadir un efecto de niebla a toda la escena; cuanto más lejos esté un objeto, más se ocultará de la vista, como se muestra en la siguiente captura de pantalla:

Enabling fog is really easy in Three.js. Just add the following line of code after you’ve defined your scene:

Activar la niebla es muy fácil en Three.js. Simplemente añade la siguiente línea de código después de haber definido tu escena:

scene.fog=new THREE.Fog( 0xffffff, 0.015, 100 );

Here, we define a white fog (0xffffff). The preceding two properties can be used to tune how the mist appears. The 0.015 value sets the near property, and the 100 value sets the far property. With these properties, you can determine where the mist starts and how fast it gets denser. With the THREE.Fog object, the fog increases linearly. There is also a different way to set the mist for the scene; for this, use the following definition:

Aquí definimos una niebla blanca (0xffffff). Las dos propiedades anteriores se pueden usar para ajustar la apariencia de la niebla. El valor 0.015 establece la propiedad de proximidad y el valor 100 la de lejanía. Con estas propiedades, puede determinar dónde comienza la niebla y con qué rapidez aumenta su densidad. Con el objeto THREE.Fog, la niebla aumenta linealmente. También existe otra forma de configurar la niebla para la escena; para ello, utilice la siguiente definición:

scene.fog=new THREE.FogExp2( 0xffffff, 0.01 );

This time, we don’t specify near and far, but just the color (0xffffff) and the mist’s density (0.01). It’s best to experiment a bit with these properties to get the effect you want. Note that with THREE.FogExp2, the fog doesn’t increase linearly but grows exponentially denser with the distance.

Esta vez, no especificamos cerca ni lejos, sino solo el color (0xffffff) y la densidad de la niebla (0.01). Lo mejor es experimentar un poco con estas propiedades para obtener el efecto deseado. Ten en cuenta que con THREE.FogExp2, la niebla no aumenta linealmente, sino que su densidad crece exponencialmente con la distancia.

Using the overrideMaterial property

The last property we discuss for the scene is overrideMaterial. When you use this property, all the objects in the scene will use the material that is set to the overrideMaterial property and ignore the material that is set on the object itself.

La última propiedad que analizaremos para la escena es overrideMaterial. Al usar esta propiedad, todos los objetos de la escena usarán el material que se haya establecido en la propiedad overrideMaterial e ignorarán el material que tenga asignado el propio objeto.

Use it like this:

scene.overrideMaterial = new THREE.MeshLambertMaterial({color:
0xffffff});

Upon using the overrideMaterial property as shown in the preceding code, the scene will be rendered as shown in the following screenshot:

Al utilizar la propiedad overrideMaterial como se muestra en el código anterior, la escena se renderizará como se muestra en la siguiente captura de pantalla:

In the preceding figure, you can see that all the cubes are rendered using the same material and the same color. In this example, we used a THREE. MeshLambertMaterial object as the material. With this material type, we can create non-shiny-looking objects that respond to the lights that are present in the scene. In Chapter 4, Working with Three.js Materials, you’ll learn more about this material.

En la figura anterior, se puede observar que todos los cubos se renderizan con el mismo material y el mismo color. En este ejemplo, utilizamos un objeto THREE.MeshLambertMaterial como material. Con este tipo de material, podemos crear objetos sin brillo que reaccionan a las luces presentes en la escena. En el Capítulo 4, «Trabajando con materiales de Three.js», aprenderá más sobre este material.

In this section, we looked at the first of the core concepts of Three.js: THREE.Scene. The most important thing to remember about the scene is that it is basically a container for all the objects, lights, and cameras you want to use when rendering. The following table summarizes the most important functions and attributes of the THREE.Scene object:

En esta sección, analizamos el primero de los conceptos fundamentales de Three.js: THREE.Scene. Lo más importante que hay que recordar sobre la escena es que, básicamente, es un contenedor para todos los objetos, luces y cámaras que se desean utilizar durante el renderizado. La siguiente tabla resume las funciones y atributos más importantes del objeto THREE.Scene:

Function/Property add(object)Description childrenThis returns a list of all the objects that have been added to the scene, including the camera and lights. getObjectByName(name, recursive)When you create an object, you can give it a distinct name. The scene object has a function that you can use to directly return an object with a specific name. If you set the recursive argument to true, Three.js will also search through the complete tree of objects to find the object with the specified name. remove(object)If you have a reference to an object in the scene, you can also remove it from the scene using this function. traverse(function)The children property returns a list of all the children in the scene. With the traverse function, we can also access these children. With traverse, all the children are passed in to the supplied function one by one. fogThis property allows you to set the fog for the scene. The fog will render a haze that hides faraway objects. overrideMaterialWith this property, you can force all the objects in the scene to use the same material. This is used to add an object to the scene. You can also use this function, as we’ll see later on, to create groups of objects.

In the next section, we’ll take a closer look at the objects that you can add to the scene.

Geometries and meshes

In each of the examples until now, you’ve seen geometries and meshes being used. For instance, to add a sphere to the scene, we did the following:

En cada uno de los ejemplos hasta ahora, has visto el uso de geometrías y mallas. Por ejemplo, para agregar una esfera a la escena, hicimos lo siguiente:

var sphereGeometry = new THREE.SphereGeometry(4,20,20);
var sphereMaterial = new THREE.MeshBasicMaterial({color:
0x7777ff);
var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial);

We defined the shape of the object and its geometry (THREE.SphereGeometry), we defined what this object looks like (THREE.MeshBasicMaterial) and its material, and we combined these two in a mesh (THREE.Mesh) that can be added to a scene. In this section, we’ll take a closer look at what a geometry is and what a mesh is. We’ll start with the geometry.

Definimos la forma del objeto y su geometría (THREE.SphereGeometry), definimos su apariencia (THREE.MeshBasicMaterial) y su material, y combinamos ambos en una malla (THREE.Mesh) que se puede agregar a una escena. En esta sección, analizaremos con más detalle qué es una geometría y qué es una malla. Comenzaremos con la geometría.

The properties and functions of a geometry

Three.js comes with a large set of geometries out of the box that you can use in your 3D scene. Just add a material, create a mesh, and you’re pretty much done. The following screenshot, from example 04-geometries, shows a couple of the standard geometries available in Three.js:

Three.js incluye un amplio conjunto de geometrías predefinidas que puedes usar en tu escena 3D. Solo tienes que añadir un material, crear una malla y listo. La siguiente captura de pantalla, del ejemplo 04-geometries, muestra algunas de las geometrías estándar disponibles en Three.js:

In Chapter 5, Learning to Work with Geometries, and Chapter 6, Advanced Geometries and Binary Operations, we’ll explore all the basic and advanced geometries that Three.js has to offer. For now, we’ll look in greater detail at what a geometry actually is.

En el Capítulo 5, Aprender a trabajar con geometrías, y en el Capítulo 6, Geometrías avanzadas y operaciones binarias, exploraremos todas las geometrías básicas y avanzadas que ofrece Three.js. Por ahora, analizaremos con mayor detalle qué es una geometría.

A geometry in Three.js, and in most other 3D libraries, is basically a collection of points in a 3D space, also called vertices, and a number of faces connecting those points together. Take, for example, a cube:

En Three.js, y en la mayoría de las demás bibliotecas 3D, una geometría es básicamente una colección de puntos en un espacio 3D, también llamados vértices, y una serie de caras que conectan esos puntos entre sí. Tomemos, por ejemplo, un cubo:

  • A cube has eight corners. Each of these corners can be defined as an x, y, and z coordinate. So each cube has eight points in a 3D space. In Three.js, these points are called vertices, and a single one is called a vertex.

  • A cube has six sides, with a vertex at each corner. In Three.js, a face always consists of three vertices that make a triangle. So, in the case of a cube, each

side consists of two triangles to make the complete side.

When you use one of the geometries provided by Three.js, you don’t have to define all the vertices and faces yourself. For a cube, you only need to define the width, height, and depth. Three.js uses that information and creates a geometry with eight vertices at the correct position and the correct number of faces (12 in the case of a cube). Even though you’d normally use the geometries provided by Three.js or generate them automatically, you can still create geometries completely by hand using vertices and faces. This is shown in the following lines of code:

Cuando utilizas una de las geometrías proporcionadas por Three.js, no tienes que definir manualmente todos los vértices y caras. Para un cubo, solo necesitas definir el ancho, la altura y la profundidad. Three.js utiliza esta información y crea una geometría con ocho vértices en la posición correcta y el número adecuado de caras (12 en el caso de un cubo). Aunque normalmente usarías las geometrías proporcionadas por Three.js o las generarías automáticamente, también puedes crear geometrías completamente a mano utilizando vértices y caras. Esto se muestra en las siguientes líneas de código:

var vertices = [
new THREE.Vector3(1,3,1),
new THREE.Vector3(1,3,-1),
new THREE.Vector3(1,-1,1),
new THREE.Vector3(1,-1,-1),
new THREE.Vector3(-1,3,-1),
new THREE.Vector3(-1,3,1),
new THREE.Vector3(-1,-1,-1),
new THREE.Vector3(-1,-1,1)
];
var faces = [
new THREE.Face3(0,2,1),
new THREE.Face3(2,3,1),
new THREE.Face3(4,6,5),
new THREE.Face3(6,7,5),
new THREE.Face3(4,5,1),
new THREE.Face3(5,0,1),
new THREE.Face3(7,6,2),
new THREE.Face3(6,3,2),
new THREE.Face3(5,7,0),
new THREE.Face3(7,2,0),
new THREE.Face3(1,3,4),
new THREE.Face3(3,6,4),
];
var geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;
geom.computeFaceNormals();

This code shows how to create a simple cube. We define the points that make up this cube in the vertices array. These points are connected to create triangular faces and are stored in the faces array. For instance, new THREE.Face3(0,2,1) creates a triangular face using the points 0, 2, and 1 from the vertices array. Note that you have to take care of the sequence of the vertices used to create THREE.Face. The order in which they are defined determines whether Three.js thinks it is a front- facing face (a face facing the camera) or a back-facing face. If you create the faces, you should use a clockwise sequence for front-facing faces and a counterclockwise sequence if you want to create a back-facing face.

Este código muestra cómo crear un cubo simple. Definimos los puntos que componen este cubo en el array vertices. Estos puntos se conectan para crear caras triangulares y se almacenan en el array faces. Por ejemplo, new THREE.Face3(0,2,1) crea una cara triangular usando los puntos 0, 2 y 1 del array vertices. Ten en cuenta que debes cuidar la secuencia de los vértices utilizados para crear THREE.Face. El orden en que se definen determina si Three.js lo considera una cara frontal (una cara que mira a la cámara) o una cara posterior. Si creas las caras, debes usar una secuencia en sentido horario para las caras frontales y una secuencia en sentido antihorario si quieres crear una cara posterior.

In this example, we used a THREE.Face3 element to define the six sides of the cube, with two triangles for each face. In previous versions of Three.js, you could also use a quad instead of a triangle. A quad uses four vertices instead of three to define the face. Whether using quads or triangles is better is a heated debate raging in the 3D modeling world. Basically though, using quads is often preferred during modeling since they can be more easily enhanced and smoothed than triangles. For render and game engines though, working with triangles is often easier since every shape can be rendered very efficiently as a triangle.

En este ejemplo, usamos un elemento THREE.Face3 para definir las seis caras del cubo, con dos triángulos para cada cara. En versiones anteriores de Three.js, también se podía usar un cuadrilátero en lugar de un triángulo. Un cuadrilátero usa cuatro vértices en lugar de tres para definir la cara. El debate sobre si usar cuadriláteros o triángulos es mejor es muy intenso en el mundo del modelado 3D. En general, se suele preferir usar cuadriláteros durante el modelado, ya que se pueden mejorar y suavizar más fácilmente que los triángulos. Sin embargo, para los motores de renderizado y de juegos, trabajar con triángulos suele ser más sencillo, ya que cualquier forma se puede renderizar de forma muy eficiente como un triángulo.

Using these vertices and faces, we can now create a new instance of THREE.Geometry and assign the vertices to the vertices attribute and the faces to the faces attribute. The last step that we need to take is call computeFaceNormals() on the geometry we created. When we call this function, Three.js determines the normal vector for each of the faces. This is the information Three.js uses to determine how to color the faces based on the various lights in the scene.

Utilizando estos vértices y caras, podemos crear una nueva instancia de THREE.Geometry y asignar los vértices al atributo vertices y las caras al atributo faces. El último paso es llamar a computeFaceNormals() sobre la geometría creada. Al llamar a esta función, Three.js determina el vector normal de cada cara. Esta información es la que Three.js utiliza para determinar el color de las caras según la iluminación de la escena.

With this geometry, we can now create a mesh just as we saw earlier. I’ve created an example that you can use to play around with the position of the vertices, and which also shows the individual faces. In example 05-custom-geometry, you can change the position of all the vertices of a cube and see how the faces react. This is shown in the following screenshot (should the control GUI be in the way, you can hide it by pressing H):

Con esta geometría, ahora podemos crear una malla como vimos anteriormente. He creado un ejemplo que puedes usar para experimentar con la posición de los vértices y que también muestra las caras individuales. En el ejemplo 05-custom-geometry, puedes cambiar la posición de todos los vértices de un cubo y ver cómo reaccionan las caras. Esto se muestra en la siguiente captura de pantalla (si la interfaz gráfica de control está presente, puedes ocultarla pulsando H):

This example, which uses the same setup as all our other examples, has a render loop. Whenever you change one of the properties in the drop-down control box, the cube is rendered based on the changed position of one of the vertices. This isn’t something that works out of the box. For performance reasons, Three.js assumes that the geometry of a mesh won’t change during its lifetime. For most geometries and use cases, this is a very valid assumption. To get our example to work, however, we need to make sure the following is added to the code in the render loop:

Este ejemplo, que utiliza la misma configuración que todos nuestros demás ejemplos, tiene un bucle de renderizado. Cada vez que se cambia una de las propiedades en el cuadro de control desplegable, el cubo se renderiza en función de la posición modificada de uno de los vértices. Esto no funciona de forma predeterminada. Por motivos de rendimiento, Three.js asume que la geometría de una malla no cambiará durante su vida útil. Para la mayoría de las geometrías y casos de uso, esta es una suposición muy válida. Sin embargo, para que nuestro ejemplo funcione, debemos asegurarnos de que se agregue lo siguiente al código en el bucle de renderizado:

mesh.children.forEach(function(e) {
e.geometry.vertices=vertices;
e.geometry.verticesNeedUpdate=true;
e.geometry.computeFaceNormals();
});

In the first line, we point the vertices of the mesh you see on screen to an array of updated vertices. We don’t need to reconfigure the faces since they are still connected to the same points as they were before. After we’ve set the updated vertices, we need to tell the geometry that the vertices need to be updated. We do this by setting the verticesNeedUpdate property of the geometry to true. Finally, we do a recalculation of the faces to update the complete model using the computeFaceNormals function.

En la primera línea, conectamos los vértices de la malla que se ve en pantalla a una matriz de vértices actualizados. No es necesario reconfigurar las caras, ya que siguen conectadas a los mismos puntos que antes. Una vez establecidos los vértices actualizados, debemos indicarle a la geometría que estos vértices deben actualizarse. Para ello, establecemos la propiedad verticesNeedUpdate de la geometría en true. Finalmente, recalculamos las caras para actualizar el modelo completo mediante la función computeFaceNormals.

The last geometry functionality we’ll look at is the clone() function. We mentioned that the geometry defines the form and shape of an object, and combined with a material, we create an object that can be added to the scene to be rendered by Three. js. With the clone() function, as the name implies, we can make a copy of the geometry, and for instance, use it to create a different mesh with a different material. In the same example, 05-custom-geometry, you can see a clone button at the top of the control GUI, as can be seen in the following screenshot:

La última funcionalidad de geometría que veremos es la función clone(). Ya mencionamos que la geometría define la forma y el contorno de un objeto, y al combinarla con un material, creamos un objeto que se puede agregar a la escena para que Three.js lo renderice. Con la función clone(), como su nombre lo indica, podemos hacer una copia de la geometría y, por ejemplo, usarla para crear una malla diferente con un material distinto. En el mismo ejemplo, 05-custom-geometry, se puede ver un botón de clonación en la parte superior de la interfaz gráfica de control, como se muestra en la siguiente captura de pantalla:

If you click on this button, a clone (a copy) will be made of the geometry as it currently is, a new object is created with a different material, and it is added to the scene. The code for this is rather simple but is made a bit more complex because of the materials I used. Let’s take a step back and first look at how the green material for the cube was created, as shown in the following code:

Si haces clic en este botón, se creará un clon (una copia) de la geometría actual, se generará un nuevo objeto con un material diferente y se añadirá a la escena. El código es bastante sencillo, pero se vuelve un poco más complejo debido a los materiales que utilicé. Retrocedamos un poco y veamos primero cómo se creó el material verde para el cubo, como se muestra en el siguiente código:

var materials = [
new THREE.MeshLambertMaterial( { opacity:0.6, color: 0x44ff44,
transparent:true } ),
new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true
} )
];

As you can see, I didn’t use a single material, but I used an array of two materials. The reason is that besides showing a transparent green cube, I also wanted to show you the wireframe since that shows up very clearly where the vertices and faces are located.

Como pueden ver, no utilicé un solo material, sino una combinación de dos. La razón es que, además de mostrar un cubo verde transparente, también quería mostrarles la estructura alámbrica, ya que así se aprecian claramente la ubicación de los vértices y las caras.

Three.js, of course, supports using multiple materials when creating a mesh. You can use the SceneUtils.createMultiMaterialObject function for this, as shown in the following code:

Three.js, por supuesto, admite el uso de múltiples materiales al crear una malla. Para ello, puede utilizar la función SceneUtils.createMultiMaterialObject, como se muestra en el siguiente código:

var mesh = THREE.SceneUtils.createMultiMaterialObject( geom,
materials);

What Three.js does in this function is that it doesn’t create one THREE.Mesh object, but it creates one for each material you specified and puts these meshes in a group (a THREE.Object3D object). This group can be used in the same manner as you’ve used the scene object. You can add meshes, get objects by name, and so on. For instance, to make sure all the children of the group cast shadows, you do the following:

Lo que hace Three.js en esta función es que no crea un único objeto THREE.Mesh, sino uno por cada material especificado, y agrupa estas mallas (un objeto THREE.Object3D). Este grupo se puede usar de la misma manera que el objeto de escena. Se pueden añadir mallas, obtener objetos por nombre, etc. Por ejemplo, para asegurar que todos los elementos secundarios del grupo proyecten sombras, se hace lo siguiente:

mesh.children.forEach(function(e) {e.castShadow=true});

Now, let’s get back to the clone() function we were discussing:

Ahora, volvamos a la función clone() que estábamos comentando:

this.clone = function() {
var clonedGeom = mesh.children[0].geometry.clone();
var materials = [
new THREE.MeshLambertMaterial( { opacity:0.6, color: 0xff44ff,
transparent:true } ),
new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: true
} )
];
var mesh2 = THREE.SceneUtils.createMultiMaterialObject
(clonedGeom, materials);
mesh2.children.forEach(function(e) {e.castShadow=true});
mesh2.translateX(5);
mesh2.translateZ(5);
mesh2.name="clone";
scene.remove(scene.getObjectByName("clone"));
scene.add(mesh2);
}

This piece of JavaScript is called when the clone button is clicked on. Here, we clone the geometry of the first child of our cube. Remember, the mesh variable contains two children; it contains two meshes, one for each material we specified. Based on this cloned geometry, we create a new mesh, aptly named mesh2. We move this new mesh using translate functions (more on this in Chapter 5, Learning to Work with Geometries), remove the previous clone (if present), and add the clone to the scene.

Este fragmento de JavaScript se ejecuta al hacer clic en el botón de clonación. Aquí, clonamos la geometría del primer hijo de nuestro cubo. Recuerda que la variable mesh contiene dos hijos; contiene dos mallas, una para cada material que especificamos. A partir de esta geometría clonada, creamos una nueva malla, llamada mesh2. Movemos esta nueva malla usando funciones de traslación (más información en el Capítulo 5, Aprender a trabajar con geometrías), eliminamos el clon anterior (si existe) y agregamos el clon a la escena.

In the previous section, we used createMultiMaterialObject from the THREE.SceneUtils object to add a wireframe to the geometry we created. Three.js also provides an alternative way of adding a wireframe using THREE.WireFrameHelper. To use this helper, first instantiate the helper like this:

En la sección anterior, usamos createMultiMaterialObject del objeto THREE.SceneUtils para agregar una estructura alámbrica a la geometría que creamos. Three.js también proporciona una forma alternativa de agregar una estructura alámbrica usando THREE.WireFrameHelper. Para usar esta función auxiliar, primero instancie la función auxiliar de esta manera:

var helper = new THREE.WireframeHelper(mesh, 0x000000);

You provide the mesh you want to show the wireframe for and the color of the wireframe. Three.js will now create a helper object that you can add to the scene, scene.add(helper). Since this helper internally is just a THREE.Line object, you can style how the wireframe appears. For instance, to set the width of the wireframe lines, use helper.material. linewidth = 2;.

Proporcionas la malla para la que quieres mostrar el modelo alámbrico y el color del mismo. Three.js creará un objeto auxiliar que puedes añadir a la escena con scene.add(helper). Como este auxiliar es internamente un objeto THREE.Line, puedes personalizar el aspecto del modelo alámbrico. Por ejemplo, para establecer el grosor de las líneas del modelo alámbrico, usa helper.material. linewidth = 2;.

That’s enough on geometries for now.

Functions and attributes for meshes

We’ve already learned that to create a mesh, we need a geometry and one or more materials. Once we have a mesh, we add it to the scene and it’s rendered. There are a couple of properties that you can use to change where and how this mesh appears on the scene. In this first example, we’ll look at the following set of properties and functions:

Ya hemos aprendido que para crear una malla, necesitamos una geometría y uno o más materiales. Una vez que tenemos la malla, la añadimos a la escena y se renderiza. Hay un par de propiedades que puedes usar para cambiar dónde y cómo aparece esta malla en la escena. En este primer ejemplo, veremos el siguiente conjunto de propiedades y funciones:

Function/PropertyDescription positionThis determines the position of this object relative to the position of its parent. Most often, the parent of an object is a THREE.Scene object or a THREE.Object3D object. rotationWith this property, you can set the rotation of an object around any of its axes. Three.js also provides specific functions for rotations around an axis: rotateX(), rotateY(), and rotateZ(). scaleThis property allows you to scale the object around its x, y, and z axes. translateX(amount)This property moves the object the specified amount over the x axis. [ 48 ]Chapter 2 Function/PropertyDescription translateY(amount)This property moves the object the specified amount over the y axis. translateZ(amount)This property moves the object the specified amount over the z axis. For the translate functions, you could also use the translateOnAxis(axis, distance) function, which allows you to translate the mesh a distance along a specific axis. visible If you set this property to false, THREE.Mesh won’t be rendered by Three.js.

As always, we have an example ready for you that will allow you to play around with these properties. If you open up 06-mesh-properties.html in your browser, you get a drop-down menu where you can alter all these properties and directly see the result, as shown in the following screenshot:

Como siempre, tenemos un ejemplo preparado para que puedas experimentar con estas propiedades. Si abres 06-mesh-properties.html en tu navegador, verás un menú desplegable donde podrás modificar todas estas propiedades y ver directamente el resultado, como se muestra en la siguiente captura de pantalla:

Let me walk you through them, and I’ll start with the position property. We’ve already seen this property a couple of times, so let’s quickly address this. With this property, you set the x, y, and z coordinates of the object. This position is relative to its parent object, which is normally the scene you add the object to, but could also be a THREE. Object3D object or another THREE.Mesh object. We’ll get back to this in Chapter 5, Learning to Work with Geometries, when we look at grouping objects. We can set an object’s position property in three different ways. We can set each coordinate directly:

Permítanme explicarles, comenzando con la propiedad position. Ya hemos visto esta propiedad un par de veces, así que vamos a abordarla rápidamente. Con esta propiedad, se establecen las coordenadas x, y y z del objeto. Esta posición es relativa a su objeto padre, que normalmente es la escena a la que se agrega el objeto, pero también podría ser un objeto THREE.Object3D u otro objeto THREE.Mesh. Volveremos a esto en el Capítulo 5, Aprendiendo a trabajar con geometrías, cuando veamos cómo agrupar objetos. Podemos establecer la propiedad position de un objeto de tres maneras diferentes. Podemos establecer cada coordenada directamente:

cube.position.x=10;
cube.position.y=3;
cube.position.z=1;

However, we can also set all of them at once, as follows:

cube.position.set(10,3,1);

There is also a third option. The position property is a THREE.Vector3 object. That means, we can also do the following to set this object:

cube.postion=new THREE.Vector3(10,3,1)

I want to make a quick sidestep before looking at the other properties of this mesh. I mentioned that this position is set relative to the position of its parent. In the previous section on THREE.Geometry, we used THREE.SceneUtils. createMultiMaterialObject to create a multi-material object. I explained that this doesn’t really return a single mesh but a group that contains a mesh based on the same geometry for each material; in our case, it’s a group that contains two meshes. If we change the position of one of these meshes that is created, you can clearly see that it really is two distinct THREE.Mesh objects. However, if we now move the group around, the offset will remain the same, as shown in the following screenshot. In Chapter 5, Learning to Work with Geometries, we look deeper into parent-child relations and how grouping affects transformation, such as scaling, rotation, and translation.

Quiero hacer un breve inciso antes de examinar las demás propiedades de esta malla. Mencioné que esta posición se establece en relación con la posición de su padre. En la sección anterior sobre THREE.Geometry, usamos THREE.SceneUtils.createMultiMaterialObject para crear un objeto multimaterial. Expliqué que esto no devuelve una sola malla, sino un grupo que contiene una malla basada en la misma geometría para cada material; en nuestro caso, es un grupo que contiene dos mallas. Si cambiamos la posición de una de estas mallas creadas, se puede ver claramente que en realidad son dos objetos THREE.Mesh distintos. Sin embargo, si ahora movemos el grupo, el desplazamiento permanecerá igual, como se muestra en la siguiente captura de pantalla. En el Capítulo 5, Aprendiendo a trabajar con geometrías, profundizamos en las relaciones padre-hijo y cómo el agrupamiento afecta la transformación, como el escalado, la rotación y la traslación.

OK, next on the list is the rotation property. You’ve already seen this property being used a couple of times in this chapter and the previous chapter. With this property, you set the rotation of the object around one of its axes. You can set this value in the same manner as we did the position. A complete rotation, as you might remember from math class, is 2 x π. You can configure this in Three.js in a couple of different ways:

Bien, el siguiente punto de la lista es la propiedad de rotación. Ya la has visto usarse un par de veces en este capítulo y en el anterior. Con esta propiedad, se establece la rotación del objeto alrededor de uno de sus ejes. Puedes establecer este valor de la misma manera que lo hicimos con la posición. Una rotación completa, como recordarás de la clase de matemáticas, es 2 x π. Puedes configurarla en Three.js de varias maneras:

cube.rotation.x = 0.5*Math.PI;
cube.rotation.set(0.5*Math.PI, 0, 0);
cube.rotation = new THREE.Vector3(0.5*Math.PI,0,0);

If you want to use degrees (from 0 to 360) instead, we’ll have to convert those to radians. This can be easily done like this:

Var degrees = 45;
Var inRadians = degrees * (Math.PI / 180);

You can play around with this property using the 06-mesh-properties.html example.

The next property on our list is one we haven’t talked about: scale. The name pretty much sums up what you can do with this property. You can scale the object along a specific axis. If you set the scale to values smaller than one, the object will shrink, as shown in the following screenshot:

99999

When you use values larger than one, the object will become larger, as shown in the following screenshot:

The next part of the mesh that we’ll look at in this chapter is the translate functionality. With translate, you can also change the position of an object, but instead of defining the absolute position where you want the object to be, you define where the object should move to, relative to its current position. For instance, we have a sphere that is added to a scene, and its position has been set to (1,2,3). Next, we translate the object along its x axis: translateX(4). Its position will now be (5,2,3). If we want to restore the object to its original position, we do this: translateX(-4). In the 06-mesh- properties.html example, there is a menu tab called translate. From there, you can experiment with this functionality. Just set the translate values for x, y, and z and hit the translate button. You’ll see the object being moved to a new position based on these three values.

The last property you can use from the menu in the top-right corner is the visible property. If you click on the visible menu item, you’ll see that the cube becomes invisible, as follows:

When you click on it another time, the cube becomes visible again. For more information on meshes, geometries, and what you can do with these objects, look at Chapter 5, Learning to Work with Geometries, and Chapter 7, Particles, Sprites, and the Point Cloud.

Different cameras for different uses

There are two different camera types in Three.js: the orthographic camera and the perspective camera. In Chapter 3, Working with the Different Light Sources Available in Thrree.js, we’ll have a much more detailed look at how to work with these cameras, so in this chapter, I’ll stick to the basics. The best way to explain the differences between these cameras is by looking at a couple of examples.

Orthographic camera versus perspective camera

In the examples for this chapter, you can find a demo called 07-both-cameras.html. When you open this example, you’ll see something like this:

This is called a perspective view and is the most natural view. As you can see from this figure, the farther away the cubes are from the camera, the smaller they are rendered.

If we change the camera to the other type supported by Three.js, the orthographic camera, you’ll see the following view of the same scene:

With the orthographic camera, all the cubes are rendered the same size; the distance between an object and the camera doesn’t matter. This is often used in 2D games such as SimCity 4 and old versions of Civilization.

In our examples, we’ll use the perspective camera the most since it best resembles the real world. Switching cameras is really very easy. The following piece of code is called whenever you hit the switch camera button on the 07-both-cameras example:

this.switchCamera = function() {
if (camera instanceof THREE.PerspectiveCamera) {
camera = new THREE.OrthographicCamera( window.innerWidth / -
16, window.innerWidth / 16, window.innerHeight / 16,
window.innerHeight / - 16, -200, 500 );
camera.position.x = 120;
camera.position.y = 60;
camera.position.z = 180;
camera.lookAt(scene.position);
this.perspective = "Orthographic";
} else {
camera = new THREE.PerspectiveCamera(45, window.innerWidth /
window.innerHeight, 0.1, 1000);
camera.position.x = 120;
camera.position.y = 60;
camera.position.z = 180;
camera.lookAt(scene.position);
this.perspective = "Perspective";
}
};

In this table, you can see that there is a difference in the way we create the camera. Let’s look at THREE.PerspectiveCamera first. This camera takes the following arguments:

Argument fov Description FOV stands for Field Of View. This is the part of the scene that can be seen from the position of the camera. Humans, for instance, have an almost 180-degree FOV, while some birds might even have a complete 360-degree FOV. But since a normal computer screen doesn’t completely fill our vision, normally a smaller value is chosen. Most often, for games, a FOV between 60 and 90 degrees is chosen. Good default: 50 [ 57 ]Basic Components That Make Up a Three.js Scene Argument aspect Description This is the aspect ratio between the horizontal and vertical sizes of the area where we’re to render the output. In our case, since we use the entire window, we just use that ratio. The aspect ratio determines the difference between the horizontal FOV and the vertical FOV, as you can see in the following image. Good default: window.innerWidth / window.innerHeight near The near property defines from how close to the camera Three.js should render the scene. Normally, we set this to a very small value to directly render everything from the position of the camera. Good default: 0.1 far The far property defines how far the camera can see from the position of the camera. If we set this too low, a part of our scene might not be rendered, and if we set it too high, in some cases, it might affect the rendering performance. Good default: 1000 zoom The zoom property allows you to zoom in and out of the scene. When you use a number lower than 1, you zoom out of the scene, and if you use a number higher than 1, you zoom in. Note that if you specify a negative value, the scene will be rendered upside down. Good default value: 1

The following image gives a good overview of how these properties work together to determine what you see:

The fov property of the camera determines the horizontal FOV. Based on the aspect property, the vertical FOV is determined. The near property is used to determine the position of the near plane, and the far property determines the position of the far plane. The area between the near plane and the far plane will be rendered.

To configure the orthographic camera, we need to use other properties. The orthographic projection isn’t interested either in the aspect ratio to use or with what FOV we look at the scene since all the objects are rendered at the same size. What you do when you define an orthographic camera is define the cuboid area that needs to be rendered. The properties for the orthographic camera reflect this, as follows:

Argument leftDescription rightThe right property works in a way similar to the left property, but this time, to the other side of the screen. Anything farther to the right won’t be rendered. topThis is the top position to be rendered. bottomThis is the bottom position to be rendered. This is described in the Three.js documentation as Camera frustum left plane. You should see this as what is the left-hand border of what will be rendered. If you set this value to -100, you won’t see any objects that are farther to the left-hand side. [ 59 ]Basic Components That Make Up a Three.js Scene Argument nearDescription farTo this point, based on the position of the camera, the scene will be rendered. zoomThis allows you to zoom in and out of the scene. When you use a number lower than 1, you’ll zoom out of the scene; if you use a number higher than 1, you’ll zoom in. Note that if you specify a negative value, the scene will be rendered upside down. The default value is 1. From this point, based on the position of the camera, the scene will be rendered.

All these properties can be summarized in the following figure:

Looking at specific points

Until now, you’ve seen how to create a camera and what the various arguments mean. In the previous chapter, you also saw that you need to position your camera somewhere in the scene, and that the view from that camera is rendered. Normally, the camera is pointed to the center of the scene: position (0,0,0). We can, however, easily change what the camera is looking at, as follows:

camera.lookAt(new THREE.Vector3(x,y,z));

I’ve added an example where the camera moves, and the point it is looking at is marked with a red dot, as follows:

If you open the 08-cameras-lookat example, you’ll see the scene moving from left to right. The scene isn’t really moving. The camera is looking at different points (see the red dot in the center), which gives the effect that the scene is moving from left to right. In this example, you can also switch cameras to the orthographic one. There, you see that changing the point the camera looks at has pretty much the same effect as with THREE.PerspectiveCamera. The interesting part to notice, though, is that with THREE.OrthographicCamera, you can clearly see that the sizes of all the cubes stay the same regardless of where the camera is looking.

When you use the lookAt function, you point the camera at a specific position. You can also use this to make the camera follow an object around the scene. Since every THREE.Mesh object has a position that is a THREE.Vector3 object, you can use the lookAt function to point to a specific mesh in the scene. All you need to do is this: camera. lookAt(mesh.position). If you call this in the render loop, you’ll make the camera follow an object as it moves through the scene.

Summary

We discussed a lot of items in this second introduction chapter. We showed all the functions and properties of THREE.Scene and explained how you can use these properties to configure your main scene. We also showed you how you can create geometries. You can either create them from scratch using a THREE.Geometry object or use any of the built-in geometries Three.js provides. Finally, we showed you how you can configure the two cameras Three.js provides. THREE.PerspectiveCamera renders a scene using a real-world perspective, and THREE.OrthographicCamera provides a fake 3D effect also often seen in games. We’ve also introduced how geometries work in Three.js. You can now easily create your own geometries.

In the next chapter, we’ll look at the various light sources that are available in Three. js. You’ll learn how the various light sources behave, how to create and configure them, and how they affect specific materials.