Web-Based 3D Scene:
Setup in Blender

|
21 min read
Optimize 3D scenes for web use by following this tutorial on finding models, simplifying scenes in Blender, and exporting for online integration.

Introduction

In this blog post we're setting out on a mission to optimise a 3D scene for a web application, using Blender. Our aim isn't to simulate physics effects, but rather to focus on quality and performance in our rendering. To achieve our goal, we'll handle all the rendering in Blender and export the resulting data as a baked texture. This approach enables us to simplify our web application to a single material, resulting in a significantly faster rendering process.

In this first part, we'll be walking you through selecting an appropriate model and optimising the scene in Blender. Our goal is to prepare a 3D scene that loads swiftly and efficiently on the web, ensuring a seamless user experience. It's helpful to have a basic understanding of Blender.

For this tutorial, I've prepared a 3D model for you to use, saving you the time and effort of searching for one. The scene we'll create is designed for one-sided viewing, which enables us to optimize the model more effectively by disregarding the non-visible part of the scene.

Tips where to find the model

In case you want to search for alternative 3D models to use in your project, consider websites such as Sketchfab, TurboSquid, Blend Swap and CGTrader. These platforms offer a wide variety of models, ranging from free to premium assets.

Ideally, you should look for models that are already optimized for web use, as this will significantly simplify your workflow. However, if you come across a more complex scene that requires optimization, follow this tutorial to learn the necessary steps.

Model overview

Upon initial inspection, the 3D scene we'll be working with may appear simple, but it is quite complex. To get an idea of its complexity, try exporting the scene and check the file size.

You'll notice that the exported file size is rather large, which is something we need to address first and foremost to ensure quick loading times.

One of the main problems is number of polygons in the scene. As you can see the scene have over 42k triangles. This is a lot for a scene like this.

Scene stats
Scene stats

We can reduce the number of polygons and still keep the same shape of the model.

Optimising the scene

Let's start by optimising the scene and reducing number of polygons.

Removing unnecessary objects

First, consider how you plan to use your model and which parts will be visible to the user. This will allow you to remove unnecessary objects and simplify the scene. In our case, the plan is for the scene to be viewable from one side with a slight tilt/rotation. This means that most objects at the back won't be visible to users.

When removing objects, remember that these changes could affect lighting and shadows. In some cases, it's a good idea to replace a complex object with a simpler one or keep it in the scene to influence lighting and shadows but exclude it from the export file.

Selecting objects to remove
Selecting objects to remove

Removing modifiers

In Blender, modifiers are powerful tools that modify an object's geometry in a non-destructive manner. While they can enhance the details and capabilities of your scene, they can also significantly increase its complexity. Therefore, to keep your scene manageable and efficient, it's beneficial to remove unnecessary modifiers or apply them permanently to the mesh.

Keep in mind that modifiers cannot be directly exported. That said, they can be automatically applied during the export process, so it's not always essential to apply them beforehand. However, applying modifiers can make the model easier to work with, and it can further streamline the mesh for optimal performance.

Modifiers can be easily identified in the three views of our scene.

Easily identify modifiers in the three views of our scene
Easily identify modifiers in the three views of our scene

In our scene, we are dealing with three types of modifiers:

Solidify

The Solidify modifier adds depth to the object. For our model, this modifier is necessary, so we're going to keep it.

Model with and without solidify modifier
Model with and without solidify modifier

Simple deform

The Simple Deform modifier is typically used to bend the object. In most cases, this modifier is applied to retain the bend in the object. However, in our specific scenario, we can safely remove it. We'll then manually add and potentially animate the bend using Three.js.

Model with and without simple deform modifier
Model with and without simple deform modifier

Bevel

This modifier adds a bevel to the edges. In some cases, you can remove this modifier or reduce the number of segments. In our case, the bevel is applied to wooden planks and bricks, which are relatively small compared to the preview, so we can likely remove it

Model with and without simple deform modifier
Model with and without simple deform modifier

When evaluating your scene's modifiers, it's helpful to set up a Blender preview that mirrors your desired end result. By toggling the modifiers on and off within this preview, you can observe the influence of each modifier. This makes it easier to decide which ones enhance your scene and which ones could be removed.

Preview how the modifiers affect the scene
Preview how the modifiers affect the scene

Decimate modifier

Sometimes, you may come across models with complex meshes that cannot be easily optimized by merely removing the modifiers. In such cases, you can use the Decimate modifier to reduce the number of polygons in the model. The Decimate modifier allows you to decrease the vertex/face count of a mesh while minimally affecting its overall shape.

In our scene, even after the removal of all modifiers, some meshes, like roof tiles, bricks, and wooden planks, remain relatively complex. We can further simplify these using the Decimate modifier.

To utilize the Decimate modifier, select the desired object, and then add the Decimate modifier. Three options allow you to adjust the mesh: Collapse, Un-Subdivide, and Planar. Collapse and Planar are the most frequently used and can offer the best results. Experiment with these to achieve an optimal outcome.

Use decimate to reduce the number of polygons
Use decimate to reduce the number of polygons

Manual editing

