Swift中实现AR场景下车身随车轮联动移动与旋转的方法
Hey there! Let's get those wheels spinning in sync with your AR car's movement—here's a straightforward approach based on your existing code:
Step 1: Save References to Your Wheel Nodes
First, you need to grab and store references to the wheel nodes in your car model so you can manipulate them later. Use the node names from your 3D model (adjust these names to match your actual model's wheel nodes):
// Add these properties to your class var carNode: SCNNode? var frontLeftWheel: SCNNode? var frontRightWheel: SCNNode? var rearLeftWheel: SCNNode? var rearRightWheel: SCNNode? // Update your touchesBegan method to save these references override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { let touchLocation = touch.location(in: sceneView) let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent) if let hitResult = results.first { let boxScene = SCNScene(named: "art.scnassets/porsche.scn")! carNode = boxScene.rootNode.childNode(withName: "car", recursively: true) guard let carNode = carNode else { return } // Save wheel nodes (use YOUR model's actual wheel node names) frontLeftWheel = carNode.childNode(withName: "frontLeftWheel", recursively: true) frontRightWheel = carNode.childNode(withName: "frontRightWheel", recursively: true) rearLeftWheel = carNode.childNode(withName: "rearLeftWheel", recursively: true) rearRightWheel = carNode.childNode(withName: "rearRightWheel", recursively: true) // Position the car as before carNode.position = SCNVector3( x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y + 0.15, z: hitResult.worldTransform.columns.3.z ) sceneView.scene.rootNode.addChildNode(carNode) } } }
Step 2: Track Car Position & Calculate Movement Distance
To sync wheel rotation with movement, you need to measure how far the car moves each frame. Add a property to track the car's previous position, then calculate the distance traveled when moving the car:
// Add this property to your class var lastCarPosition: SCNVector3? // Example method for moving the car forward (attach this to your accelerate button) func accelerateCar(speed: Float) { guard let carNode = carNode else { return } // Define forward direction (adjust based on your model's orientation—most models use -z for forward) let forwardDir = SCNVector3(0, 0, -1) let movement = forwardDir * speed * Float(1/60) // Adjust for 60fps refresh // Update car position let newPosition = carNode.position + movement carNode.position = newPosition // Calculate distance traveled and update wheels if let lastPos = lastCarPosition { let distance = calculateDistance(from: lastPos, to: newPosition) rotateWheels(distance: distance, isForward: true) } // Save current position for next frame lastCarPosition = newPosition } // Helper function to calculate 3D distance between two points func calculateDistance(from a: SCNVector3, to b: SCNVector3) -> Float { let dx = a.x - b.x let dy = a.y - b.y let dz = a.z - b.z return sqrt(dx*dx + dy*dy + dz*dz) }
Step 3: Rotate Wheels Based on Movement
Wheels rotate based on the distance traveled—each full rotation equals the wheel's circumference (2πr). Adjust the wheel radius to match your model's actual size:
func rotateWheels(distance: Float, isForward: Bool) { // Replace this with your wheel's actual radius (measure from your 3D model!) let wheelRadius: Float = 0.3 // Calculate rotation angle: distance / radius (since circumference = 2πr, angle = distance/r) var rotationAngle = distance / wheelRadius if !isForward { rotationAngle *= -1 } // Reverse rotation for reverse // Update wheel rotation (adjust the axis if needed—most wheels rotate around the x-axis) frontLeftWheel?.eulerAngles.x += rotationAngle frontRightWheel?.eulerAngles.x += rotationAngle rearLeftWheel?.eulerAngles.x += rotationAngle rearRightWheel?.eulerAngles.x += rotationAngle }
Step 4: Add Steering Logic (Bonus!)
For your steering buttons, you can rotate the front wheels around the y-axis (adjust direction based on your model):
func steerLeft(angle: Float) { frontLeftWheel?.eulerAngles.y += angle frontRightWheel?.eulerAngles.y += angle } func steerRight(angle: Float) { frontLeftWheel?.eulerAngles.y -= angle frontRightWheel?.eulerAngles.y -= angle }
Key Tips to Get It Right
- Double-check node names: Your 3D model's wheel nodes might have different names (e.g., "Wheel_Front_L")—use your printed
boxNode.childNodesoutput to find the correct names. - Adjust wheel radius: If wheels spin too fast/slow, tweak the
wheelRadiusvalue to match your model's actual scale. - Fix rotation direction: If wheels spin backward when moving forward, swap the
+=to-=in the rotation code. - Handle reverse movement: Call
rotateWheels(distance: ..., isForward: false)in your reverse button action.
内容的提问来源于stack exchange,提问作者PvDev

