Ios SceneKit视图是向后渲染的

Ios SceneKit视图是向后渲染的,ios,swift,core-location,scenekit,core-motion,Ios,Swift,Core Location,Scenekit,Core Motion,我正在尝试我的第一个SceneKit应用程序。我的目标是模拟地球表面的视图,能够将设备的摄像头指向任何方向,并将信息覆盖在摄像头视图上 首先,我只是想让SceneKit摄像头视图与设备的方向相匹配。为了验证它是否按预期工作,我在特定的纬度和经度坐标处添加了一组球体 除了一个重要问题外,一切都在运转。该视图从其应显示的内容左/右(东/西)镜像。我花了几个小时试着调整相机的不同排列方式 下面是我完整的测试应用程序视图控制器。我无法找出正确的更改组合来正确渲染场景。北极的球体是正确的。按照我目前的经度

我正在尝试我的第一个SceneKit应用程序。我的目标是模拟地球表面的视图,能够将设备的摄像头指向任何方向,并将信息覆盖在摄像头视图上

首先,我只是想让SceneKit摄像头视图与设备的方向相匹配。为了验证它是否按预期工作,我在特定的纬度和经度坐标处添加了一组球体

除了一个重要问题外,一切都在运转。该视图从其应显示的内容左/右(东/西)镜像。我花了几个小时试着调整相机的不同排列方式

下面是我完整的测试应用程序视图控制器。我无法找出正确的更改组合来正确渲染场景。北极的球体是正确的。按照我目前的经度,从北极延伸到赤道的那条球体线在我头顶上出现了。这是球体的其他线条不正确。它们从它们应该是的东西方向镜像,就好像镜子在我自己的经度上一样

如果要测试此代码,请使用SceneKit创建一个新的游戏项目。将模板GameViewController.swift文件替换为以下文件。您还需要在Info.plist中添加“Privacy-Location-When-Use-Description”键。我还建议调整…行中lon的
,使数字以您自己的经度开始或结束。然后可以看到球体是否绘制在显示屏的正确部分。这可能还需要稍微调整
UIColor(色调:CGFloat(lon+104)*2/255.0
color)

import UIKit
import QuartzCore
import SceneKit
import CoreLocation
import CoreMotion

let EARTH_RADIUS = 6378137.0

class GameViewController: UIViewController, CLLocationManagerDelegate {
    var motionManager: CMMotionManager!
    var scnCameraArm: SCNNode!
    var scnCamera: SCNNode!
    var locationManager: CLLocationManager!
    var pitchAdjust = 1.0
    var rollAdjust = -1.0
    var yawAdjust = 0.0

    func radians(_ degrees: Double) -> Double {
        return degrees * Double.pi / 180
    }

    func degrees(_ radians: Double) -> Double {
        return radians * 180 / Double.pi
    }

    func setCameraPosition(lat: Double, lon: Double, alt: Double) {
        let yaw = lon
        let pitch = lat

        scnCameraArm.eulerAngles.y = Float(radians(yaw))
        scnCameraArm.eulerAngles.x = Float(radians(pitch))
        scnCameraArm.eulerAngles.z = 0
        scnCamera.position = SCNVector3(x: 0.0, y: 0.0, z: Float(alt + EARTH_RADIUS))
    }

    func setCameraPosition(loc: CLLocation) {
        setCameraPosition(lat: loc.coordinate.latitude, lon: loc.coordinate.longitude, alt: loc.altitude)
    }

    // MARK: - UIViewController methods

