I'm having a problem where the InstancedMesh method setMatrixAt
seems to fail (the matrix positions doesn't change visually) whenever I add another object with the same material object (not a clone) in the scene. No log/warning/errors are emitted.
The following briefly illustrates:
var geometry = new THREE.BoxBufferGeometry();
var material = new THREE.MeshStandardMaterial( { roughness: 0, envMap: texture });
var mesh1 = new THREE.Mesh( geometry, material );
mesh1.position.set(0, 1, 0);
scene.add( mesh1 ); // removing this line makes the instanced mesh work as intended
mesh = new THREE.InstancedMesh( geometry, material, 9 ); // same material usage
scene.add( mesh ); // This works and I can see both meshes in the scene.
var dummy = new THREE.Object3D();
dummy.position.set( 1, 5, 1 );
dummy.updateMatrix();
mesh.setMatrixAt( 0, dummy.matrix ); // Nope, doesn't work, it just stays where it's at.
mesh.setMatrixAt( 1, dummy.matrix ); // Rotation seems to be applied, but position doesn't.
// It looks like every instance is at the same place, but I don't know.
Note that if I use material.clone() at the instanced mesh declaration, the problem also goes away / is fixed, but now I have two materials, and I intend to have one for performance reasons.
A live example is available here:
(Not applicable, as far as I know)
I have not checked whether other OS'es or Browsers have this issue, I just confirmed it on Windows, both Chrome and Edge.
Yeah, known issue. Haven't made that work yet.
Not sure if that is a related issue or intended behaviour, but I also have problems re-usinng the BufferGeometry
passed into InstancedMesh
. For example when using one geometry for two InstancedMesh
es, neither renders, and there is also no warnings or errors.
@s-ol Interesting. Do you mind putting together a jsfiddle?
@mrdoob sure, here you go: http://jsfiddle.net/x7Lzvqte/
you can toggle the red & green batches on and off individually with the bools at the top.
When either one is on it works as expected (red on the left or green on the right), but when both are on only the green one renders, and it renders on the left side.
I've debugged the issue a bit and found out that the bug refers to the same root cause mentioned here: https://github.com/mrdoob/three.js/issues/17959#issuecomment-562846047.
The renderer needs the ability to manage multiple shader programs per material, see #15047. Currently there is always a 1:1 relationship (which is somewhat wrong since material properties are not the only factors which determine the correct shader program). So the renderer assumes it can reuse the same shader for both the mesh and instanced mesh.
The renderer needs the ability to manage multiple shader programs per material. Currently there is always a 1:1 relationship...
Or alternatively, a property on the material that enables instancing, similar to the relationship between .skinning=true and THREE.SkinnedMesh. I鈥檓 not sure which solution is better but would prefer consistency. 馃
but now I have two materials, and I intend to have one for performance reasons.
Note that in any outcome here, you really do need two shader programs for this situation. You might find that using an InstancedMesh with count=1 for the second object avoids this, not sure if there should be any side effects of that...
I just got bit by this as well. A note in the docs while the fix is underway would be great.
https://threejs.org/docs/#api/en/objects/InstancedMesh
@mracette Good point. Let me update the docs.
Most helpful comment
@mracette Good point. Let me update the docs.