如何检索现有场景中节点的位置?

时间:2016-11-25 07:46:41

标签: ios swift sprite-kit scenekit sketchup

我创建了一个模型(例如,使用四面墙构建)并使用Sketchup将其导出为.dea文件。后来我在现场添加了tap guest,并找出了场景中的哪个墙被点击了。我得到了结果 - 墙的确切名称(id),但我没有得到这个位置。位置总是 - (x:0,y:0,z:0)。我想在我拍摄的每个墙上添加一个新的SCNNode,所以我需要在场景中准确定位墙壁。

截图:

enter image description here

如截图所示,我点击了第一栋建筑的前侧墙,但结果为零矢量。

我在stackOverflow和Internet上也尝试了所有解决方案,但没有成功。有人能帮助我吗?

dae文件:

http://www.filefactory.com/file/40y2ef86hgm3/Sample3d.dae

代码:

import UIKit
import QuartzCore
import SceneKit
import SpriteKit
import AVFoundation

class SceneViewController: UIViewController, UIGestureRecognizerDelegate {

    //Data handlers
    var currentSceneView: SCNView? = nil
    var cameraOrbit = SCNNode()
    let cameraNode = SCNNode()
    let camera = SCNCamera()
    var sceneText = SCNText()

    //HANDLE PAN CAMERA
    var lastWidthRatio: Float = 0
    var lastHeightRatio: Float = 0.2
    var WidthRatio: Float = 0
    var HeightRatio: Float = 0.2
    var fingersNeededToPan = 1
    var maxWidthRatioRight: Float = 0.2
    var maxWidthRatioLeft: Float = -0.2
    var maxHeightRatioXDown: Float = 0.02
    var maxHeightRatioXUp: Float = 0.4

    //HANDLE PINCH CAMERA
    var pinchAttenuation = 20.0  //1.0: very fast ---- 100.0 very slow
    var lastFingersNumber = 0
    var myScene = SCNScene()


   // MARK: - View Lifecycle methods
    override func viewDidLoad() {
        super.viewDidLoad()

        // create a new scene
        let scene = SCNScene(named: "Sample3d.dae")!


        myScene = scene

        addCameraNode(scene: scene)
        prepareScene(scene: scene)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

    // MARK: - Private APIs


    func addCameraNode(scene : SCNScene){
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = SCNLight.LightType.omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        //  scene.rootNode.addChildNode(lightNode)

        cameraNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = SCNLight.LightType.ambient
        ambientLightNode.light!.color = UIColor.darkGray
        //   scene.rootNode.addChildNode(ambientLightNode)
        cameraNode.addChildNode(ambientLightNode)

        //Create a camera like Rickster said
        camera.usesOrthographicProjection = true
        camera.orthographicScale = 1
        //camera.orthographicScale = 100
        camera.zNear = 1
        camera.zFar = 100

        cameraNode.position = SCNVector3(x: 0, y: 0, z: 20)
        cameraNode.camera = camera
        cameraOrbit = SCNNode()
        cameraOrbit.addChildNode(cameraNode)
        scene.rootNode.addChildNode(cameraOrbit)
    }

    func prepareScene(scene : SCNScene){
        self.navigationItem.title = "3D Scene"
        //initial camera setup
        self.cameraOrbit.eulerAngles.y = Float(-3 * M_PI) * lastWidthRatio
        self.cameraOrbit.eulerAngles.x = Float(-M_PI) * lastHeightRatio

        // retrieve the SCNView
        let scnView = self.view as! SCNView

        currentSceneView = scnView

        // set the scene to the view
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = UIColor.black

        //allows the user to manipulate the camera
        scnView.allowsCameraControl = false  //not needed

        // add a tap gesture recognizer
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(SceneViewController.handlePan(_:)))
        scnView.addGestureRecognizer(panGesture)

        // add a pinch gesture recognizer
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(SceneViewController.handlePinch(_:)))
        scnView.addGestureRecognizer(pinchGesture)

        let tap = UITapGestureRecognizer(target: self, action: #selector(SceneViewController.handleTap(_:)))
        tap.delegate = self
        scnView.addGestureRecognizer(tap)
    }

    // MARK: - Guesture Recognition methods

