Skip to content

Conversation

@sunag
Copy link
Collaborator

@sunag sunag commented Nov 11, 2025

Related issue: #30560 (comment), #30560 (comment), #26673 (comment)

Description

This is a WIP.

The basic idea is to group the RenderObject so that we can handle similar objects.

Today we have a lot of redundant calls between similar objects in the rendering call that could be resolved in just one Backend.draw().

  • Improve RenderObject grouping

    • Add a key related to the object to separate properties relevant to shader creation, such as object.morphTargetInfluences and object.count for filterObjects, RenderObjects.get and RenderObject.getChainArray().
    • Remove the term RenderObject.instances and leave only RenderObject.objects
    • Implement the dispose logic
  • Create shared buffer

    • Create an extended buffer class designed to couple multiple uniforms.
    • Integrate shared buffer initially for modelWorldMatrix.
      • Introduce objectIndex
      • Introduce mediumpModelWorldMatrix
    • The buffer node is not being shared properly when shared with other materials, causing the buffer to be updated more than once in the same render call. WebGPURenderer: Improve cache bindings from node uniforms #32244
    • buffer does not have an integrated updateRanges range, which can be a problem if used in conjunction with instances since InstanceNode does not distinguish it with an attribute. WebGPURenderer: Add update ranges for bindings #32248
      // Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute.
      if ( count <= 1000 ) {
      instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
      } else {

@github-actions
Copy link

github-actions bot commented Nov 11, 2025

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 350.9
83.23
350.9
83.23
+0 B
+0 B
WebGPU 616.15
171.03
618.22
171.92
+2.07 kB
+891 B
WebGPU Nodes 614.75
170.76
616.82
171.67
+2.07 kB
+903 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 482.96
118.03
482.96
118.03
+0 B
+0 B
WebGPU 686.81
186.58
689.68
187.72
+2.87 kB
+1.14 kB
WebGPU Nodes 636.65
173.8
639.52
174.89
+2.87 kB
+1.09 kB


import * as THREE from 'three/webgpu';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { texture, uv, userData, fog, rangeFogFactor, color, context } from 'three/tsl';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import context.
} );*/
document.body.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable controls.
for ( let i = 0, l = group.children.length; i < l; i ++ ) {

const sprite = group.children[ i ];
const scale = Math.sin( time + sprite.position.x * 0.01 ) * 0.3 + 1.0;

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable scale.

import * as THREE from 'three/webgpu';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { texture, uv, userData, fog, rangeFogFactor, color, context } from 'three/tsl';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import context.
} );*/
document.body.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable controls.
for ( let i = 0, l = group.children.length; i < l; i ++ ) {

const sprite = group.children[ i ];
const scale = Math.sin( time + sprite.position.x * 0.01 ) * 0.3 + 1.0;

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable scale.
import { cameraViewMatrix } from './Camera.js';
import { Matrix3 } from '../../math/Matrix3.js';
import { objectIndex } from '../core/IndexNode.js';
import { instancedDynamicBufferAttribute } from '../accessors/BufferAttributeNode.js';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import instancedDynamicBufferAttribute.
@sunag
Copy link
Collaborator Author

sunag commented Dec 7, 2025

I've included [two identical examples] using 10k sprites without instances, (1eb6d6d) for testing purposes, one using the current build and the other using the source code from the new code.

I'm excited about the results;
/cc @Mugen87 @mrdoob

New - 144~ FPS

image

Current - 30~ FPS

image


}

const updateObjects = ( objects ) => {

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable updateObjects.
@sunag sunag added this to the r183 milestone Dec 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant