You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:19:10