How to build 3D web apps. Part 3. Client-side libraries for 3D data display

In the third part of "How to build 3D web apps" series we explore two JavaScript libraries that simplify the development of 3D web app clients

Anton Larin
Anton Larin
6 min read

Previous parts:

Part 1: Introduction

Part 2: Architectures

As was established the last time, for the next few posts we're going to assume that we're developing a client-server application with client-side 3D rendering. This time we will see what tools can be used to implement the interactive 3D model display on the client.

Can I use raw WebGL?

An experienced technical leader is careful with introducing dependencies in their architecture, so this is a completely natural question. Since every other tool uses WebGL under the hood to display 3D models on the web, it is possible to use the underlying technology directly. WebGL is ultimately based on OpenGL, so implementing a 3D renderer requires expressing the model data in terms of GPU-consumable buffers with vertices, normals, texture coordinates, and expressing the rendering process in terms of draw calls and shader invocation. The API is low-level, meaning that your team needs graphics developers. Additionally, virtually all the 3D viewer functionality will have to be implemented from scratch: 3D model loading, displaying with a camera, shading, handling of user input in the viewport and mapping it to the camera movements, etc.

This route is extremely time-consuming, and ultimately not recommended for your average web development team. Does it make sense at all? One viable use case for this can be an implementation of a custom high-performance visualization mechanism. Such a mechanism might not afford the overhead introduced by higher-level libraries, while hiding the complexity of WebGL. Implementing high-performance visualization requires optimizing meshes and shaders, reducing the number of draw calls to squeeze all the framerate out of the GPU. High-performance visualization is a must, if the 3D models are truly massive, but luckily there are alternatives to doing custom renderer from scratch, as there are commercial projects providing such tools (e.g. Zea).

What JavaScript 3D library to pick?

Now that the need to use a 3D library has been justified, we'll take a look at and compare two popular client-side 3D libraries: Three.js and Babylon.js. They can be considered general-purpose 3D libraries, as they provide support for the functionality that every 3D app developer might need - managing scenes, displaying objects, handling user input, playing animations. If the app has additional, domain-specific requirements (e.g. displaying CAE simulation results), these might not be available out of the box. Generally, such requirements have to be implemented with custom logic on top of these tools. So the amount of freedom a tool gives the developer to implement domain-specific features is quite important when making the choice.

Fig. 1. CAE and BIM are two of the areas where domain-specific visualization tools, aimed at the datasets of the respective areas, can be helpful to app developers.
Fig. 1. CAE and BIM are two of the areas where domain-specific visualization tools, aimed at the datasets of the respective areas, can be helpful to app developers.

An alternative approach would be to use a domain-specific tool. There's a number of CAD and BIM data display, scientific visualization and other libraries. They typically provide extra features specific to their areas: loaders for domain-specific 3D formats, ready-made primitives to display domain-specific 3D object types and tools, customarily used to manipulate the objects. Thus, if the domain-specific application's functions fall in line with the general needs of its potential users, they can potentially save lots of development time. We won't cover them in detail here, as discussion of these tools is out of scope for this post.

Three.js

This is an extremely popular 3D graphics library. Three.js makes the basic 3D model display much simpler compared to the raw WebGL. It allows the setup of the scene not in terms of raw buffers and shaders, but with convenient primitives that describe meshes and materials. It provides an ability to hierarchically group the objects to define the scene graph and to assign LODs, which are used to automatically switch to the lower-fidelity version of an object when it's far away. It simplifies the basic scene controls by providing a few predefined control schemes (orbit, fly, first-person, etc.), which handle user input (mouse clicks and drags) and adjust the camera position relative to the object. There's also a built-in functionality to handle object selection in the scene via mouse clicks. A simple scene editor allows one to create scenes in WYSIWYG fashion and download them in JSON format for later loading in your application, instead of setting up the same scenes by hand using JavaScript.

Fig. 2. Three.js main page, showcasing projects built with the library. Some of these are built by big and famous organizations, such as NASA, Apple, Oculus and Maserati.
Fig. 2. Three.js main page, showcasing projects built with the library. Some of these are built by big and famous organizations, such as NASA, Apple, Oculus and Maserati.

