私は最初のSceneKitアプリケーションを試しています。私の目標は、地球の表面からのビューをシミュレートし、デバイスのカメラを任意の方向に向け、カメラビュー上に情報を重ねることができるようにすることです。SceneKitビューが後方にレンダリングされる
まず、SceneKitカメラビューをデバイスの向きに合わせようとしています。必要に応じて動作していることを確認するために、特定の緯度と経度の座標で球を追加しています。
1つの重要な問題以外はすべて動作しています。ビューは、表示されるべきものから左右(東/西)にミラーリングされます。私は時間をカメラの調整の異なる順列をしようと過ごした。
以下は私の完全なテストアプリビューコントローラです。シーンを適切にレンダリングするための変更の適切な組み合わせを理解することはできません。北極の球は正しいです。私の現在の経度で、北極から赤道まで伸びる球の線は、予想通りオーバーヘッドに見えます。それは正しくない他の球体です。鏡は自分の経度にあるかのように、彼らは東西に映し出されます。
このコードをテストする場合は、SceneKitで新しいGameプロジェクトを作成します。テンプレートGameViewController.swiftファイルを以下のファイルに置き換えます。また、Info.plistに「Privacy - Location When In Use Description」キーを追加する必要があります。 for lon in ...
行を調整して、数字が自分の経度で始まるか終わるようにすることもお勧めします。次に、球がディスプレイの正しい部分に描かれているかどうかを見ることができます。これはまた、UIColor(hue: CGFloat(lon + 104) * 2/255.0
の色を少し調整する必要があります。
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) {
}
}
変化は、おそらくsetCameraPosition
方法および/またはviewDidLoad
の終わりにmotionManager.startDeviceMotionUpdates
閉鎖のいくつかの組み合わせで行う必要があります。
は正しい方向に私を指してくれてありがとう。 "scn"ファイルを作成し、シーンエディタで見ているあなたの提案は、私の世界が映っていることを私に示しました。私は間違った方向にy軸を中心に回転していました。したがって、実際には、 'x '値ではなくネゲートする必要がある' eulerAngles.y'です。そして私はカメラと球の両方でそうする必要がありました。だからあなたの提案された答えは実際に私の問題の正しい解決策ではありませんが、あなたの答えは私に正しい解決策を見いだすのに非常に役立ちました。 – rmaddy