Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

Follow publication

Optimizing 3D Model Rendering in Next.js by Reducing Blocking Time Using React Fiber Offscreen

--

Optimize 3D Model Rendering in Next.js by Reducing Blocking Time Using React Fiber Offscreen

Whenever we use CPU-intensive operation on the Web, it becomes sluggish and un-interactable for some time. Rendering a 3D model directly affects the initial loading time of the Web, so we can use Web Workers to load them behind the scenes.

In this article, we will optimize the loading time of our model which we built in the following article:

If you want to study Web Workers in general, you can visit the following article:

Now without further ado, let's start our tutorial!

1) Install React Three Fiber:

To render your model in Web Worker you can install the following dependency using:

npm install @react-three/offscreen

2) Moving all the Children of Canvas into Another File:

In the previous “Animated Avatar” tutorial we had our model rendered something like this:

// components/avatar-renderer.tsx

"use client";

import { Suspense } from "react";

import { Canvas } from "@react-three/fiber";
import { Environment, OrbitControls } from "@react-three/drei";

import Avatar from "@/Avatar";

const ModelRenderer = () => {
return (
<div className="w-full h-auto aspect-[24/25]">
<Suspense
fallback={
<div className="w-full flex items-center justify-center h-[calc(100vh-300px)] font-bold text-[30px] font-mono text-white">
loading...
</div>
}
>
<Canvas
shadows="basic"
// adjust camera parameters according to your needs
camera={{
position: [0, -5, 1.5],
fov: 50,
castShadow: true,
zoom: 1.3,
}}
className="w-full h-full"
>
<OrbitControls />
<ambientLight intensity={1.5} />
<Environment preset="sunset" />
<directionalLight intensity={0.8} />
<Avatar />
</Canvas>
</Suspense>
</div>
);
};

export default ModelRenderer;

Now we will divide this into different files.

First, we will create scence.tsx which will contain our scene as follows:

// scene.tsx

"use client";

import Avatar from "@/Avatar";

import { Environment, OrbitControls } from "@react-three/drei";

const Scene = () => {
return (
<>
<OrbitControls />
<ambientLight intensity={1.5} />
<Environment preset="sunset" />
<directionalLight intensity={0.8} />
<Avatar />
</>
);
};

export default Scene;

Now we will create a worker named worker.tsx which will import the scene as follows:

// worker.tsx

"use client";

import { render } from "@react-three/offscreen";

import Scene from "./scene";

render(<Scene />);

Now, in the model-renderer.tsx , rather than importing Canvas from @react-three/fiber now we will import from @react-three/offscreen and configure our components as follows:

// components/avatar-renderer.tsx

"use client";

import { Suspense, lazy } from "react";
import { Canvas } from "@react-three/offscreen";

const Scene = lazy(() => import("./scene"));

const worker = new Worker(new URL("./worker.tsx", import.meta.url), {
type: "module",
});

const ModelRenderer = () => {
return (
<div className="w-full h-auto aspect-[24/25]">
<Suspense
fallback={
<div className="w-full flex items-center justify-center h-[calc(100vh-300px)] font-bold text-[30px] font-mono text-white">
loading...
</div>
}
>
<Canvas
worker={worker}
fallback={<Scene />}
shadows="basic"
camera={{
position: [0, -5, 1.5],
fov: 50,
castShadow: true,
zoom: 1.3,
}}
className="w-full h-full"
/>
</Suspense>
</div>
);
};

export default ModelRenderer;

Make sure to import ModelRenderer dynamically as follows:

import dynamic from "next/dynamic";

const ModelRenderer = dynamic(() => import("@/components/model-renderer"), {
ssr: false,
});

const Page = () => {
return <>
{/* ... any other code */}
<ModelRenderer />
</>
}

export default Page;

Testing Blocking Time:

Now we will test for blocking time. The rendered model without the Web Worker is deployed at: https://next-with-animated-avatar.vercel.app/, and it gave the following results:

Model Blocking Time
Model Blocking Time Without Web Worker

The model rendered using Web Worker can be found at https://next-with-animated-avatar-offload.vercel.app/. It gave the following results:

Model Blocking Time Web Worker

And that’s it, Happy Coding! 😊

Access the Code at:

Visit the Live version at: https://next-with-animated-avatar-offload.vercel.app/

If you liked my story you can follow me for more interesting tips and tricks at Farasat Ali — Medium.

You can Find Me on LinkedIn and GitHub.

Also, Visit My Portfolio at:

You can also explore the following related articles:

Stackademic 🎓

Thank you for reading until the end. Before you go:

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

Written by Farasat Ali

Tech Savvy 💖 Blockchain, Web & Artificial Intelligence. Love to travel, explore culture & watch anime. Visit My Portfolio 👇 https://linktr.ee/faraasat

No responses yet

Write a response