iOS/ARKIT开发:实现带动画的3D模型前后切换及幻灯片展示
没问题,我来帮你搞定这个AR幻灯片式的3D模型展示功能!下面是完整的实现方案,从思路到代码都给你梳理清楚:
核心实现思路
- 先维护一个模型数据集合,每个条目包含模型文件名、对应展示文本、动画名称(可选)
- 用索引变量跟踪当前展示的模型位置,初始指向「闲置模型」的索引
- 点击「上一个/下一个」按钮时,更新索引并触发模型加载逻辑
- 加载新模型时,先清空当前AR场景内容,再加载模型、播放指定时长的动画,同步更新Label文本
- 实时控制按钮可用性,避免索引越界
完整代码示例(Swift)
import ARKit import UIKit class ARSlideShowVC: UIViewController { // MARK: - UI组件 @IBOutlet weak var arSceneView: ARSCNView! @IBOutlet weak var modelDescLabel: UILabel! @IBOutlet weak var prevBtn: UIButton! @IBOutlet weak var nextBtn: UIButton! // MARK: - 模型数据结构 struct ModelItem { let modelFileName: String let displayText: String let animationName: String? // 支持无动画的模型 } // MARK: - 核心变量 private var currentIndex = 0 private let modelLibrary: [ModelItem] = [ // 初始展示的闲置模型 ModelItem(modelFileName: "IdleModel", displayText: "闲置状态模型", animationName: nil), // 其他模型示例 ModelItem(modelFileName: "SportsCar", displayText: "高性能跑车", animationName: "DriveLoop"), ModelItem(modelFileName: "Robot", displayText: "智能机器人", animationName: "WaveAnimation"), ModelItem(modelFileName: "Flower", displayText: "生长的花朵", animationName: "BloomAnimation") ] override func viewDidLoad() { super.viewDidLoad() // 初始化AR场景基础配置 setupARScene() // 加载初始闲置模型 loadCurrentModel() // 初始化按钮状态(初始时上一个按钮禁用) updateButtonAvailability() } // MARK: - AR场景初始化 private func setupARScene() { arSceneView.delegate = self arSceneView.scene = SCNScene() // 开启默认光照,让模型显示更自然 arSceneView.autoenablesDefaultLighting = true // 可选:开启统计信息用于调试 arSceneView.showsStatistics = true } // MARK: - 按钮点击事件 @IBAction func prevBtnTapped(_ sender: UIButton) { guard currentIndex > 0 else { return } currentIndex -= 1 loadCurrentModel() updateButtonAvailability() } @IBAction func nextBtnTapped(_ sender: UIButton) { guard currentIndex < modelLibrary.count - 1 else { return } currentIndex += 1 loadCurrentModel() updateButtonAvailability() } // MARK: - 更新按钮可用状态 private func updateButtonAvailability() { prevBtn.isEnabled = currentIndex > 0 nextBtn.isEnabled = currentIndex < modelLibrary.count - 1 } // MARK: - 加载当前索引对应的模型 private func loadCurrentModel() { let currentItem = modelLibrary[currentIndex] // 1. 更新展示文本 modelDescLabel.text = currentItem.displayText // 2. 清空当前场景的所有节点 arSceneView.scene.rootNode.enumerateChildNodes { node, _ in node.removeFromParentNode() } // 3. 加载3D模型文件 guard let modelScene = SCNScene(named: "\(currentItem.modelFileName).scn") else { print("模型加载失败:\(currentItem.modelFileName)") // 实际项目中可以添加UI提示,比如弹出Alert return } // 将模型节点添加到场景根节点 let modelNode = SCNNode() modelScene.rootNode.childNodes.forEach { modelNode.addChildNode($0) } // 设置模型位置:放在相机前方1米处,高度居中 modelNode.position = SCNVector3(0, 0, -1) arSceneView.scene.rootNode.addChildNode(modelNode) // 4. 播放指定动画(如果存在) guard let animName = currentItem.animationName else { return } if let animation = modelScene.animation(forKey: animName) { animation.duration = 3.0 // 设置动画播放时长为3秒 animation.autoreverses = false // 不循环播放 modelNode.addAnimation(animation, forKey: "activeAnimation") } } } // MARK: - ARSCNViewDelegate(可选,处理AR会话回调) extension ARSlideShowVC: ARSCNViewDelegate { func session(_ session: ARSession, didFailWithError error: Error) { print("AR会话出错:\(error.localizedDescription)") } }
关键细节说明
- 模型文件准备:确保你的
.scn格式模型和动画文件已添加到Xcode项目,并勾选了对应的target - 动画自定义:如果需要循环播放动画,可以设置
animation.repeatCount = .infinity;需要停止动画时调用modelNode.removeAnimation(forKey: "activeAnimation") - AR场景优化:示例中模型放在相机前方1米,你可以根据需求调整
modelNode.position;如果需要平面检测,可以添加ARWorldTrackingConfiguration并启动AR会话 - 错误处理:代码中添加了模型加载失败的日志,实际项目建议补充用户可见的错误提示(比如弹窗)
- 性能优化:频繁切换模型时,可以提前预加载模型资源,避免加载等待时间
内容的提问来源于stack exchange,提问作者jon
相关产品推荐
相关产品推荐

