Pretty sure I am doing something wrong or there are some API changes but my compute function does not assign to the storage buffer.
const count = 10
const colArray = new THREE.StorageInstancedBufferAttribute(new Float32Array(count * 3), 3);
scene.children[0].children[0].instanceColor = colArray;
for (let i = 0; i < count; i++) {
colArray.array.set([1,0,0],i*3);
}
//at this point all instances are red
const computeColor = Fn(() => {
const instanceColor = storage( colArray, 'vec3', count );
instanceColor.element(instanceIndex).assign(vec3(0.0, 1.0, 0.0))
})().compute(count)
const { gl } = useThree()
gl.compute(computeColor)
// ^^ this is basically renderer.compute(computeColor), just R3F
console.log(colArray)
//at this point all instances are still red
Any idea why?
Neither using instancedArray as in this example nor StorageInstancedBufferAttribute from this comment seem to work.
I’ve managed to force an error somehow, maybe anyone encountered something similar?
ERROR: 0:142: 'assign' : l-value required (can't modify an input "nodeVarying5")
Disappears when the assign line in the shader is commented.
To read the array back from the GPU, use renderer.getArrayBufferAsync
. Both renderer.compute
and renderer.getArrayBufferAsync
are asynchronous, so you’ll need to await
them to get the resulting buffer.
The following code worked for me. Here’s a working example:
renderer
.compute(computeColor)
.then(() => renderer.getArrayBufferAsync(instanceColor.value))
.then((arrayBuffer) => {
const computedColorArray = new Float32Array(arrayBuffer);
console.log(computedColorArray);
})
or if you prefer using await
:
await renderer.compute(computeColor);
const arrayBuffer = await renderer.getArrayBufferAsync(instanceColor.value);
const computedColorArray = new Float32Array(arrayBuffer);
console.log(computedColorArray);
4 Likes
Thank you a lot! This makes sense.
1 Like
EDIT: Ignore this, it seems to be something to do with how R3F accesses the renderer, not the three.js itself.
EDIT2: for anyone using fiber, do not
const { gl } = useThree();
useFrame(() => {
gl.computeAsync(...) }
but grab renderer properly with
useFrame(({ gl }) => {
gl.computeAsync(...) }
Or getArrayBufferAsync will return zeroes after the first frame.
1 Like