For more complex models, manual editing may be necessary. This method involves removing extra vertices, edges, and faces while maintaining the overall shape of the model. Fortunately, in our case, we were able to avoid most of the manual editing by effectively using the Decimate modifier. This reduced complexity and optimized the model, saving us time and effort.

Removing invisible faces

Another efficient way to optimize your scene is by removing faces that aren't visible to the camera or viewer. This step differs from our previous discussion on whole objects. Here, the focus narrows to individual objects and their specific polygons. Besides further reducing the number of vertices, this step also simplifies the UV mapping process and helps conserve valuable texture space.

Luckily, some of our meshes are linked together, which streamlines the editing process. For instance, editing one brick applies the changes to all the bricks in the scene, saving considerable time and effort.

Removing back of the bricks and wooden elements- before
Removing back of the bricks and wooden elements- before

Before proceeding to the next step, it's important to apply all the modifiers. This ensures that we're working with the simplified meshes when we transition to the UV editor.

UV unwrapping

To bake textures, a UV map is required for each object. This process, known as unwrapping, translates the 3D model onto a 2D texture canvas.

Preparing the texture

Before we dive into unwrapping the UVs, it's essential to assign a material to every object in the scene. Each material must also have an associated texture. This texture will be instrumental when we bake the texture from the high poly model to the low poly model. In our case, all models have a single material, simplifying this process.

Begin by creating a new image texture in the UV Editing view 1. To do this, click Image > New 2. Set the size to 2048x2048 3, select UV Grid 4 for Generated Type, and then click OK. This image will serve as the blueprint for the UV unwrapping process. We're assigning the UV Grid so that we can quickly assess the layout of the UV map.

Create new texture
Create new texture

Next, assign the texture to the material. Switch to the Shading view 1 and select the material 2. Add a new Image Texture node 3 and connect it to the Base Color 4 input of the Principled BSDF node. Finally, select the texture 5 we created in the previous step. This links our newly created texture to the model's material, setting the stage for efficient texture baking.

Add new image texture node
Add new image texture node

Unwrapping

You have the option of manually cutting seams in your mesh or using Blender's Smart UV Project feature to automatically generate a UV map. From my experience, manually cutting seams often yields better results. However, this method requires a bit of experience and familiarity with the process. Fortunately, there are numerous online tutorials available that can guide you through this task.

Now let's explore the unwrapping of various elements in our scene to better understand the process. We'll need to switch to the UV Editing view. Then, select an object and enter Edit Mode. This mode gives you the freedom to manipulate individual vertices, edges, and faces, which is crucial for effective UV unwrapping.

Ground

Begin by selecting the ground object, then switch to Edit Mode and select all its faces. Press U and choose Unwrap.

Unwrapp the ground
Unwrapp the ground

Upon observing the scene preview, you'll notice areas where the texture appears stretched. This distortion results from an imperfect UV map. We can optimize the UV map by creating seams in the mesh. Let's try to cut seams at the corners of the ground and then unwrap it again. It's advisable to add seams near regions where the texture is stretched and in areas where the seams are less likely to be seen.

Adding seams
Adding seams

Next, let's unwrap the ground tiles. Select the object, switch to Edit Mode, and select all its faces.

Unwrapp the ground
Unwrapp the ground

On inspection, the texture appears quite acceptable; there's minimal distortion. Given this, we can leave it as is and proceed to the next object. The aim is to optimize where necessary, without overcomplicating the process.

Trees

Select one of the tree objects and apply the unwrapping process. You'll notice that the default unwrap is quite good, although it could benefit from additional seams for further optimization.

Default tree unwrapping
Default tree unwrapping

Building

Now, let's turn to the building. We'll begin with the bricks. As all the bricks are linked, we only need to unwrap one of them, and the changes will apply across the board.

Default brick unwrapping
Default brick unwrapping

Next, we'll tackle the wooden parts of the building, starting with the wooden beams.

Default unwrapping
Default unwrapping

Remaining

The previous steps should have given you a sense of the process. I'll briefly go over the rest of the model and focus on presenting the final results. You'll find a link to the Blender file with all seams at the end of this tutorial. This can help you understand where and how to position seams for optimal UV unwrapping outcomes.

Wooden planks
Wooden planks

Final steps

Before proceeding to the next step, we need to unlink all objects in our scene 1. This will enable us to assign a different part of the UV map to each object. Please note, this means objects in our scene will no longer share mesh data, which could complicate any further editing. If you anticipate future adjustments, it may be a good idea to duplicate your model and hide it in the scene for later use. We should also apply scaling to our objects in the scene to simplify the scaling of our UV maps 2.

Remove relations
Remove relations

Baking

Now lets move on to baking our scene.

Preparing the texture

To start, let's create a new texture for baking. As before, navigate to UV Editing, select Image > New Image 1 and adjust following settings 2:

  • Set the size to 4096x4096 - This should provide sufficient resolution for our scene, and we can always scale it down later if necessary.
  • Set the color to white - Occasionally, the background color may show up in the baked map, so it's preferable to use a color that will blend with the scene.
  • Select 32-bit Float - This will allow us to bake the scene with high dynamic range.

