Chidume Nnamdi I'm a software engineer with 6+ years of experience. I've worked with different stacks ranging from WAMP, to MERN, to MEAN. My language of choice is JavaScript; frameworks are Angular and Nodejs.

Three.js: Geometries and materials

7 min read 2102

Three.js: Creating Geometries and Materials

The gaming industry is one of the most successful industries. In 2020 alone, the gaming industry was forecast to generate $159 billion.

Among the millions of games produced each year are some extraordinary web-based games. Browsers are becoming more sophisticated and powerful every day, making it more and more possible to create stunningly realistic 3D and 2D games for the web browser.

In this tutorial, we’ll demonstrate how to create geometries and materials for styling geometries in Three.js.

What is Three.js?

Three.js is one of the powerful game libraries for creating web-based games. It is a cross-browser JavaScript library and API designed to help you build and display 3D animations in the browser using WebGL — anything from simple 3D patterns to photorealistic, real-time scenes.

Three.js enables you to apply textures and materials to your objects. It also provides various light sources to illuminate your scene, advanced postprocessing effects, custom shaders, etc. You can load objects from 3D modeling software to use in your game.

For a deeper dive to help you get started, check out this beginner’s guide to Three.js for game developers.

Installing Three.js

Three.js is very easy to start with. First, get the minified Three.js file from https://mrdoob.github.com/three.js/build/three.min.js. Then, add it to the src attribute in the script tag:

<script src="https://mrdoob.github.com/three.js/build/three.min.js"></script>

With this, Three.js is initialized and ready to go.

Geometries in Three.js

Geometries are used to create and define shapes in Three.js. A geometry is an instance of the Three.Geometry class.

A shape is defined by faces and vertices. A vertex defines the position of points in space. A face represents the surface of a shape.

We made a custom demo for .
No really. Click here to check it out.

For example, a cube has six vertices (edges) and six faces. To draw a cube on a grid, we have to first map out the position of the six vertices and then connect them with a line. This creates the surfaces of the cube and defines the shape/geometry. You can create all kinds of other shapes — polygons, cylinders, pyramids, etc. — with this same method.

A face in Three.js is an instance of the Three.Face3 class and a vertex/surface is an instance of the Three.Vector3 class. We can create geometries with these classes. Three.js has some built-in primitive shapes, including a cube, sphere, polyhedra, torus, and torus knot.

CubeGeometry

To create a Cube in Three.js, use Three.CubeGeometry.

>var cubeGeometry = new THREE.CubeGeometry(20, 20, 20);

The first param is the width of the cube. The second and third params are the height and depth of the cube, respectively. Here, we gave them the same value: 20.

The result should look like this:

Cube Wireframe in Three.js

CubeGeometry has three other arguments:

>var cubeGeometry = new THREE.CubeGeometry(20, 20, 20, 2, 2, 2);

The segments of the cube are width, height, and depth. These segments divide the surfaces of the cube into smaller sides.

The above sets the width, height, and depth segments to 2, so they will be split into two sides.

Three.js Geometry Split Into Two Sides

A value of 3 will split the surface into three smaller sides.

>var cubeGeometry = new THREE.CubeGeometry(20, 20, 20, 3, 3, 3);

If you don’t specify the arguments, they have a default value of 1, so the surface has one side.

SphereGeometry

In Three.js, Three.SphereGeometry creates a sphere.

>var sphereGeometry = new Three.SphereGeometry(20)

The above will create a sphere with a radius of 20.

Three.js: Sphere With Radius Set to 20

SphereGeometry has two more args:

>var sphereGeometry = new Three.SphereGeometry(20, 8, 6)

This is the number of horizontal and vertical segments into which the sphere should be divided. The 8 param represents the horizontal segment division. The sphere will be divided into eight segments and its vertical axis into five segments.

CylinderGeometry

To create a cylinder in Three.js, use the Three.CylinderGeometry.

>var cylinderGeometry = new THREE.CylinderGeometry(15, 15, 30)

The first arg is the radius of the cylinder’s top; the second is the radius of the bottom. The third argument represents the height of the cylinder.

Three.js: Cylinder

We can set the number of edges connecting the top and bottom faces down the curved surface. This is called the radiusSegments, and it goes in as the fourth arg. The default value is 8.

>var cylinderGeometry = new THREE.CylinderGeometry(15, 15, 30, 9)

This will divide the top and down faces into nine segments:

Three.js: Cylinder Shaped Using radiusSegments

We can also set the number of rings of faces around the curved surface. This is called heightSegments. It goes as the fifth argument with a default value of 1.

