【问题标题】:Slider over ARSCNView in ARKit (Xcode)ARKit(Xcode)中 ARSCNView 上的滑块
【发布时间】:2018-01-11 05:14:14
【问题描述】:

所以我是 Swift、Xcode 和 Arkit 的新手。 我使用 Xcode 9.2

我想构建一个简单的应用程序,当在屏幕上点击一个对象时,它会放置到它检测到一个平面或点的位置。

我启动了 Xcode,并将这段简短的代码写入了基本示例中,当您打开 scenekit 时就在该示例中。 代码如下所示:

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {
    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self

        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true

        // Create a new scene
        let scene = SCNScene(named: "art.scnassets/ship.scn")!

        // Set the scene to the view
        sceneView.scene = scene
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Create a session configuration
        let configuration = ARWorldTrackingConfiguration()

        // Run the view's session
        sceneView.session.run(configuration)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {return}
        let result = sceneView.hitTest(touch.location(in: sceneView), types: [ARHitTestResult.ResultType.featurePoint])
        guard let hitResult = result.last else {return}
        let hitTransform = SCNMatrix4.init(hitResult.worldTransform)
        let hitVector = SCNVector3Make(hitTransform.m41,hitTransform.m42,hitTransform.m43)
        createBall(position: hitVector)
    }

    func createBall(position: SCNVector3){
        var ballShape = SCNSphere(radius: 0.01)
        var ballNode = SCNNode(geometry: ballShape)

        ballNode.position = position

        sceneView.scene.rootNode.addChildNode(ballNode)
    }

    // MARK: - ARSCNViewDelegate

    func session(_ session: ARSession, didFailWithError error: Error) {
        // Present an error message to the user
    }

    func sessionWasInterrupted(_ session: ARSession) {
        // Inform the user that the session has been interrupted, for example, by presenting an overlay
    }

    func sessionInterruptionEnded(_ session: ARSession) {
        // Reset tracking and/or remove existing anchors if consistent tracking is required
    }
}

我插入了这个相关部分:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {return}
        let result = sceneView.hitTest(touch.location(in: sceneView), types: [ARHitTestResult.ResultType.featurePoint])
        guard let hitResult = result.last else {return}
        let hitTransform = SCNMatrix4.init(hitResult.worldTransform)
        let hitVector = SCNVector3Make(hitTransform.m41,hitTransform.m42,hitTransform.m43)
        createBall(position: hitVector)
    }

    func createBall(position: SCNVector3){
        var ballShape = SCNSphere(radius: 0.01)
        var ballNode = SCNNode(geometry: ballShape)

        ballNode.position = position

        sceneView.scene.rootNode.addChildNode(ballNode)
    }

这个应用程序运行良好。每次我点击屏幕时,它都会放置球。 现在我想向 Main.Storyboard 添加一个滑块,以更改要放置的球的大小值。 Main.Storyboard 如下所示:

当我在情节提要屏幕上拖动滑块时,滑块不会添加到场景中,而是将 ARSCNView 放置到全尺寸。然后它看起来像这样:

我需要做什么才能将滑块放在视图上?这是否适用于其他 UI 元素?这甚至可能吗?它是如何工作的。这可能很简单,但这是我第一次在 Xcode 中编码。

【问题讨论】:

  • 如果您不想要陡峭的学习曲线……我建议您在操场上使用小型编码 sn-ps 来学习基础知识。在掌握了各个框架的基础知识之后,你会更容易理解 xcode 的界面,尤其是 scenekit 编辑器。我在下面添加了一个游乐场,如果您想采用这种方法,它将帮助您入门。

标签: ios swift xcode arkit


【解决方案1】:

您不能将 UI 控件拖放到 ARSCNView。 (它不应该托管子视图)你需要

  1. 拖动 UIView 到你的场景,
  2. 然后将ARSCNView拖到它上面,
  3. 添加约束(例如,上、下、左、右 = 0),
  4. 将您的 ARSCNView 链接到 sceneView
  5. 添加您的滑块。确保滑块在 ARSCNView 上方(层次结构中较低),否则将隐藏在后面。

