在SceneKit中如何播放USDZ文件中的MDLPackedJointAnimation?
Got it, let's work through getting that MDLPackedJointAnimation playing in your SceneKit scene. The core issue here is that SceneKit doesn't automatically translate animations stored in the MDLAsset's animation collection into SCNAnimationPlayer instances attached to your node—you have to handle that conversion manually. Here's a step-by-step solution:
Step 1: Load the USDZ Asset and Extract the Animation
First, load your asset like you already are, then grab the MDLPackedJointAnimation from the asset's animation pool:
let usdzURL = Bundle.main.url(forResource: "Sitting Laughing", withExtension: "usdz")! let asset = MDLAsset(url: usdzURL) asset.loadTextures() // Fetch your character node from the asset guard let characterMDLObject = asset.object(at: 0) as? MDLMesh else { fatalError("Failed to retrieve the main mesh from the USDZ file") } let characterNode = SCNNode(mdlObject: characterMDLObject) // Pull out the MDLPackedJointAnimation instance guard let packedAnimation = asset.animations.objects.first as? MDLPackedJointAnimation else { fatalError("No MDLPackedJointAnimation found in the asset") }
Step 2: Bind the Animation to the Character's Skeleton
MDLPackedJointAnimation needs explicit mapping to your character's skeleton joints. We'll create an MDLAnimationBindComponent to link the animation's joint paths to the skeleton's bind transforms:
// Get the skeleton's bind transforms from the SceneKit node guard let skeletonBindTransforms = characterNode.skeleton?.bindTransforms else { fatalError("Character node has no attached skeleton") } // Create the bind component and attach it to the MDL mesh object let bindComponent = MDLAnimationBindComponent( jointPaths: packedAnimation.jointPaths, jointBindTransforms: skeletonBindTransforms ) asset.addComponent(bindComponent, to: characterMDLObject)
Step 3: Convert to SCNAnimation and Start Playback
Now convert the metal-focused MDLPackedJointAnimation to a SceneKit-compatible SCNAnimation, create an animation player, attach it to your node, and kick off playback:
// Convert the MDL animation to a SceneKit animation let scnAnimation = SCNAnimation(mdlAnimation: packedAnimation) // Configure animation behavior (tweak these to fit your needs) scnAnimation.usesSceneTimeBase = false // Let the animation run on its own timeline scnAnimation.repeatCount = .infinity // Loop the animation non-stop scnAnimation.fadeInDuration = 0.2 // Add a smooth start transition scnAnimation.fadeOutDuration = 0.2 // Add a smooth end transition if needed // Create an animation player and attach it to the character node let animationPlayer = SCNAnimationPlayer(animation: scnAnimation) characterNode.addAnimationPlayer(animationPlayer, forKey: "SittingLaughing") // Start the animation animationPlayer.play()
Key Details to Keep in Mind
- The
MDLAnimationBindComponentis non-negotiable—it bridges the gap between the animation's joint data and your character's skeleton, ensuring the animation applies correctly to each joint. - If your USDZ contains multiple animations, loop through
asset.animations.objectsinstead of grabbing the first one, and use unique keys when adding animation players to avoid conflicts. - You can control playback later (pause, stop, adjust speed) by fetching the
SCNAnimationPlayerinstance using the key you assigned.
内容的提问来源于stack exchange,提问作者Fattie

