-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GLTFLoader: add arbitrary property animation through KHR_animation_pointer support #24108
base: dev
Are you sure you want to change the base?
Conversation
The name of the extension is kind of confusing. |
Fully agree – it has been renamed a couple of times already and the name hasn't necessarily gotten better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 Thanks for opening this PR @hybridherbst! We'd likely want to wait on merging anything until the extension is ratified, or nearly so. It's helpful to see how this might look for discussion in the meantime.
The features required by KHR_animation_pointer are pretty complex to support (nothing wrong with this PR, it is just a very complex extension in practice) and so I'll flag a few likely issues in comments below.
examples/jsm/loaders/GLTFLoader.js
Outdated
const pathStart = path.substring( 0, pathIndex ); | ||
targetProperty = path.substring( pathIndex ); | ||
|
||
// TODO implement all properties and/or find a better way to have a good mapping here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Supporting all properties may be a non-goal for three.js I think. Especially as animated extension properties come into the mix. We can try to support whichever properties seem helpful to three.js users, and are not overly complex to include.
No need to change these in the draft PR now, but a few things to flag:
- alphaCutoff animation can trigger shader recompilation
- we have very limited support for UV transforms, all textures except aoMap must share the same transform. I wonder if we should avoid animating those properties until that is improved.
- metallicFactor seems unlikely to be animated much?
examples/jsm/loaders/GLTFLoader.js
Outdated
targetProperty = 'morphTargetInfluences'; | ||
break; | ||
|
||
// TODO matrix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think animation is required to target TRS properties, not a matrix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. @UX3D-nopper is /matrix
intentionally included in KHR_animation_pointer?
examples/jsm/loaders/GLTFLoader.js
Outdated
targetProperty = 'far'; | ||
break; | ||
case 'aspect': | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above, will have to call camera.updateProjectionMatrix()
after any of these changes.
I'm not sure what I think about animation of the aspect ratio. glTF lacks any meaningful way to express "let the camera inherit the aspect ratio from the application", animating this property kind of seems like stacking blocks on top of something that is already not working properly.
examples/jsm/loaders/GLTFLoader.js
Outdated
if ( useExtension ) | ||
nodeDependency = this.getAnimationPointerDependency( target ); | ||
else | ||
nodeDependency = this.getDependency( 'node', name ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the larger hurdles on this extension will be that glTF definitions do not translate 1:1 into three.js objects —
- Materials will be cloned depending on the context in which they're used. The same glTF material applied to (1) points, (2) lines, (3) mesh with vertex colors, (4) mesh with vertex normals, (5) mesh with vertex tangents, will result in 5x copies of the material.
- Lights and Cameras will be cloned if they're attached at >1 Node.
- Probably similar for KHR_audio if that gets ratified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have an idea on how to tackle these in the context of this extension? I'd assume that when they are split, the correct additional tracks would need to be created.
I first thought one could be keeping some importUUID
around, which could then be used during findNode
to map back to objects, but I don't think one track can target multiple objects (by design).
examples/jsm/loaders/GLTFLoader.js
Outdated
parts[ 2 ] = node.uuid; | ||
animationPointerPropertyPath = parts.join( '.' ); | ||
if ( animationPointerDebug ) | ||
console.log( node, inputAccessor, outputAccessor, target, animationPointerPropertyPath ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trouble with targeting animation to the UUID is that many users will clone the model before attaching one or more copies to their scene. The cloned objects will have new UUIDs, and so the same animation clips cannot target them. We prefer to target based on unique names for that reason, but glTF doesn't require unique names. And in this case (see above) we may need to animate multiple objects, even if only a single source glTF definition was animated. 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to node.name ?? node.uuid
, similar to other places.
Hi, thanks for working on it. I didn't look into the spec and change deeply yet, but let me share my rough thoghts so far.
|
examples/jsm/loaders/GLTFLoader.js
Outdated
}; | ||
|
||
// HACK monkey patching findNode to ensure we can map to other types required by KHR_animation_pointer. | ||
const find = PropertyBinding.findNode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think monkey patching is a good idea. Maybe good to consider either
- Update the core
findNode
- Give up the perfect extension support and consider partial feature support that the existing
findNode
can handle - If we really need monkey patching, it may be good to do it only if
KHR_animation_pointer
extension is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing findNode
can't handle most of what animation_pointer requires unfortunately. I agree that it would be better to update findNode
as mentioned in my original post, looking forward to ideas which parts should move there. Ideally there's a callback that for example extensions can tap into.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the implementation to only monkey patch if the extension is actually used.
examples/jsm/loaders/GLTFLoader.js
Outdated
|
||
let nodeDependency = undefined; | ||
if ( useExtension ) | ||
nodeDependency = this.getAnimationPointerDependency( target ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be good to consider the plugin system for handling a extension. It provides an extensibility while it keeps the simplicity for processing the glTF core in the loader unless the extension handler really needs to be in the loader core. If the current Plugin API doesn't fit to process the extension, please consider to propose a good new API for handling animation extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as written in my original message that was the plan.
I now refactored it to be contained entirely in an animation, and added two new callbacks, see
9743045
to
7e0d1de
Compare
I believe the support added here is now "feature complete" for the core spec and all currently ratified extensions (minus some texture transforms that three doesn't support anyways). There's still open questions regarding the currently required use of PropertyBinding/monkey patching, and what to do when materials and/or lights/cameras are duplicated during import (and would thus require creating multiple tracks). Looking for input on these! I refactored everything into a self-contained extension (
|
Made a separate PR with the required callbacks to allow for KHR_animation_pointer: |
6f69066
to
d6adc29
Compare
3c019f1
to
b9a0b83
Compare
The PRs that would need to be merged so |
I think I would prefer that we exclude KHR_animation_pointer from the threejs repository unless/until it has started the ratification process with Khronos. I'm not aware if it's more than a proposal at this stage. Adding hooks or other extension API changes required to support the extension externally, as in the other PRs, would be welcome. |
Understood. You are right that it's currently just a proposal, however, both Gestaltor and Babylon have already implemented it and there's multiple sample assets that I made. I'll ask what the blocker is for moving forward. |
b9a0b83
to
1a881e9
Compare
1a881e9
to
2d05374
Compare
b7504d6
to
3e5ac4c
Compare
add some TODO comments, rename pointer path property wip support for camera and light properties, added morph target support formatting, fix alphaTest, add opacity track splitting added some comments, added some material ext animation properties fixed Ior > IOR, test switching to node names to avoid duplication problems (but incomplete yet, needs full paths) fix: use "pointer" property instead of "path" refactor: move to extension, add new callbacks move remaining pieces into extension, rename methods fix: orthographic/perspective camera, pbrMetallicRoughness prefix, clearcoat/sheen/specular extensions rm change on PATH_PROPERTIES only patch PropertyBindings if KHR_animation_pointer is actually used fix: fall back to original findNode implementation earlier if special cases don't yield results introduce animationPointerResolver to allow configuring KHR_animation_pointer from outside fix: glTF camera fov is in radians, not degrees fix: use QuaternionKeyframeTrack instead of ColorKeyframeTrack if property ends with .quaternion use extension hooks
3e5ac4c
to
1152049
Compare
@hybridherbst just as an FYI, on my end I have dared using your GLTF Loader version from this PR in my GLTF Viewer and it seems to be working fine for the Animate All The Things example that you have available for testing. Whenever you might get back to dealing with this arbitrary extension, and in addition to the warning listed by the bot above, there is one other thing to correct related to Khronos InterpolationTest example shows this correction as necessary to be fully functional. |
The good news is the glTF interactivity WG is now pushing KHR_animation_pointer as a dependency for the interactivity extension. It should be going through the ratification process shortly, which will require implementations like this. Thanks @hybridherbst! |
@GitHubDragonFly the version on our latest branch (2412881) should be better and lilkely already has that fix. @elalish happy to hear – let me know when a good time would be to pick up this PR again and bring it up to speed with our latest changes. |
@hybridherbst I think now is great - did you see that KHR_animation_pointer is going through ratification now? So there are already two implementations out there somewhere. Would be awesome to have in Three! |
The following PRs are rolled into this one and ideally are merged first:
Description
This PR adds support for KHR_animation_pointer. We wanted to put this out early for discussion. There's a good amount of refactoring to be done (especially figuring out how to do property binding in a clean/extensible way, and how to deal with animated cameras/lights/materials that three might duplicate in certain cases).
three.js fork with built drag-and-drop viewer can be found here:
https://needle.tools/three.js/examples/?q=loader_mu#webgl_loader_multiple
Some sample models are here:
KhronosGroup/glTF-Sample-Models#353
To quickly test, just download some of the GLB files from the sample-models fork and drop them into the three-js fork above :)
Known Limitations
Next steps
Before doing the remaining implementation (which mostly consists of mapping glTF JSON Pointer strings to three.js property names), I think a couple of points are worth discussing:
PropertyBinding.findNode
is monkey patched to support materials and node uuids. It may be that custom extensions need to have callbacks into this (e.g. KHR_animation_pointer wants to resolve materials). I'm unsure iffindNode
itself should be extended to support more cases or a callback mechanism be introduced (I'd prefer the callback).lights currently don't work, getDependency doesn't have 'lights' right now (another candidate for a callback forfindNode
).pendingNodes
may now contain other things than nodes (e.g. materials). Should we rename this topendingDependencies
?cc @donmccurdy @elalish @mrdoob and probably others :) I'm really looking forward to having support for this, opens up many possibilities.
Babylon and Gestaltor seem to have also started implementations.
This contribution is funded by Needle and prefrontal cortex