>var cylinderGeometry = new THREE.CylinderGeometry(15, 15, 30, 9, 2)

This will divide each face of the curved surface into two segments:

Three.js: Cylinder Sized Using heightSegments

You can determine whether the ends of the cylinder are open or closed. It’s a boolean: true makes it open while false makes it closed. This goes in as the sixth arg. The default value is false.

>var cylinderGeometry = new THREE.CylinderGeometry(15, 15, 30, 9, 2, true)

This will render a cylinder with open ends.

Open-Ended Cylinder in Three.js

TorusGeometry

TorusGeometry generates a tubelike shape. The Three.TorusGeometry class is what we use to generate the shape.

>var torusGeo = new THREE.TorusGeometry(10, 3, 16, 100)

var meshBasicMaterial = new THREE.MeshBasicMaterial({
    color: 0x0095DD,
    wireframe: true,
    wireframeLinewidth: 2
});

var torusMesh = new THREE.Mesh(torusGeo, meshBasicMaterial);

scene.add(torusMesh)

The above will generate a torus shape:

Torus Shape in Three.js

new THREE.TorusGeometry(10, 3, 16, 100)

The first argument sets the radius of the torus from the center of the torus to the center of the tube. Its default value is 1. The second is the radius of the tube, the default value of which is 0.4.

The third arg represents the radial segments, which are set to 8 by default. The fourth sets the tubular segments to 6 by default.

We have seen basic 3D geometrics. We can also create and render 2D geometry in Threejs.

2D geometry in Three.js

In addition to 3D geometrics, you can create engaging 2D shapes in Three.js, such as planes, circles, and rings.

PlaneGeometry

To create a plane in Three.js, we’ll use Three.PlaneGeomerty.

>var planeGeo = new THREE.PlaneGeometry(20, 20)

The first parameter is the width of the plane. The second represents the height.

The above will create a 2D plane with 20 units wide and high.

Three.js: PlaneGeometry

PlaneGeometry‘s third and fourth arguments specify the number of segments the width and height of the plane, respectively, can have.

>var planeGeo = new THREE.PlaneGeometry(20, 20, 3, 3)

This will divide the plane into three rows and three columns.

Three.js: PlaneGeometry

CircleGeometry

To create a circle in Three.js, you can use the THREE.CircleGeometry class.

>var circleGeo = new THREE.CircleGeometry(20)

The above creates a circle shape with a radius of 20 units.

Three.js: CircleGeometry

As you can see, the circle is subdivided into eight sides. A second arg to the THREE.CircleGeometry constructor allows us to set the number of sides for the circle to be divided into. The default value is 8.

>var circleGeo = new THREE.CircleGeometry(20, 10)

The above creates a circle divided into 10 parts.

Three.js: CircleGeometry

RingGeometry

RingGeometry creates a 2D ring shape with a hole in the middle. The THREE.RingGeometry constructor creates the ring shape.

>var ringGeo = new THREE.RingGeometry(20, 20)

The command above creates a ring with an inner and outer radius of 20 units each.

Three.js: RingGeometry

We can set radial segments and ring segments in the ring’s shape.

>var ringGeo = new THREE.RingGeometry(20,
    20, 9, 10)

The third param is the number of radial segments the ring will be divided into. The fourth sets the number of ring segments into which the ring will be divided.

Rendering text in Three.js

Just as we created 3D and 2D geometrics, we can also render text in Three.js. Font .js files from Three.js must be included in the page before Three.js can render text.

For example, the code below adds the Helvetica font to the page:

<script src="https://raw.github.com/mrdoob/three.js/master/examples/fonts/helvetiker_bold.typeface.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/fonts/helvetiker_regular.typeface.js"></script>

To create and render text in Three.js, we’ll use THREE.TextGeometry.

>var myNameGeometry = new THREE.TextGeometry("Nnamdi Chidume", {
    size: 30,
    height: 20
    font: "Tahoma",
});

The first param is the text we want to render. Here, I set my name: “Nnamdi Chidume.”

The second param is an object with options we set on our text. Here, we set the size and height of the text to be 30 and 20, respectively. We also set the rendering font to be Tahoma.

There are several additional options we can set, including:

  • weight, which sets the font weight
  • style, which determines how the text will be styled — normal, bold, or italic
  • bevelEnabled, which determines whether the text has blunt or sharp edges; its value can be true or false

Materials in Three.js

Materials manage the texture and color of objects in Three.js. A material covers an object, the colors, or textures on a surface.

To use an analogy, materials are like the clothes we wear. Whether you wake up and choose to put on a polo shirt, jeans, a suit, skirt, blouse, traditional garb, etc., the point is to add some pizazz to your normal appearance. Materials are like snazzy clothes for your objects in Three.js.

Three.js provides a plethora of materials, including:

  • MeshBasicMaterial
  • MeshPhongMaterial
  • MeshLambertMaterial
  • MeshNormalMaterial
  • MeshDepthMaterial
  • MeshFaceMaterial

The above are all child classes of the MeshMaterial.

MeshBasicMaterial

MeshBasicMaterial is used to display a solid color or a wireframe.

>var basicMaterial = new THREE.MeshBasicMaterial({
    color: 0x0095DD
});

The above displays a solid color of blue.

>var meshBasicMaterial = new THREE.MeshBasicMaterial({
    color: 0x0095DD,
    wireframe: true,
    wireframeLinewidth: 2
});

This displays a wireframe with a line width of 2.

Sometimes it’s hard to distinguish between two adjacent, unlit surfaces of the same color. For example, here’s a sphere with a solid display:

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)
var basicMaterial = new THREE.MeshBasicMaterial({
    color: 0x0095DD
});

var sphMesh = new THREE.Mesh(sphGeo, meshBasicMaterial);

It would be difficult to see the solid appearance of the sphere; although it appears as 2D, it should be 3D.

Basic materials are not affected by lighting.

MeshPhongMaterial

The Phong material looks glossier and shinier than the basic material. PhongMaterial is affected by light in the scene. Without lights, the Phong material laced objects would appear black.

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)
var phongMaterial = new THREE.MeshPhongMaterial({
    color: 0x0095DD
});

Nothing will be shown, everywhere will be black. This is because there is no light in the scene.

Three.js: MeshLambertMaterial

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)

var phongMaterial = new THREE.MeshPhongMaterial({
    color: 0x0095DD
});
var sphMesh = new THREE.Mesh(sphGeo, phongMaterial);

var light = new THREE.PointLight(0xFFFFFF);
light.position.set(-10, 15, 50);
scene.add(light);

Here, we added light to the scene and pointed it toward the sphere object. The sphere with Phong material will be visible.

Three.js: MeshPhongMaterial

MeshLambertMaterial

Lambert material is similar to Phong material, but it’s not as glossy. Objects with Lambert material appear black if not under lighting.

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)

var lambertMaterial = new THREE.MeshLambertMaterial({
    color: 0x0095DD
});

var sphMesh = new THREE.Mesh(sphGeo, lambertMaterial);

var light = new THREE.PointLight(0xFFFFFF);
light.position.set(-10, 15, 50);
scene.add(light);

The sphere with Lambert material will appear but less shiny than the Phong material we saw in the last section.

Three.js: MeshLambertMaterial

MeshNormalMaterial

This material is great for distinguishing surfaces in objects or objects’ shapes — especially for objects with solid-colored, unlit surfaces that are difficult to tell apart.

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)
var basicMaterial = new THREE.MeshBasicMaterial({
    color: 0x0095DD
});

var sphMesh = new THREE.Mesh(sphGeo, meshBasicMaterial);

It will be difficult to see the shape of the sphere surface. If we change the material to normal material, the surface will be distinguishable.

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)
var basicMaterial = new THREE.MeshNormalMaterial({
    color: 0x0095DD
});

var sphMesh = new THREE.Mesh(sphGeo, meshBasicMaterial);

Three.js: MeshNormalMaterial

MeshNormalMaterial uses the magnitude of the x/y/z values of the faces’ normal vectors to calculate and set the red/green/blue values of the colors displayed.

The variations of coloring done by this Normal material enables us to see the shape of an unlit, same-colored object.

MeshDepthMaterial

MeshDepthMaterial renders the object in shades of grey. Its brightness is dependent on its distance from the camera.

>var sphGeo = new THREE.SphereGeometry(20, 8, 6)
var depthMaterial = new THREE.MeshDepthMaterial();

var sphMesh = new THREE.Mesh(sphGeo, depthMaterial);

Three.js: MeshDepthMaterial

Conclusion

We covered a lot in this post, including materials and geometries, how to create 3D objects such as spheres and cylinders, etc, how to create 2D objects such as rings and planes, and how to create text. We also learned how to build materials that change the texture and color of shapes.

: Debug JavaScript errors easier by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

.
Chidume Nnamdi I'm a software engineer with 6+ years of experience. I've worked with different stacks ranging from WAMP, to MERN, to MEAN. My language of choice is JavaScript; frameworks are Angular and Nodejs.

Leave a Reply