    override func viewDidLoad() {
        super.viewDidLoad()

        // create a new scene
        let scene = SCNScene()

        let scnCamera = SCNNode()
        let camera = SCNCamera()
        camera.zFar = 2.5 * EARTH_RADIUS
        scnCamera.camera = camera
        scnCamera.position = SCNVector3(x: 0.0, y: 0.0, z: Float(EARTH_RADIUS))
        self.scnCamera = scnCamera

        let scnCameraArm = SCNNode()
        scnCameraArm.position = SCNVector3(x: 0, y: 0, z: 0)
        scnCameraArm.addChildNode(scnCamera)
        self.scnCameraArm = scnCameraArm

        scene.rootNode.addChildNode(scnCameraArm)

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

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

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

        // Draw spheres over part of the western hemisphere
        for lon in stride(from: 0, through: -105, by: -15) {
            for lat in stride(from: 0, through: 90, by: 15) {
                let mat4 = SCNMaterial()
                if lat == 90 {
                    mat4.diffuse.contents = UIColor.yellow
                } else if lat == -90 {
                    mat4.diffuse.contents = UIColor.orange
                } else {
                    //mat4.diffuse.contents = UIColor(red: CGFloat(lat + 90) / 255.0, green: CGFloat(lon + 104) * 4 / 255.0, blue: 1, alpha: 1)
                    mat4.diffuse.contents = UIColor(hue: CGFloat(lon + 104) * 2 / 255.0, saturation: 1, brightness: CGFloat(255 - lat * 2) / 255.0, alpha: 1)
                }

                let ball = SCNSphere(radius: 100000)
                ball.firstMaterial = mat4
                let ballNode = SCNNode(geometry: ball)
                ballNode.position = SCNVector3(x: 0.0, y: 0.0, z: Float(100000 + EARTH_RADIUS))

                let ballArm = SCNNode()
                ballArm.position = SCNVector3(x: 0, y: 0, z: 0)
                ballArm.addChildNode(ballNode)
                scene.rootNode.addChildNode(ballArm)

                ballArm.eulerAngles.y = Float(radians(Double(lon)))
                ballArm.eulerAngles.x = Float(radians(Double(lat)))
            }
        }

        // configure the view
        scnView.backgroundColor = UIColor(red: 0, green: 191/255, blue: 255/255, alpha: 1) // sky blue

        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        let auth = CLLocationManager.authorizationStatus()
        switch auth {
        case .authorizedWhenInUse:
            locationManager.startUpdatingLocation()
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        default:
            break
        }

        motionManager = CMMotionManager()
        motionManager.deviceMotionUpdateInterval = 1 / 30
        motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical, to: OperationQueue.main) { (motion, error) in
            if error == nil {
                if let motion = motion {
                    //print("pitch: \(self.degrees(motion.attitude.roll * self.pitchAdjust)), roll: \(self.degrees(motion.attitude.pitch * self.rollAdjust)), yaw: \(self.degrees(-motion.attitude.yaw))")
                    self.scnCamera.eulerAngles.z = Float(motion.attitude.yaw + self.yawAdjust)
                    self.scnCamera.eulerAngles.x = Float(motion.attitude.roll * self.pitchAdjust)
                    self.scnCamera.eulerAngles.y = Float(motion.attitude.pitch * self.rollAdjust)
                }
            }
        }
    }

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

        if UIApplication.shared.statusBarOrientation == .landscapeRight {
            pitchAdjust = -1.0
            rollAdjust = 1.0
            yawAdjust = Double.pi
        } else {
            pitchAdjust = 1.0
            rollAdjust = -1.0
            yawAdjust = 0.0
        }
    }

    override var shouldAutorotate: Bool {
        return false
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscape
    }

    // MARK: - CLLocationManagerDelegate methods

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            manager.startUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        for loc in locations {
            print(loc)
            if loc.horizontalAccuracy > 0 && loc.horizontalAccuracy <= 100 {
                setCameraPosition(loc: loc)
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

    }
}
导入UIKit
进口石英砂
导入SceneKit
导入核心定位
导入CoreMotion
让接地半径=6378137.0
类GameViewController:UIViewController、CLLocationManagerDelegate{
var motionManager:CMMotionManager!
var scncameraram:SCNNode!
var scnCamera:SCNNode!
var locationManager:CLLocationManager!
变桨距调整=1.0
var rollAdjust=-1.0
var yawAdjust=0.0
func弧度(u度:双精度)->双精度{
返回度*Double.pi/180
}
func度(uu弧度:Double)->Double{
返回弧度*180/Double.pi
}
func setCameraPosition(横向:双精度、纵向:双精度、纵向:双精度){
让偏航=lon
让螺距=纬度
scncamerarm.eulerAngles.y=浮动(弧度(偏航))
scncamerarm.eulerAngles.x=浮动(弧度(螺距))
scncamerarm.eulerAngles.z=0
scnCamera.position=SCNVector3(x:0.0,y:0.0,z:Float(alt+EARTH_半径))
}
func设置摄像机位置(loc:CLLocation){
设置摄像机位置(纬度:位置坐标纬度,经度:位置坐标经度,高度:位置高度)
}
//MARK:-UIViewController方法
重写func viewDidLoad(){
super.viewDidLoad()
//创建一个新场景
让场景=SCNScene()
设scnCamera=SCNNode()
让摄影机=SCNCamera()
camera.zFar=2.5*地球半径
scnCamera.camera=摄像机
scnCamera.position=scinvector3(x:0.0,y:0.0,z:Float(地球半径))
self.scnCamera=scnCamera
设scncameraram=SCNNode()
scncameraram.position=scinvector3(x:0,y:0,z:0)
scncamerarm.addChildNode(scnCamera)
self.scncameraram=scncameraram
scene.rootNode.addChildNode(scncameraram)
//创建环境光并将其添加到场景中
让ambientLightNode=SCNNode()
ambientLightNode.light=SCNLight()
ambientLightNode.light!。类型=.ambientLightNode.light
ambientLightNode.light!.color=UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
//检索SCNView
让scnView=self.view为!scnView
//将场景设置为视图
scnView.scene=场景
//scnView.pointOfView=scnCamera
//在西半球的部分区域绘制球体
对于跨步长(从:0到-105,由-15){
步幅为横向(从:0到:90,由:15){
设mat4=SCNMaterial()
如果lat==90{
mat4.diffuse.contents=UIColor.yellow
}否则,如果lat==-90{
mat4.diffuse.contents=UIColor.orange
}否则{
//mat4.diffuse.contents=UIColor(红色:CGFloat(lat+90)/255.0,绿色:CGFloat(lon+104)*4/255.0,蓝色:1,阿尔法:1)
mat4.diffuse.contents=UIColor(色调:CGFloat(lon+104)*2/255.0,饱和度:1,亮度:CGFloat(255-lat*2)/255.0,alpha:1)
}
让球=圆球(半径:100000)
ball.firstMaterial=mat4
设ballNode=SCNNode(几何体:ball)
ballNode.position=SCInvector3(x:0.0,y:0.0,z:Float(100000+地球半径))
设ballArm=SCNNode()
ballArm.position=SCInvector3(x:0,y:0,z:0)
ballArm.addChildNode(ballNode)
scene.rootNode.addChildNode(ballArm)
ballArm.eulerAngles.y=浮动(弧度(双(长)))
ballArm.eulerAngles.x=浮动(弧度(双倍(横向)))
}
}
//配置视图
scnView.backgroundColor=UIColor(红色:0,绿色:191/255,蓝色:255/255,alpha:1)//天蓝色
locationManager=CLLocationManager()
locationManager.delegate=self
locationManager.desiredAccuracy=KCallocationAccuracyBestforNavigation
让auth=CLLocationManager.authorizationStatus()
交换机身份验证{
案例.授权使用:
locationManager.startUpdatingLocation()
案例。未确定:
locationManager.RequestWhenUseAuthorization()
违约:
打破
}
motionManager=CMMotionManager()
运动经理
    ballArm.eulerAngles.x = -1 * Float(radians(Double(lat)))
    // Draw spheres over part of the western hemisphere
    for lon in stride(from: 0, through: -105, by: -15) {
        for lat in stride(from: 0, through: 90, by: 15) {
            let mat4 = SCNMaterial()
            if lon == 0 {
                mat4.diffuse.contents = UIColor.black
            } else if lon == -105 {
                mat4.diffuse.contents = UIColor.green
            } else if lat == 90 {
                mat4.diffuse.contents = UIColor.yellow
            } else if lat == 0 {
                mat4.diffuse.contents = UIColor.orange
            } else  {
                mat4.diffuse.contents = UIColor(red: CGFloat(lat + 90) / 255.0, green: CGFloat(lon + 104) * 4 / 255.0, blue: 1, alpha: 1)
                //mat4.diffuse.contents = UIColor(hue: CGFloat(lon + 104) * 2 / 255.0, saturation: 1, brightness: CGFloat(255 - lat * 2) / 255.0, alpha: 1)
                //mat4.diffuse.contents = UIColor.green
            }

            let ball = SCNSphere(radius: 100000)
            ball.firstMaterial = mat4
            let ballNode = SCNNode(geometry: ball)
            ballNode.position = SCNVector3(x: 0.0, y: 0.0, z: Float(100000 + EARTH_RADIUS))

            let ballArm = SCNNode()
            ballArm.position = SCNVector3(x: 0, y: 0, z: 0)
// debugging label
            ballArm.name = "\(lat) \(lon)"
            ballArm.addChildNode(ballNode)
            scene.rootNode.addChildNode(ballArm)

            ballArm.eulerAngles.y = Float(radians(Double(lon)))
            ballArm.eulerAngles.x = -1 * Float(radians(Double(lat)))
        }
    }
    // configure the view
    scnView.backgroundColor = UIColor.cyan

    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let docsFolderURL = urls[urls.count - 1]
    let archiveURL = docsFolderURL.appendingPathComponent("rmaddy.scn")
    let archivePath = archiveURL.path
// for  copy/paste from Simulator's file system
    print (archivePath)  
    let archiveResult = NSKeyedArchiver.archiveRootObject(scene, toFile: archivePath)
    print(archiveResult)
scnCameraArm.eulerAngles.y = Float(radians(yaw))
scnCameraArm.eulerAngles.y = -Float(radians(yaw))
ballArm.eulerAngles.y = Float(radians(Double(lon)))
ballArm.eulerAngles.y = -Float(radians(Double(lon)))