    func handleTap(_ gestureRecognize: UIGestureRecognizer) {

        let location: CGPoint = gestureRecognize.location(in: currentSceneView)// for example from a tap gesture recognizer
        let hits = self.currentSceneView?.hitTest(location, options: nil)
        if let tappedNode = hits?.first?.node {
addVideoNodeToScene(presentNode: tappedNode)

        }
    }


func addVideoNodeToScene(presentNode: SCNNode){

        if let path = Bundle.main.path(forResource: "Sample", ofType: "mp4") {
            let videoUrl = NSURL(fileURLWithPath: path)
            let player = AVPlayer(url: videoUrl as URL)
            let videoNode = SKVideoNode(avPlayer: player)
            let size = CGSize(width: 1024, height: 512)
            videoNode.size = size
            videoNode.position = CGPoint(x: size.width/2.0,y :size.height/2.0)
            let spriteScene = SKScene(size: size)
            spriteScene.addChild(videoNode)

            let cubeMaterial = SCNMaterial()
            cubeMaterial.diffuse.contents = spriteScene
            cubeMaterial.isDoubleSided = true

            let v1 = SCNVector3(x: 0,y: 0,z: 0)
            let v2 = SCNVector3(x: 0,y: 0,z: 0)
            let dx:Float = Float(v1.x - v2.x)/2.0
            let dy:Float = Float(v1.y - v2.y)

            var plane = SCNPlane()
            plane = SCNPlane.init(width: 0.35, height: 0.35)
            let planeNode = SCNNode(geometry: plane)

            plane.firstMaterial?.isDoubleSided = true
            planeNode.rotation = SCNVector4(x: 0, y: 0, z: 1, w: Float(M_PI))
            planeNode.geometry?.firstMaterial = cubeMaterial
            planeNode.position = presentNode.position
            planeNode.position.z = planeNode5.position.z + 0.15

            myScene.rootNode.addChildNode(planeNode)

            videoNode.play()
        }
    }


    func handlePan(_ gestureRecognize: UIPanGestureRecognizer) {

        let numberOfTouches = gestureRecognize.numberOfTouches
        let translation = gestureRecognize.translation(in: gestureRecognize.view!)

        if (numberOfTouches==fingersNeededToPan) {

            WidthRatio = Float(translation.x) / Float(gestureRecognize.view!.frame.size.width) + lastWidthRatio
            HeightRatio = Float(translation.y) / Float(gestureRecognize.view!.frame.size.height) + lastHeightRatio

            //  HEIGHT constraints
            if (HeightRatio >= maxHeightRatioXUp ) {
                HeightRatio = maxHeightRatioXUp
            }
            if (HeightRatio <= maxHeightRatioXDown ) {
                HeightRatio = maxHeightRatioXDown
            }

            //  WIDTH constraints
            if(WidthRatio >= maxWidthRatioRight) {
                WidthRatio = maxWidthRatioRight
            }
            if(WidthRatio <= maxWidthRatioLeft) {
                WidthRatio = maxWidthRatioLeft
            }

            self.cameraOrbit.eulerAngles.y = Float(-5 * M_PI) * WidthRatio
            self.cameraOrbit.eulerAngles.x = Float(-2 * M_PI) * HeightRatio

            //print("Height: \(round(HeightRatio*100))")
            //print("Width: \(round(WidthRatio*100))")

            //for final check on fingers number
            lastFingersNumber = fingersNeededToPan
        }

        lastFingersNumber = (numberOfTouches>0 ? numberOfTouches : lastFingersNumber)

        if (gestureRecognize.state == .ended && lastFingersNumber==fingersNeededToPan) {
            lastWidthRatio = WidthRatio
            lastHeightRatio = HeightRatio
            //print("Pan with \(lastFingersNumber) finger\(lastFingersNumber>1 ? "s" : "")")
        }

    }

    func handlePinch(_ gestureRecognize: UIPinchGestureRecognizer) {
        let pinchVelocity = Double.init(gestureRecognize.velocity)
        //print("PinchVelocity \(pinchVelocity)")

        camera.orthographicScale -= (pinchVelocity/pinchAttenuation)

        //print("PinchVelocity \(camera.orthographicScale)")

        if camera.orthographicScale <= 0.5 {
            camera.orthographicScale = 0.5
        }

        if camera.orthographicScale >= 5 {
            camera.orthographicScale = 5
        }

    }

    // MARK: - ViewController Orientation methods

    override var shouldAutorotate : Bool {
        return true
    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }

    // MARK: - Status bar methods

    override var prefersStatusBarHidden : Bool {
        return true
    }
}

1 个答案:

答案 0 :(得分:1)

在您附加的文件中,每个节点都位于(0, 0, 0)上,但具有不同的euler angle。正如我正在检查其他3D模型,你的代码工作得非常好。联系您的3D设计师并让他/她修复模型。

我建议您在编辑器(Xcode)中打开dae,将每个euler angle设为(0, 0, 0),并根据要求更改节点的位置。