Skip to content

When using the WebGPU renderer, the second call to LineSegmentsGeometry.setPositions does not take effect #31056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jellychen opened this issue May 6, 2025 · 8 comments
Labels

Comments

@jellychen
Copy link

Description

When using the WebGPU renderer, the second call to LineSegmentsGeometry.setPoints does not take effect

Reproduction steps

Add a line segment to the scene.

Code

// code goes here
const line = new LineSegments2();
line.geometry = new LineSegmentsGeometry();
line.material = new Line2NodeMaterial({....});
line.geometry.setPositions(points);

//
// render first
// everything is ok
//
render()

//
// set new positions
//
line.geometry.setPositions(points);

//
// render second
// new points is not be applyed????
//
render();

Live example

Screenshots

No response

Version

r175

Device

Desktop

Browser

Chrome

OS

MacOS

@jellychen
Copy link
Author

Currently, every time I update the position, I first ​​dispose​​ the geometry and then create a new one, which works. But could this be related to some ​​buffer management issue in WebGPU​​? Because it runs fine under ​​WebGL​​.

@Mugen87
Copy link
Collaborator

Mugen87 commented May 6, 2025

This is likely a duplicate of #30518 although we must update LineSegmentsGeometry to honor the new policy. Existing buffer attributes are not allowed to be overwritten anymore. The existing array data must be updated instead, see #30518 (comment).

@jellychen
Copy link
Author

@Mugen87
But after reading the code, I found that setPositions internally does rebuild it.
/** * Sets the given line positions for this geometry. The length must be a multiple of six since * each line segment is defined by a start end vertex in the pattern (xyz xyz)`.
*
* @param {Float32Array|Array} array - The position data to set.
* @return {LineSegmentsGeometry} A reference to this geometry.
*/
setPositions( array ) {

	let lineSegments;

	if ( array instanceof Float32Array ) {

		lineSegments = array;

	} else if ( Array.isArray( array ) ) {

		lineSegments = new Float32Array( array );

	}

	const instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz

	this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
	this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz

	this.instanceCount = this.attributes.instanceStart.count;

	//

	this.computeBoundingBox();
	this.computeBoundingSphere();

	return this;

}`

So this approach doesn't work either? Is rebuilding mandatory?

@Mugen87
Copy link
Collaborator

Mugen87 commented May 6, 2025

Ideally the implementation would not use setAttribute() twice but only once when no attributes are defined yet. When calling setPositions() a second times, the existing buffers should only be updated (and not overwritten via setAttribute()).

@jellychen
Copy link
Author

So in this case, can ​​LineSegmentsGeometry​​ only call ​​setPositions​​ once per instance? Is there no way to make new geometry data take effect by setting some kind of flag?

In the current implementation, ​​LineSegmentsGeometry​​ recreates a new ​​InstancedInterleavedBuffer​​ every time ​​setPositions​​ is called.

@jellychen
Copy link
Author

My application is performance-sensitive. In WebGL, I would pre-allocate a large buffer and use ​​drawRange​​ to dynamically adjust the rendering range, thereby minimizing VRAM allocation/deallocation. But with WebGPU, this optimization approach seems no longer viable.

@WestLangley
Copy link
Collaborator

When I introduced "fat" lines, I did not intend for users to call setPositions() more than once, and unfortunately, updating only the data values is tedious in this case.

Perhaps the implementation needs to be revisited...

@jellychen
Copy link
Author

there's a point I'm not entirely sure about. setAttribute will create a new GPUBuffer. This buffer shouldn't conflict with the previous one. Even when updating the buffer, shouldn't it be updating the buffer in memory? Before drawing, there should be a check, and then invoke WebGPU's writeBuffer.

Why wouldn't this logic work? Naively, we’d typically use triple buffering as a solution. But from what I understand, Three.js’s architecture shouldn’t need to be this complex. Are there factors I’m unaware of here?

@Mugen87 Mugen87 added the Addons label May 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants