Creating Stunning 3D Graphics on the Web: Beginner’s Guide

A guide to creating and incorporating stunning 3D web graphics to take your website to the next level and make it stand out from the crowd.

Hugo Gonçalves
MCTW_TDW
10 min readFeb 26, 2024

--

With the rampant growth of web and web services, making your website stand out in this crowded market is challenging. In today’s market, simply having a beautiful design is not enough to impress your customers. It takes something extra, something to cause the “Wow” factor. Using 3D graphics can be a great way to achieve that. Whether you want to create some product visualizations or interactive experiences, 3D graphics can add a whole new level of dynamism to your website. Just check how Madbox, a game studio, uses 3D graphics on their website. Isn’t it awesome?

However, starting your journey in this world of 3D graphics can be daunting and very intimidating, especially if you are trying to use low-level APIs such as OpenGL or WebGL. Thankfully, nowadays, many libraries abstract the complexity of such APIs while still allowing the necessary flexibility for building excellent graphics.

In this article, I will unravel this world with you! We’ll begin by breaking down the difference between Low-Level graphics APIs and Graphics Libraries. From there, we will examine the different types of graphics libraries and some of their strengths and weaknesses. Finally, we will wrap things up with a straightforward tutorial on creating your own 3D graphics for the web using Three.js. By the end of this article, you’ll have a basic understanding of the 3D graphics world and the tools available to create these stunning visuals that you see around on some websites.

Low-Level Graphics APIs vs. Graphics Libraries

At this point, you may be wondering what a “low-level graphics API” is. In the web context, we generally speak about two APIs:

  • OpenGL is a graphics standard for rendering 2D and 3D graphics. It is cross-language and cross-platform, meaning it can be used with a wide range of programming languages and run on various platforms, from browsers to smartphones.
  • WebGL is a Javascript API based on OpenGL that was specially conceived to render graphics directly in web browsers.

A graphic library simplifies creating 3D graphics by abstracting complex APIs. Depending on project requirements, the choice of using a library over a low-level API (or vice-versa) may have advantages and disadvantages. To illustrate this point, I have created a table comparing the advantages and disadvantages of graphic libraries vs. low-level graphic APIs.

Comparison of Low-Level APIs with Graphical Libraries — created by the author

Now that you know what Low-Level APIs and Libraries are and some of the advantages and disadvantages of each, we will focus on our primary goal — creating awesome graphics for the web using the most straightforward approach, i.e., a graphic library.

What are our options?

There are several libraries to manipulate WebGL graphics. The most popular one is, by far, Three.js. Three.js is an open-source Javascript library to create 3D graphics on web browsers based on WebGL. There are also some projects to simplify its usage on major web frameworks such as ReactJS. It is well-documented and has a large community of developers, which means plenty of resources are available for learning and troubleshooting. It does not provide some extra features other competitors offer, such as a physics engine, but don’t worry; some can still be achieved using external libraries.

The Story About Little Bird — An interactive 3D experience created using Three.js.

Babylon.js is another open-source JavaScript library for creating 3D graphics on the web. Unlike Three.js, it is designed with game development in mind, offering more refined features and functionality for games specifically. One of the main advantages of Babylon.js over Three.js is the built-in physics engine. Babylon.js also has better support for augmented and virtual reality applications when compared to Three.js.

Scene rendered and constructed using Babylon.js and SSR (Screen Space Reflections).

PlayCanvas is presented as “an open-source game engine” that uses WebGL to run games and other 3D experiences in browsers. Unlike Three.js and Babylon.js, it features a comprehensive visual editor where developers can manage their 3D objects, adjust their properties, import and control assets, etc. It works somewhat like Unity in this regard. Compared to Three.js and Babylon.js, PlayCanvas is much more UI-oriented than the previous ones, which are more code-oriented. Babylon.js and PlayCanvas serve the same purpose: to be complete game engines for the Web, available as open-source projects.

PlayCanvas Web Editor — One of the most iconic features in the PlayCanvas library.

After this comparison, we are in a good position to choose the best library for our applications. In summary, if you intend to develop a game for the Web, consider looking at Babylon.js or PlayCanvas, as both libraries were developed to serve as game engines for the Web. Keep in mind that, as of 2023, Babylon.js is slightly more popular than PlayCanvas and has a more significant community. On the other hand, PlayCanvas is more user-friendly as it has a complete UI, which can be particularly helpful if you’re accustomed to other game engines like Unity or Godot.

Three.js is a great choice for beginners in the 3D world, with a vast community of developers and contributors. You can rely on a massive library of simple and complex example applications to learn from. Once Three.js doesn’t have a physics engine and other extra features natively, it is easier to learn as you have less to understand to get started.

Getting started with Three.js

Now that we have seen some of the libraries that can allow us to achieve the primary purpose of this article — creating 3D graphics for the web — it is time to practice!

To create some basic graphics on the Web, we will use Three.js. We need four elements:

  • a scene;
  • a camera;
  • a renderer;
  • some 3D objects to render.

Create a new project

To create a new project and install Three.js, follow the tutorial on the Three.js website. It is very straightforward. Install Three.js using Vite. Once you have created the project, return to building our basic example.

Create HTML document

Once Three.js is rendered in a Web environment, we must create a simple HTML document to start our example. This document will essentially contain a canvas element (#webgl) and a script implementing all the Three.js logic.

The canvas element acts as a whiteboard on which our graphics are rendered, while the script controls all the graphics' behavior.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Three.js Introduction</title>
</head>
<body>
<canvas id="webgl"></canvas>
<script type="module" src="./scripts/three_exercise.js"></script>
</body>
</html>

Scene

Next, we need to create a Scene. A scene allows you to set up what/where the 3D objects will be placed. You can add all of your objects, models, particles, lights, etc., in it, and at some point, you will ask Three.js to render that scene.

// Import three JS library
import * as THREE from 'three'

// Scene
const scene = new THREE.Scene()

Objects

Now that we have created our scene, we must add some Objects. Objects can be many things; you can have primitive geometries, imported models, particles, lights, etc. In this example, we will create a simple red cube. To make that red cube, we need to develop a type of object named Mesh. A Mesh combines a geometry (the shape) and a material (how it looks).

There are many geometries and materials, but we will keep things simple for now and create a BoxGeometry (cube) and a MeshBasicMaterial (a basic material with a color).

// Create the geometry
const geometry = new THREE.BoxGeometry(1, 1, 1) // Create a geometry

// Create the material
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })

// Create the mesh of points using the geometry and the material
const mesh = new THREE.Mesh(geometry, material)

// Rotate the cube a little bit so it looks better
mesh.rotation.x = 5
mesh.rotation.z = 5

// Add the mesh (cube) to the scene. When we create a new mesh, we always need to add it to // the scene so it can be rendered
scene.add(mesh)

Camera

The next step is to add a Camera. When we render the scene, it will be rendered from the camera’s point of view. You can have multiple cameras, just like on a movie set, and you can switch between those cameras as you please. To create a camera, we can use the PerspectiveCamera class.

// Camera
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight)

scene.add(camera)

Renderer

Now that we have a scene, a camera, and a simple cube in our 3D environment, we need to render it. To achieve this, we will request the renderer to render the scene from the camera’s perspective. The output of this process will be drawn onto a canvas. In this case, we will render the scene into the canvas we created at the beginning of this example.

// Obtain the canvas from the HTML document
const canvas = document.querySelector('#webgl')

// Create the rendered
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})

// Set the renderer as full screen
renderer.setSize(window.innerWidth, window.innerHeight)

// Finally, render the scene
renderer.render(scene, camera)

And that’s it! It was simple, wasn’t it? After completing these steps, you should see something like this

3D result of the basic tutorial

Performance Considerations

Although web graphics are amazing and can help create exciting and engaging web experiences, the performance impact of such technologies must always be considered. Both OpenGL and WebGL — as well as the libraries build on top of these — use the device’s GPU to render the different graphics frames. Although some of the available Graphics Processing Units nowadays are extremely powerful, some devices with low-end GPU still exist. Therefore, to ensure that your graphics will perform even in “slower” devices, you should at least know about the primary performance “eaters” in web graphics.

Do not abuse lighting techniques

Although lighting techniques can add extra realism to your 3D graphics, they can be costly for performance. My tip is to use as few lights as possible. However, if you need to use them, consider using simpler lighting techniques, such as Ambient Lighting, instead of more complex ones, such as SpotLights.

One way to maintain high performance in highly realistic scenes is to use Baked Lighting. I won't discuss this topic as it is highly broad and would require an article dedicated to it. However, it involves simulating the lighting of a scene by adding artificial lights to the textures. If you want to know more about it, you can check the following article.

Use simple materials and shaders

Most libraries support a huge set of different materials, each implementing different rendering techniques. Although using more complex materials (PBR materials, for example) can provide more visually appealing results, they are more costly in terms of performance. Always balance the looks vs. the performance cost.

Antialiasing and pixel density can impact performance

The effort of your GPU to render graphics is proportional to your screen's resolution. This means that as the resolution increases, the performance of your graphics may decrease.

However, although some devices have small screens, they still have incredibly high resolutions. Smartphones achieve high-quality displays by increasing pixel density, for example. This means that the GPU has to render bigger frames, which requires more effort. However, since the screen is small, there is no difference in the final graphics quality if it renders the scene with a smaller resolution. Some libraries, such as Three.js, allow developers to choose the maximum pixel ratio to use on their scenes. By reducing this value, some performance can be gained by avoiding unnecessary effort instructing the GPU to render “smaller” frames.

Similarly, antialiasing techniques can provide more visually appealing results as they remove the appearance of jagged edges around objects. However, these techniques impact the performance as, depending on the antialiasing method, this can be solved by rendering a scene with a higher resolution.

Always keep an eye on performance

It is important to always monitor your graphics performance. However, this can be difficult as although your graphics run smoothly on your computer, it doesn’t mean they will run as well on other people's devices. Additionally, what is the definition of smooth?

To help with this, several libraries allow you to check statistics about graphics, such as the current FPS, time of rendering, etc. One example of a library like this is r3f-perf, a JavaScript library that allows the monitoring of Three.js experiences using React.

And that’s it! With this knowledge, you are now more prepared to embark on your journey to create awesome 3D graphics for the web using Three.js.

To learn more, please consult Three.js documentation and tutorials here.

Also, take a look at some of the examples available on the Three.js website. You would be surprised by how much knowledge you can gather from them.

References

--

--

Hugo Gonçalves
MCTW_TDW
Writer for

Master's student in Software Engineering at Universidade de Aveiro | Special interest in Software Architecture, DevOps, and Computer Graphics.