【讨论】:

  • 感谢您的帮助。所以我设法重新配置了一个新的视图控制器。您能解释一下如何在代码中将 ARSCNView 链接到 sceneView 吗?也许有截图。我查了教程,但没有找到任何东西
  • 按下 ctrl 从侧边菜单的控制器拖动到它
  • hmm 当我尝试执行此操作时,它会在 View Controller Scene ->ViewController 上方的情节提要布局中出现 View Controller Scene ->View->ARSCNView 并导致黑屏。缺少什么?
  • 检查所有元素的透明度,确保您的场景视图低于您要显示的控件(在层次结构中的早期),确保场景视图已初始化并运行。
【解决方案2】:

以编程方式在快速操场上缩放球的完整编码解决方案。

import ARKit
import UIKit
import SceneKit
import PlaygroundSupport


// Main ARKIT ViewController
class ViewController : UIViewController, ARSCNViewDelegate, ARSessionDelegate {

    var ballNode: SCNNode!
    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // set the views delegate
        sceneView.delegate = self as! ARSCNViewDelegate
       // show statistics such as fps and timing information
       sceneView.showsStatistics = true
       // Create a new scene 
       sceneView.scene.rootNode
       // Add ligthing
       sceneView.autoenablesDefaultLighting = true

        // sphere geometry
       let sphere = SCNSphere(radius: 0.1)

      //Create Node object
      ballNode = SCNNode(geometry: sphere)
        // position node in scene
     ballNode.position = SCNVector3(x: 0, y:0, z: -1)

     //  add new node to root node
     self.sceneView.scene.rootNode.addChildNode(ballNode)

     // Add an scaleSlider button
     weak var scaleSlider: UISlider! {
         didSet {
            scaleSlider.transform =  CGAffineTransform(rotationAngle: -CGFloat.pi/2)
        }
     }
     scaleSlider = UISlider()
     scaleSlider.addTarget(self, action: #selector(updateScaleWithSlider(_:)), for: .touchUpInside)
     scaleSlider.minimumValue = 0
     scaleSlider.maximumValue = 10
        // add scaleSlider to view
    sceneView.addSubview(scaleSlider)

    // Auto Layout
    scaleSlider.translatesAutoresizingMaskIntoConstraints = true
  }

 override func loadView() {

    sceneView = ARSCNView(frame:CGRect(x: 0.0, y: 0.0, width: 500.0, height: 600.0))
    // Set the view's delegate
    sceneView.delegate = self 

    let config = ARWorldTrackingConfiguration()
    config.planeDetection = .horizontal

    // Now we'll get messages when planes were detected...
    sceneView.session.delegate = self

    self.view = sceneView
    sceneView.session.run(config)

 }

 func scaleNode(value: Float) {
    SCNTransaction.begin()
    SCNTransaction.animationDuration = 1
    ballNode.scale = SCNVector3(value, value, value)
    SCNTransaction.commit()
 }

@IBAction func updateScaleWithSlider(_ sender: UISlider) {
    guard let slider = sender as? UISlider else { return }
    scaleNode(value: slider.value)
 }

}
PlaygroundPage.current.liveView = ViewController()
PlaygroundPage.current.needsIndefiniteExecution = true

【讨论】:

  • 我让 Slider 工作,现在标签中的值已更改。但我不想更改完整的代码。如何将滑块值放入变量中并在以下位置使用它:var ballShape = SCNSphere(radius: 0.01)(而不是 0.01 滑块值)
  • 我不太确定你在问什么。但在我的解决方案中,球节点被创建并在开始时加载到视图中。在您的情况下,节点被点击到视图中。但无论如何,一旦创建节点,您想在节点上进行缩放,该节点由滑块向上或向下更改。如果滑块正在工作,它应该在每次移动滑块时对 ballNode 进行缩放。
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 2019-05-10
  • 2018-09-19
  • 2022-09-27
  • 1970-01-01
  • 2018-04-06
  • 2021-01-24
相关资源
最近更新 更多