Instanced interleaved buffer attribute

Hi, I’m using a library that gives me back such buffer:

Uint32Array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, ....])

Those are the individual data for an instance. Each instance has two attributes. I want to map them to those attributes in my vertex shader:

attribute uint attrib1;
attribute uint attrib2;

My attempt was to create an InstancedBufferGeometry

But then, there’s no such thing as a InstancedInterleavedBufferAttribute!

In the InterleavedBufferAttribute I can set the element size and the offset in an element for the attribute, but I cannot set the mesh per attribute.

In the InstancedBufferAttribute I can set the mesh per attribute, but I can’t set the offset, but I can strangely set a stride (itemSize)

My intension was to create something like that:

const arraybuffer = Uint32Array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7]);
const geometry = new THREE.InstancedBufferGeometry();

// attribute 1 is from the buffer of 2 item per mesh, 0 in offset, 1 mesh per attribute
geometry.setAttribute('attrib1', new THREE.InstancedInterleavedBufferAttribute(arraybuffer, 2, 0, 0, 1));

// attribute 2 is from the same buffer of 2 items per mesh, but 1 in offset and still 1 mesh per attribute
geometry.setAttribute('attrib2', new THREE.InstancedInterleavedBufferAttribute(arraybuffer, 2, 1, 0, 1));

// Instances are rendered with the following data
// instance1: attrib1 = 0, attrib2 = 0
// instance2: attrib1 = 1, attrib2 = 1
// instance3: attrib1 = 2, attrib2 = 2
// instance4: attrib1 = 3, attrib2 = 3
// instance5: attrib1 = 4, attrib2 = 4
// instance6: attrib1 = 5, attrib2 = 5
// instance7: attrib1 = 6, attrib2 = 6
// instance8: attrib1 = 7, attrib2 = 7

Any clues on what I’m supposed to use to send the correct metadata to threejs so it setup the buffers correctly? Thanks.

You missed the using of InstancedInterleavedBuffer.

A very simplified example for two instanced attributes, based on a single buffer is:

const arraybuffer = new Uint32Array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7]);
const geometry = new THREE.InstancedBufferGeometry().copy(new THREE.BoxGeometry(1, 1, 1));
geometry.instanceCount = Infinity;
const iIB = new THREE.InstancedInterleavedBuffer(arraybuffer, 2, 1); // this part is important
geometry.setAttribute("attr1", new THREE.InterleavedBufferAttribute(iIB, 1, 0));
geometry.setAttribute("attr2", new THREE.InterleavedBufferAttribute(iIB, 1, 1));

let material = new THREE.MeshLambertMaterial({
  color: 0xff0000,
  //wireframe: true,
  onBeforeCompile: shader => {
    shader.vertexShader = `
      attribute uint attr1;
      attribute uint attr2;
      ${shader.vertexShader}
    `.replace(
      `#include <begin_vertex>`,
      `#include <begin_vertex>
        transformed.xy += vec2(attr1, attr2); // check, that it's working
      `
    );
    console.log(shader.vertexShader)
  }
});

let mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

Demo: https://codepen.io/prisoner849/pen/NWMzgjw?editors=0010

1 Like

It totally worked, thank you very much!

@gracicot
You’re welcome :handshake:

1 Like