Once you've created the texture, you should save it to a file. Go to Image > Save As Image 3 and save the texture to a file as an HDR (high dynamic range) 4, and store it in the same folder as the Blender file. Saving the file as an HDR and using a 32-bit float texture will allow us to bake textures with the highest possible quality, which we can then convert to PNG or JPG.

Create new texture
Create new texture

Now we're ready to unwrap our entire scene. Select all objects in the scene 1, switch to Edit Mode 2, and press U to unwrap all the elements 3. You should also add small amout of margin to avoid textures bleeding into each other 4. This should unwrap all the elements in such a way that there are no overlaps

5
Unwrapp the whole scene
Unwrapp the whole scene

Finally, we need to update the texture 2 in the Shading tab 1. We should also unlink the texture from the material 3 to ensure it doesn't impact the final render.

Update the nodes
Update the nodes

Baking the scene

Switch to the Render Properties tab 1. Before we start baking, let's discuss some of the settings:

  • Render engine Cycles 2 - Currently, this is the only render engine that supports baking.
  • Bake type Combined 3 - This will bake all visible information into a texture.
  • Margin 4px 4 - This will add a margin around the UV islands to prevent bleeding. The size of the margin depends on the space we have between the UV islands.
  • Clear image disabled - This will prevent the texture from being cleared before baking. It is also useful if you want to split the baking into multiple steps.
  • Sampling 5
    • Samples 16 - In simple terms, this defines the quality of our bake. The higher the number, the better the quality. However, a higher number will take longer to bake. If you have a powerful machine, you can select higher values.
    • Denoise off - Denoising helps reduce the noise caused by low sampling. In our case, we'll handle denoising in post-processing, which will be much faster, so we can disable this property.
Update the nodes
Update the
nodes

Now, simply click Bake and wait for the results. This may take a while depending on your hardware.

If everything went well, you should see the baked texture in the UV editor.

To verify the result, switch to the Shading tab 1, change the preview to Material preview (by pressing z) 2, and connect the baked texture directly to the Material Output node 3 (we no longer need the material node).

Baked texture
Baked texture

Denoising

As previously mentioned, we've disabled the denoising as part of our bake. Now let's denoise the texture in post-processing. To do this, we'll use the Denoise node in the compositor. Switch to the Compositing tab 1, select Use Nodes 2, then add an Image node 3 and select our baked texture 4. Next, add the Denoise node 5 and connect them as shown below. You also need to disconnect and disable the Render Layers node, which you can do by selecting it and pressing M 6. Before we run the denoising, we need to change the output size to match the size of our texture 7 . Switch to Output Properties and change the resolution 8.

Baked texture
Baked texture

Finally, you can press F12 (or go to Render > Render Image).

Once the render is finished, you can save the image as a JPG by going to Image > Save As Image.

Denoising result
Denoising result

As you can see, almost all the noise is gone, and the texture looks much better.

Exporting the scene

We've finally reached the last step of this tutorial: exporting the scene.

First, let's ensure we're only exporting the scene models, without the background (we'll add the background in three.js), cameras, and lights. Next, I usually duplicate all the elements in the scene (with Shift + D), merge all the models into one mesh (Cmd + J), and add them to a separate collection. Merging all the models together will make the model much more performant in Three.js and easier to work with.

Duplicate and then merge all the elements in the scene
Duplicate and then merge all the elements in the scene

Now we can export the scene. First, ensure that only the merged model is selected 1. Then go to File > Export > glTF 2.0 2. In the export settings, make sure to select the following options3:

  • Disable materials - all the materials are now baked into the texture
  • Disable animations - since we don't have any animations
  • Apply modifiers - this will apply all the modifiers to the model (although this should not be necessary since we already applied all the modifiers)
  • Select UVs - this is required for our baked texture to be mapped properly.
Denoising setup
Denoising setup

As you can see, we've managed to reduce the size of the model from over 8MB to just 1.1MB. Even more size reduction is possible with more thorough optimization and additional compression, which we will not cover here.

Bellow you can find all the files we've created in this tutorial:

Testing the exported model

In the next part, we'll put the exported model into a Three.js scene in a react app. But before that, let's test the model in modelviewer.dev. Upload your gltf file there by dragging and dropping it into the editor. Go to the materials tab 1, then upload our texture 2

Preview the exported model in modelviewer.dev
Preview the exported model in modelviewer.dev

Conclusion

In this guide, we took significant strides towards understanding the process of preparing a 3D model for web use. We successfully reduced a model's size to just 1.1MB, learning key techniques such as optimizing the model, decreasing polygon numbers, and baking textures.

However, it's important to note that this is just an introduction to a much broader topic. The world of 3D model optimization is vast and has a multitude of other methods that can be used to further enhance efficiency and performance. What we've covered here is the tip of the iceberg, a basic overview to get us started.

Excitingly, in the next section, we're going to bring our work to life by loading the optimized model into a React app. This upcoming segment will allow us to see our efforts in action and further appreciate the benefits of a well-optimized 3D model.

Finally, I'd love to hear from you. Please feel free to share your feedback or any thoughts on this guide. And if you found it helpful, do consider sharing it with others who might also benefit.

Leave feedback