Convert GLTF BufferedGeometry to LineSegments2

Our GLTF features an indexed BufferGeometry for all lines. Since I’d rather use Line2 than the native GL lines that GLTFLoader uses by default, we remove all Line elements and replace them with Line2.

Ideally, I’d like to convert our BufferGeometry to a LineSegmentsGeometry like so:

function toLineSegmentsGeometry(bufferGeometry: BufferGeometry)
{
	const lg = new LineSegmentsGeometry();

	const a = bufferGeometry.attributes;

	lg.setAttribute("position", a.position);
	lg.setIndex(bufferGeometry.index);

	lg.userData = bufferGeometry.userData;
	return lg;
}

But for some reason, this doesn’t work, nothing is shown, neither error nor output.

The following less nice approach does work

function toLineSegmentsGeometry(bufferGeometry: BufferGeometry)
{
	const lg = new LineSegmentsGeometry();

	const a = bufferGeometry.attributes;
	if (a.position === undefined) {
		return;
	}
	const position = a.position;
	if (!(position instanceof InterleavedBufferAttribute)) {
		return;
	}

	const data = position.data;
	if (!(data instanceof InterleavedBuffer)) {
		return;
	}
	const stride = data.stride;
	const indexAttribute = bufferGeometry.index;
	if (indexAttribute === null) {
		return;
	}
	const positions = [];
	for (let index = 0; index !== indexAttribute.array.length; ++index) {
		const i = indexAttribute.array[index] * stride;
		const x = data.array[i];
		const y = data.array[i + 1];
		const z = data.array[i + 2];
		positions.push(x, y, z);
	}

	lg.setPositions(positions);

	lg.userData = bufferGeometry.userData;
	return lg;
}

That does definitely not work. You have to use the dedicated interface for setting the position attribute. Try it like so:

const geometry = bufferGeometry.toNonIndexed(); // ensure non-indexed buffer geometry
const positionAttribute = geometry.getAttribute( 'position' );

lg.setPositions( positionAttribute );

Note that toNonIndexed() does not support interleaved geometries.

Thank you very much for your answer. The problem is that setPositions expects number[] | Float32Array, so positionAttribute does not work as such. But since we have an interleaved geometry anyway, I guess this approach wouldn’t work. So it seems unpacking and using setPositions is the only solution :frowning:

1 Like

Oh sorry, that was a mistake in my code. Yes, it’s necessary to pass in the typed array or just an ordinary array with numbers but not the attribute. So:

lg.setPositions( positionAttribute.array );

Thanks for pointing this out!