question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

BufferGeometry.merge or BufferGeometryUtils.mergeBufferGeometries: Add support for transformation matrix

See original GitHub issue
Summary of feature request

.addScaledVector but instead of adding a scaled vector, merging a transformed BufferGeometry

Description of feature request

For optimization purposes, I want to render a single buffer geometry instead of rendering each object in my scene separately

const geometry = THREE.BufferGeometryUtils.mergeBufferGeometries(this.children.map(child =>
    child.geometry.clone().applyMatrix4(child.matrix) // The issue
));
this.add(new THREE.Mesh(geometry, this.children[0].material));
for (const child of this.children) {
     child.visible = false;
}

(simplified code, not tested but should convey my point)

Unfortunately, the existing buffer geometry merge methods don’t support transforming each merged vertex by a custom matrix. That means I have to clone each child’s geometry and apply the matrix to the entire clone at once.

This is a waste of memory, and could be avoided with

  • BufferGeometry.merge(bufferGeometry, optionalMatrix)
  • BufferGeometryUtils.mergeBufferGeometries(bufferGeometries, optionalMatrices)

The 2nd option is slightly more awkward but is preferred because BufferGeometryUtils is lossless (doesn’t require manual index argument)

If a matrix is passed in, each vertex being merged in should have it applied.

Note: I know I could get around this by pre-applyMatrix4-ing all my objects’ geometries, but I don’t want to do that…I want them to share a single, applyMatrix4’d buffer geometry instance.

Note 2: For my use case, each child’s BufferGeometry is the same. A solution specific to my case is :

  • BufferGeometryUtils.stamp(bufferGeometry, matrices)

Which would take a single geometry and stamp it at multiple locations/rotations/scales defined by each matrix.

Three.js version
  • Dev
  • r114

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:13 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
donmccurdycommented, Mar 23, 2020

@finnbear both your results and your code look reasonable to me.

I expect that a carefully designed function could write arbitrary objects, with arbitrary transforms, into a large geometry buffer efficiently enough to make the 50-100ms latency go away. For an imaginary BufferGeometryBuilder example:

var merged = new BufferGeometry();
merged.setAttribute( 'position', new Float32Array( 1e6 ), 3 );
merged.setAttribute( 'normal', new Float32Array( 1e6 ), 3 );
merged.setAttribute( 'uv', new Float32Array( 1e6 ), 2 );
merged.setIndex( new Uint8Array( 1e6 ), 3 );

var builder = new THREE.BufferGeometryBuilder( merged );
var offset1 = builder.append( geometry, matrix1 );
var offset2 = builder.append( geometry, matrix2 );
var offset3 = builder.append( geometry2, matrix1 );

// later
builder.update( offset2, geometry, matrix3 );

However, this sort of API seems better as a new thing, rather than a change to mergeBufferGeometries.

2reactions
donmccurdycommented, Mar 18, 2020

What do you mean by this?

bufferGeometry1.merge(bufferGeometry2) overwrites data rather than doing a union. This is rarely what users want.

That means I have to clone each child’s geometry and apply the matrix to the entire clone at once. … This is a waste of memory …

I’m not sure how we’d implement it in BufferGeometryUtils any other way, without duplicating a fair bit of code from:

  • BufferGeometry.prototype.applyMatrix4
  • BufferAttribute.prototype.applyMatrix4
  • BufferAttribute.prototype.applyNormalMatrix
  • BufferAttribute.prototype.transformDirection

I agree with @gkjohnson that InstancedMesh may be a better fit for this use case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Three.js: How to merge two BufferGeometries and keep ...
We have been doing sich merging of (mostly single objects) to maintain the transformations for JSON Object exporting.
Read more >
Rotate each buffer geometry that's merged by ... - three.js forum
I have a mesh made like this: var cubes = [] const boxGeometry = new THREE.BoxGeometry(1,1,1); const boxBufferGeometry = BufferGeometryUtils.
Read more >
Improve your Threejs performances with BufferGeometryUtils
What we need for this tutorial is the mergeBufferGeometries method. MergeBufferGeometries put every Buffergeometries with the sames attributes ...
Read more >
14b How to merge BufferGeometries three.js - YouTube
Learn how to merge different buffer geometries into a single buffer geometry to increase performance and treat different buffer geometries ...
Read more >
Three.Js: Merging Indexed Geometries Into Buffer Geometry
mergeBufferGeometries : Add support for transformation matrix ... I want to render a single buffer geometry instead of BufferGeometryUtils is ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found