Three.js tries to strike a balance providing as much useful functionality as needed, while being fairly lightweight and minimal. As a result, some capabilities reside not in Three.js itself, but in third-party plugins for it: notably acceleration data structure for object selection, text and UI controls, some format loaders and others. Another consequence is to implement custom workflows (e.g. importing meshes from your own format), one needs to use some lower-level Three.js objects - buffers and buffer attributes. They are still not as tedious as raw WebGL, but are more technical than using primitives or built-in loaders and require a certain level of understanding of graphical programming.

Babylon.js

This is another popular Javascript library for 3D graphics. It aims to provide a more complete experience to developers seeking to implement 3D applications. Obviously, it has all the mandatory things, like the scene graph, meshes, LODs, materials, textures and lights. Aside from packaging these features into an easy-to-use API, Babylon.js provides many convenience features. There's a comprehensive range of cameras with scene controls with convenient defaults, meaning you can just drop them into your code and have them work without having to tweak their settings. An automatic LOD generation capability based on mesh simplification is also included. There's a built-in mechanism for selection acceleration. For more fancy rendering needs it provides a set of post-processing effects, a particle system and a collision system.

There are also a few tools, which can speed up the development process. Babylon.js provides a complete 3D model viewer that you can just drop into your web page without having to write any code at all. There's a visual material editor, which comes in handy when experimenting with implementation of custom shaders, or if you want to make a custom material without writing shader code altogether. There's also a Playground, an online environment useful for prototyping ideas without having to create a separate local project.

Fig. 3. The Babylon.js material editor, allowing creation of custom materials without the use of a shading programming language.
Fig. 3. The Babylon.js material editor, allowing creation of custom materials without the use of a shading programming language.

Three.js vs Babylon.js comparison

In terms of their philosophy, these tools occupy different spots on the library-frameworks spectrum. Three.js is indeed more of a library, aiming to abstract away the tediousness of WebGL API, whereas Babylon.js feels more like a framework of 3D renderer, with many things preconfigured and there being many helper and convenience functions. For a simple example, consider how the render loop is typically implemented with these tools. In Three.js we make use of built-in renderAnimationFrame() function:

function animate() {
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
}
animate();

Meanwhile, in Babylon.js there's a massive class Engine among whose responsibilities is managing the loop:

const engine = new BABYLON.Engine(canvas, true);
engine.runRenderLoop(function () {
    scene.render();
});

So, Babylon.js provides many helpful abstractions with predefined behavior, often making it more convenient to use. This comes with the cost of a heavier package size, coming in at more than 3 MB minified, compared to just 300 KB for the entire Three.js. Both can be used in the form of ES6 modules, allowing to utilize tree-shaking for smaller package sizes. For example, Babylon.js could be reduced to a few hundred KB (depending on the scope of objects used), but that will likely still be more than the Three.js. Because of that for lightweight apps, such as simple asset displayers, it makes more sense to choose Three.js over Babylon.js.

Three.js and Babylon.js also have different approaches to the development: the former releases new versions frequently and sometimes breaks the API, while the latter prioritizes backward compatibility, so its API is significantly more stable. Practically this means that it's easier to migrate to newer versions with Babylon.js, whereas with Three.js it's probably better to just fix the version you used in your app, and only update it if the new one adds something vital later.

Summary

Hopefully, this post clarified for you the situation around the two biggest client-side 3D display libraries. Three.js and Babylon.js are both great tools to build upon for your 3D data display functionality. Therefore, choosing between them is a matter of weighing their subtle differences against your specific requirements for third-party dependencies. For example, for basic display or another lightweight application, Three.js makes more sense, whereas Babylon.js can allow the implementation of more involved projects with less code.

Next time we'll consider the backend of a 3D web app, its responsibilities and the influence they have on the implementation choices.

This 3D visualization is powered by CAD Exchanger Web Toolkit - a library for interactive CAD data visualization. Find out more and request a trial here.

Learn more:

How To Load 3D CAD Data Into Three.js. Part 1

How To Load 3D CAD Data Into Three.js. Part 2

Building 3D web applications with CAD Exchanger Web Toolkit

Next parts:

Part 4. Backend

Part 5. Game engines

Part 6. Tutorial on building a 3D web app

Anton Larin
Anton Larin
Software Engineer

Get the CAD Exchanger Newsletter

From us to your inbox weekly.