3

I'm trying to send a matrix4 to the vertex shader using a THREE.InstancedBufferAttribute but I can't figure out how.

This will work:

js

// convert the geometry to an InstancedBufferGeometry
var geometry = new THREE.InstancedBufferGeometry().fromGeometry(geometry);

(...)

// transforms
var transformsCol0 = new THREE.InstancedBufferAttribute(new Float32Array(instanceCount * 4), 4, 1);
var transformsCol1 = new THREE.InstancedBufferAttribute(new Float32Array(instanceCount * 4), 4, 1);
var transformsCol2 = new THREE.InstancedBufferAttribute(new Float32Array(instanceCount * 4), 4, 1);
var transformsCol3 = new THREE.InstancedBufferAttribute(new Float32Array(instanceCount * 4), 4, 1);

// declare matrices only once outside the loop
var workingMatrix = new THREE.Matrix4();
var transformMatrix = new THREE.Matrix4();

for (var i = 0; i < instanceCount; i++) {
    var instance = instances[i];

    // transforms: translation
    transformMatrix.makeTranslation(instance.position.x, instance.position.y, instance.position.z);

    // transforms: rotation: X
    workingMatrix.makeRotationX(instance.rotation.x);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: rotation: Y
    workingMatrix.makeRotationY(instance.rotation.y);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: rotation: Z
    workingMatrix.makeRotationZ(instance.rotation.z);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: scale
    workingMatrix.makeScale(instance.scale.x, instance.scale.y, instance.scale.z);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    transformsCol0.setXYZW(i, transformMatrix.elements[0], transformMatrix.elements[1], transformMatrix.elements[2], transformMatrix.elements[3]);
    transformsCol1.setXYZW(i, transformMatrix.elements[4], transformMatrix.elements[5], transformMatrix.elements[6], transformMatrix.elements[7]);
    transformsCol2.setXYZW(i, transformMatrix.elements[8], transformMatrix.elements[9], transformMatrix.elements[10], transformMatrix.elements[11]);
    transformsCol3.setXYZW(i, transformMatrix.elements[12], transformMatrix.elements[13], transformMatrix.elements[14], transformMatrix.elements[15]);
}

geometry.addAttribute('transformsCol0', transformsCol0);
geometry.addAttribute('transformsCol1', transformsCol1);
geometry.addAttribute('transformsCol2', transformsCol2);
geometry.addAttribute('transformsCol3', transformsCol3);

shader

precision highp float;

attribute vec4 color;

attribute vec4 transformsCol0;
attribute vec4 transformsCol1;
attribute vec4 transformsCol2;
attribute vec4 transformsCol3;

varying vec4 vColor;

void main() {
    vColor = color;

    mat4 transforms = mat4(
        transformsCol0,
        transformsCol1,
        transformsCol2,
        transformsCol3
    );


    gl_Position = projectionMatrix * modelViewMatrix * transforms * vec4( position, 1.0 );
}

However this won't:

js

// convert the geometry to an InstancedBufferGeometry
var geometry = new THREE.InstancedBufferGeometry().fromGeometry(geometry);

(...)

// transforms
var transforms = new THREE.InstancedBufferAttribute(new Float32Array(instanceCount * 16), 16, 1);

// declare matrices only once outside the loop
var workingMatrix = new THREE.Matrix4();
var transformMatrix = new THREE.Matrix4();

for (var i = 0; i < instanceCount; i++) {
    var instance = instances[i];

    // transforms: translation
    transformMatrix.makeTranslation(instance.position.x, instance.position.y, instance.position.z);

    // transforms: rotation: X
    workingMatrix.makeRotationX(instance.rotation.x);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: rotation: Y
    workingMatrix.makeRotationY(instance.rotation.y);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: rotation: Z
    workingMatrix.makeRotationZ(instance.rotation.z);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    // transforms: scale
    workingMatrix.makeScale(instance.scale.x, instance.scale.y, instance.scale.z);
    transformMatrix.multiply(workingMatrix);
    workingMatrix.identity();

    transforms.set(transformMatrix.elements, i);
}

geometry.addAttribute('transforms', transforms);

shader

attribute vec4 color;
attribute mat4 transforms;

varying vec4 vColor;

void main() {
    vColor = color;

    gl_Position = projectionMatrix * modelViewMatrix * transforms * vec4( position, 1.0 );
}

When I try to run the code above I get this error in the browser console

[.Offscreen-For-WebGL-0x7ff054396800]GL ERROR :GL_INVALID_VALUE : glVertexAttribPointer: size GL_INVALID_VALUE

I couldn't find any related issue in github, but I think the creator of this example faced the same problem because of this commented-out code

Hector
  • 68
  • 7
  • Tried this yesterday and failed. Stumbled on this just now http://stackoverflow.com/questions/38853096/webgl-how-to-bind-values-to-a-mat4-attribute – pailhead Oct 18 '16 at 12:06
  • Tip: How many `Matrix4`'s are you instantiating in you code? Instead, create one instance outside the loop and reuse it -- or use a closure. – WestLangley Oct 18 '16 at 14:33
  • @WestLangley thx for the tip, will definitely do that :) – Hector Oct 19 '16 at 06:32
  • @pailhead But how could I do that using three.js's .addAttribute() ? Is there a way? – Hector Oct 19 '16 at 06:35
  • i think there might not be, i dont remember seeing a mention of that type, but it seems to be possible with webgl. Might be worth doing a pull request if possible – pailhead Oct 19 '16 at 16:22
  • Edited to improve performance as suggested by @WestLangley – Hector Oct 22 '16 at 12:26
  • @pailhead I opened a new [issue in github](https://github.com/mrdoob/three.js/issues/9916) – Hector Oct 22 '16 at 12:28

1 Answers1

1

The number of components per generic vertex attribute must be 1, 2, 3, or 4. You are trying to pass 16 components.

ref: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttribPointer.xml

three.js r.81

WestLangley
  • 102,557
  • 10
  • 276
  • 276
  • That shouldn't matter per this: http://stackoverflow.com/questions/38853096/webgl-how-to-bind-values-to-a-mat4-attribute – pailhead Oct 23 '16 at 02:59