`InstancedBufferGeometry` set matrix

I want to draw cylinders edges so instead of using a InstancedMesh I want to use a InstancedBufferGeometry as its attributes can be reused for the edges.

But I’m having a problem: the cylinders aren’t drawn.

The cylinders matrix is an equivalent to new Matrix4().setPosition(...).lookAt(...).scale(1, 1, cylinderHeight).

My code is the following:

const cylindersCenters = new Float32Array(coords.length / 2 * 16);

const up = new Vector3(0, 1, 0);

for (let i = 0; i < coords.length / 2; i++) {
	const startCoordinate = new Vector3(...coords[i * 2]);
	const endCoordinate = new Vector3(...coords[i * 2 + 1]);

	const cylinderHeight = startCoordinate.distanceTo(endCoordinate);

	const z = new Vector3().subVectors(endCoordinate, startCoordinate);
	const x = new Vector3().crossVectors(up, z);
	const y = new Vector3().crossVectors(z, x);

	cylindersCenters[i * 8] = x.x;
	cylindersCenters[i * 8 + 1] = x.y;
	cylindersCenters[i * 8 + 2] = x.z;
	cylindersCenters[i * 8 + 4] = y.x;
	cylindersCenters[i * 8 + 5] = y.y;
	cylindersCenters[i * 8 + 6] = y.z;
	cylindersCenters[i * 8 + 8] = z.x * cylinderHeight;
	cylindersCenters[i * 8 + 9] = z.y * cylinderHeight;
	cylindersCenters[i * 8 + 10] = z.z * cylinderHeight;

	cylindersCenters[i * 8 + 12] = startCoordinate.x;
	cylindersCenters[i * 8 + 13] = startCoordinate.y;
	cylindersCenters[i * 8 + 14] = startCoordinate.z;

	cylindersCenters[i * 8 + 15] = 1;
}

const cylinderGeometry = new InstancedBufferGeometry().copy(new CylinderGeometry());

cylinderGeometry.instanceCount = coords.length / 2;

cylinderGeometry.setAttribute(
	'instanceMatrix',
	new InstancedBufferAttribute(cylindersCenters, 4)
);

const cylinders = new Mesh(
	cylinderGeometry,
	new MeshLambertMaterial({
		onBeforeCompile: (shader) => {
			shader.vertexShader = `
				attribute mat4 instanceMatrix;

				void main() {
					vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4(position, 1.0);

					gl_Position = projectionMatrix * mvPosition;
				}
			`;
			shader.fragmentShader = `
				void main() {
					gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
				}
			`;
		}
	})
);

What I’m doing wrong?

Hi!
As an option: Using Instancing for EdgeGeometry / LineSegments - #7 by prisoner849

Thanks, @prisoner849, but I found a faster solution. Instead of passing the whole matrix, calculate it inside the shader, passing to it the beginning and end of the cylinders.

Also, I discovered why the code wasn’t working: I was passing the matrix with the size 4, it should be 16, but three.js doesn’t allow 16 (what made me think that it should be 4).

In the end, this don’t be implemented was even good, bytes saved.