Dispose/Update attribute efficiently

Our workflow is rather unconventional. We want to stream long GLTF animations to the user. Since that’s not supported in GLTF, I’m using gltf-Transform to extract morphAttributes on server side and incrementally load them at the client. Our animations require only 1 active morphTarget at a time.

So, I’m doing this instead:

  • Fetch basis geometry first (geometry with only position and uv attributes)
  • Fetch morphAttribute buffers from server.
  • Set the corresponding morphAttribute as custom attribute on the geometry based on currentTime.
  • With the vertex shader, modify the gl_Position like this:
localPosition.x = position.x + customAttr.x;
localPosition.y = position.y + customAttr.y;
localPosition.z = position.z + customAttr.z;
gl_Position = projectionMatrix * modelViewMatrix * localPosition;

This works well, but the issue is, I can’t figure out how to properly dispose the old customAttr from webgl context. When customAttr is set to new attribute, I want to dispose the old customAttr.

Extra info

So, How to manage the attributes disposal properly? I’m open to a radically different approach too. Thank you.

The question is why do you have to call dispose() on your custom attribute in the first place? Why can’t you keep it and just replace the data during the animation? This should be the most efficient solution since you can set the usage of the attribute to dynamic draw usage like so:

customAttr.setUsage( THREE.DynamicDrawUsage);

This allows browser to optimized the buffer upload since you don’t do this once but repeatedly when new data come in. Besides, you avoid buffer allocation and disposal which are more expensive operations than just a simple data upload.

3 Likes

Ohh! I didn’t know about DynamicDrawUsage. I just tested it now, and I don’t see any improvements in performance with it. I also tested with StreamDrawUsage, with no noticable difference. I’m updating the buffers like so:

geometry.attributes.customAttr.data.set(morphsB.data.array);
geometry.attributes.customAttr.needsUpdate = true;

I’m comparing the performance with when I’m setting the attributes directly like below. This approach is resulting in smoother animation:

geometry.attributes.customAttr = newAttr;
geometry.attributes.customAttr.needsUpdate = true;

I’ve read at these places that if webgl is working with that attribute at the moment (in this case it is), the gl.bufferSubData call stalls, which affects performance.

So, this is what I think might be happening (and reason for difference in performance):

  • When updating the attribute directly, gl.bufferData is called. Meanwhile, webgl is rendering/using the existing buffer without interuption. After it finishes, it can just change the bindings, since it has the newer buffer with it already.
  • When updating the attribute contents (setting the array), It only calls gl.bufferSubData. webgl is currently working with existing attribute and it received a request to update that attribute. Someone has to wait and thus the lag in performance.

I’m clueless how to resolve this cycle. The only way I see is, if there is dispose() method on attributes, I can dispose the attributes “after sometime” or just after I updated the attribute. Not sure if it’s okay to ping you now. Sorry If it isn’t. @Mugen87