It's 360 degree video player project.
I add a cameranode(SCNNode
) to a rootnode, the cameranode was put at the center(0,0,0) of the SCNSphere
, It can play video by now.
Now I have to use devicemotion. I need to rotate the camera when device moves. Not just rotate a certain angle. (Not just device move, When I'm holding a device, my moving regard as the device moving. because I found if I use deviceMotion.attitude.roll
, the cameranode only moves when device moves by itself, not when I circle around with device)
When device is located in (x1,y1,z1) position, the cameranode would rotate as the device moving, and when the device located in (x1,y1,z1) position again, the view should be as same as the last we left.
Here's what I've done:
if (self.motionManager.gyroAvailable) {
self.motionManager.gyroUpdateInterval = 1.0/60.0;
[self.motionManager startGyroUpdatesToQueue:self.queue withHandler:^(CMGyroData *gyroData, NSError *error){
if (error) {
[self.motionManager stopGyroUpdates];
NSLog(@"Gyroscope encountered error:%@",error);
}else {
CGFloat tempX = 0;
CGFloat tempY = 0;
CGFloat tempZ = 0;
if ((fabs(gyroData.rotationRate.y)/60) > 0.002) {
tempY = gyroData.rotationRate.y/60;
}
tempX = gyroData.rotationRate.x/60;
tempZ = gyroData.rotationRate.z/60;
[self.cameraNode runAction:[SCNAction rotateByX:-tempY y:tempX z:tempZ duration:0]];
}
}];
}else {
NSLog(@"This device has no gyroscope");
}
The math could be wrong, I don't know why would I divide 60, but it seems the nearest value I need when I use [self.cameraNode runAction:[SCNAction rotateByX:-tempY y:tempX z:tempZ duration:0]];
Here's the problem?
CMGyroData
or CMDeviceMotion
. If use CMDeviceMotion
, which specific value should I use? deviceMotion.attitude
, deviceMotion.attitude.quaternion
, deviceMotion.gravity
+ (SCNAction *)rotateByX:(CGFloat)xAngle y:(CGFloat)yAngle z:(CGFloat)zAngle duration:(NSTimeInterval)duration;
+ (SCNAction *)rotateToX:(CGFloat)xAngle y:(CGFloat)yAngle z:(CGFloat)zAngle duration:(NSTimeInterval)duration;
using the brilliant extension from the initial answer, you can simply do something like this:
override func viewDidAppear(_ animated: Bool) {
// let motionManager = CMMotionManager() // definition made globally
// CoreMotion
motionManager.startDeviceMotionUpdates()
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
let interfaceOrientation = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.windowScene?.interfaceOrientation // for iOS13 and later
// .xTrueNorthZVertical // always aligns to the real north
// .xArbitraryZVertical // will use this one for initial direction
motionManager.startDeviceMotionUpdates(using: .xArbitraryZVertical, to: OperationQueue.main, withHandler: { (motion: CMDeviceMotion?, err: Error?) in
guard let m = motion else { return }
// self.cameraNode.orientation = m.gaze(atOrientation: UIApplication.shared.statusBarOrientation) // before iOS 13
self.cameraNode.orientation = m.gaze(atOrientation: interfaceOrientation!) // for iOS13 and later
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With