# \[WebGPU\] Significant performance drop and shadow quality regression in r182 vs WebGL r170

**URL:** <https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322>\
**Category:** Questions\
**Tags:** performance\
**Created:** [January 20, 2026, 5:44pm UTC](https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322 "2026-01-20T17:44:27Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![kang-Z-A](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/kang-z-a/32/66325_2.png) [@kang-Z-A](https://discourse.threejs.org/u/kang-Z-A)\
**Post date:** [January 20, 2026, 5:44pm UTC](https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322/1 "2026-01-20T17:44:27Z")

</div>

I am exploring the migration of my project from WebGL (r170) to WebGPU (r182). I have observed unexpected performance degradation and rendering quality issues compared to the previous WebGL implementation.

Specifically, I encountered the following problems:

1. **\*\*Performance Regression:\*\***

```
\* The general frame rate when loading and interacting with models in WebGPU (r182) is noticeably lower than in WebGL (r170).

\* **\*\*Post-processing Impact:\*\*** Enabling post-processing in WebGPU causes a severe drop in frame rate, performing much worse than the WebGL equivalent (which had shadows + anti-aliasing enabled).

```

2. **\*\*Shadow Quality:\*\***

```
\* **\*\*WebGL (r170):\*\*** Shadows were relatively soft and realistic.

\* **\*\*WebGPU (r182):\*\*** Shadows appear "harder" and less realistic.

```

**\*\*Screenshots\*\***

\* **\*\*WebGL (r170) Result:\*\***

 ![Snipaste_2026-01-20_17-22-58](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/d/eda9485c519e7bda08f740d5f8154bf65871fe92.jpeg)

\* **\*\*WebGPU (r182) Result:\*\***

 ![Snipaste_2026-01-20_17-25-26](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/9/c/9cefed117cc2b7afd7a59edcc173fa9322abdd1f.jpeg)

**\*\*Reproduction\*\***

I have created a reproduction sandbox here:

[https://codesandbox.io/p/github/kang-Z-A/webgpu-example/main?import=true](https://codesandbox.io/p/github/kang-Z-A/webgpu-example/main?import=true)

**\*\*Steps to Reproduce\*\***

1. Open the sandbox link above.

2. The scene loads with Three.js r182 (WebGPU).

3. Load the test model provided (`public/threejs/building.glb`) or observe the default scene.

4. Notice the frame rate (stats) and shadow appearance.

**\*\*Expected Behavior\*\***

I expected the WebGPU renderer to provide performance comparable to or better than the WebGL renderer, and for the shadow quality to remain consistent or improve.

**\*\*Environment\*\***

\* **\*\*Three.js version:\*\*** r182.0 (WebGPU) compared to r170.0 (WebGL)

\* **\*\*Device:\*\*** Desktop PC

\* **\*\*CPU:\*\*** Intel Core i7-13700K

\* **\*\*RAM:\*\*** 32GB

\* **\*\*GPU:\*\*** NVIDIA GeForce RTX 4070 Ti

\* **\*\*OS:\*\*** Windows 11

\* **\*\*Browser:\*\*** Chrome 144.0.7559.60

**\*\*Question\*\***

Is this performance gap expected at the current stage of the WebGPU renderer? Are there specific configurations or optimization strategies required in r182 to match the performance and visual quality of the standard WebGL renderer?

---

<div class="post-metadata">

**Author:** ![phil\_crowther](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/phil_crowther/32/64202_2.png) [@phil\_crowther](https://discourse.threejs.org/u/phil_crowther)\
**Post date:** [January 20, 2026, 7:49pm UTC](https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322/2 "2026-01-20T19:49:34Z")

</div>

For one thing, I believe the ShadowBias is different for WebGL2 and WebGPU. For WebGPU, a good starting number to use is -0.0005.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [January 21, 2026, 3:30pm UTC](https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322/3 "2026-01-21T15:30:42Z")

</div>

WebGPU is still under active development. If you don’t require WebGPU specific features, you can just continue to use the WebGLRenderer.

If you see performance regressions with the WebGLRenderer then that is something worth investigating.

Comparing the two renderer types directly isn’t as useful at the present time, imo. The WebGLRenderer has had a decade of optimizations… WebGPURenderer is still very actively being developed.

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [January 21, 2026, 4:44pm UTC](https://discourse.threejs.org/t/webgpu-significant-performance-drop-and-shadow-quality-regression-in-r182-vs-webgl-r170/89322/4 "2026-01-21T16:44:29Z")

</div>

We have fixed the performance regressions on `dev` so `r183` should give you a noticeable performance boost compared to `r182`. Related issue:

> <https://github.com/mrdoob/three.js/issues/32675>
>
> \### Description
> 
> Using WebGPURenderer, when comparing the R171 version with the …R178 and dev versions, it was found that the rendering frame rate of the dev version was lower than that of the R171 version for the same model.
> 
> renderer.info.render: 
> {
> "calls": 4960,
> "frameCalls": 2,
> "drawCalls": 4493,
> "triangles": 1347487,
> "points": 0,
> "lines": 0,
> "timestamp": 0,
> "previousFrameCalls": 2,
> "timestampCalls": 0
> }
> 
> Hardware Information:
> Processor: Intel(R) Xeon(R) W-2245 CPU @ 3.90GHz 3.91 GHz
> Memory: 64.0 GB (63.7 GB available)
> Graphics Card: NVIDIA RTX A4000
> 
> \### Reproduction steps
> 
> 1. Using different versions of three.js
> 2. Loading models
> 3. Comparing frame rate performance
> 
> \### Code
> 
> \`\`\`js
> \<html lang="en"\>
> 
> \<head\>
> \<title\>three.js webgl - animation retargeting\</title\>
> \<meta charset="utf-8"\>
> \<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"\>
> \<link type="text/css" rel="stylesheet" href="main.css"\>
> \</head\>
> 
> \<body\>
> 
> \<div id="info"\>
> \<a href="https://threejs.org" target="\_blank" rel="noopener"\>three.js\</a\> webgl - animation retargeting
> \</div\>
> 
> \<script type="importmap"\>
> {
> "imports": {
> "three": "https://raw.githack.com/mrdoob/three.js/dev/build/three.webgpu.js",
> "three/webgpu": "https://raw.githack.com/mrdoob/three.js/dev/build/three.webgpu.js",
> "three/addons/": "https://raw.githack.com/mrdoob/three.js/dev/examples/jsm/"
> }
> }
> \</script\>
> 
> \<script type="module"\>
> import \* as THREE from 'three/webgpu';
> 
> import Stats from 'three/addons/libs/stats.module.js';
> 
> import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
> import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
> import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
> 
> let camera, scene, renderer, stats, controls;
> 
> init();
> 
> function init() {
> renderer = new THREE.WebGPURenderer({
> antialias: true,
> logarithmicDepthBuffer: true,
> powerPreference: "high-performance"
> });
> renderer.setPixelRatio(window.devicePixelRatio);
> renderer.setClearColor(0x000000, 0.0);
> renderer.setSize(window.innerWidth, window.innerHeight);
> renderer.setAnimationLoop(animate);
> document.body.appendChild(renderer.domElement);
> 
> scene = new THREE.Scene();
> scene.background = new THREE.Color(0xcccccc)
> 
> camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100000);
> camera.position.set(1000, 1000, 1000);
> 
> controls = new OrbitControls(camera, renderer.domElement);
> controls.enableDamping = true;
> 
> stats = new Stats();
> document.body.appendChild(stats.dom);
> 
> window.scene = scene;
> window.renderer = renderer;
> window.camera = camera;
> 
> const light = new THREE.HemisphereLight(0xe9c0a5, 0x0175ad, 5);
> scene.add(light);
> 
> const dirLight = new THREE.DirectionalLight(0xfff9ea, 4);
> dirLight.position.set(2, 5, 2);
> scene.add(dirLight);
> 
> const axesHelper = new THREE.AxesHelper(500);
> scene.add(axesHelper);
> 
> window.addEventListener('resize', onWindowResize);
> onWindowResize();
> 
> loadGltf();
> }
> 
> function loadGltf() {
> // Note: Perhaps you need to switch to a corresponding model dataset. When we compared it with our own business data, the frame rate dropped by about 4 frames. The model below is for example
> const url = \`https://threejs.org/examples/models/gltf/LittlestTokyo.glb\`;
> 
> const dracoPath = 'https://raw.githack.com/mrdoob/three.js/dev/examples/jsm/libs/draco/gltf/';
> const gltfLoader = new GLTFLoader();
> const dracoLoader = new DRACOLoader();
> dracoLoader.setDecoderPath(dracoPath);
> dracoLoader.preload();
> gltfLoader.setDRACOLoader(dracoLoader);
> console.log('start load gltf');
> console.time('load gltf');
> 
> let materialUUIDMap = new Map();
> gltfLoader.load(url, function (data) {
> const mesh = data.scene;
> console.timeEnd('load gltf');
> mesh.traverse(child =\> {
> if (child.isMesh) {
> let material = child.material;
> if (!materialUUIDMap.has(material.uuid)) {
> const {
> uuid,
> name,
> side,
> map,
> roughness,
> metalness
> } = material;
> const nodeMaterial = new THREE.MeshStandardNodeMaterial({
> name,
> side,
> map,
> roughness,
> metalness,
> });
> materialUUIDMap.set(uuid, nodeMaterial);
> }
> 
> child.material = materialUUIDMap.get(material.uuid);
> child.material.needsUpdate = true;
> material.dispose();
> material = undefined;
> }
> })
> // gltfMesh = mesh;
> for (var i = 0; i \< 15; i++) {
> let clonemesh = mesh.clone()
> 
> scene.add(clonemesh);
> }
> 
> // scene.add(mesh);
> materialUUIDMap.clear();
> materialUUIDMap = undefined;
> })
> }
> 
> function onWindowResize() {
> 
> camera.aspect = window.innerWidth / window.innerHeight;
> camera.updateProjectionMatrix();
> 
> renderer.setSize(window.innerWidth, window.innerHeight);
> 
> 
> }
> 
> function animate() {
> 
> stats.update();
> 
> controls.update();
> 
> renderer.render(scene, camera);
> 
> 
> }
> 
> 
> \</script\>
> \</body\>
> 
> \</html\>
> \`\`\`
> 
> 
> \### Live example
> 
> \-
> 
> 
> \### Screenshots
> 
> \_No response\_
> 
> \### Version
> 
> r171,r178,dev
> 
> \### Device
> 
> Desktop
> 
> \### Browser
> 
> Chrome
> 
> \### OS
> 
> Windows
