SCNCamera
照相机原理分析
视角
上图是一个游戏场景 照相机的位置为(10,0,0) 物体A的位置为(0,0-6),yFor 表示的是Y轴上的视角。图你可以不太理解,的确有点抽象。
举例说明:
在游戏引擎中,照相机好比就是你的眼睛,你眼睛在X轴(左右看)和Y轴(上下看)有个最大角度,这个角度我们叫做xFov和yFov,想想一下,如果是这视野大了,我们能看到的范围就会变大,这个时候,你拍一张照片,我的要求是,照片的大小和你手机大小一样,如果你视野小,你的照里面的物体就少,如果你视野大,你照片里面的物体就会变多,那么,对于同一个物体,当然在视野小的时候,显示的体积大,在视野大的时候,显示的体积小。就是这么简单。
f: 焦距 从图可以看出,焦距越大,视野越小,焦距越小视野越大
记住:我们显示在手机屏幕中的物体都是能被照相机看到的物体。
SCNCamera 详解
它的父类为NSObject
@interface SCNCamera : NSObject <SCNAnimatable, SCNTechniqueSupport, NSCopying, NSSecureCoding>
创建对象的方法
+ (instancetype)camera;
给照相机对象设置名字
@property(nonatomic, copy, nullable) NSString *name;
X轴方向的视角(默认为60度)
@property(nonatomic) double xFov;
Y轴方向的视角(默认为60度)
@property(nonatomic) double yFov;
照相机能照到的最近距离(默认值为1)
@property(nonatomic) double zNear;
照相机能照到的最远距离(默认值为100)
@property(nonatomic) double zFar;
让照相机自动调节最近和最远距离(默认为关闭,开启后,没有最近和最远的限制)
@property(nonatomic) BOOL automaticallyAdjustsZRange NS_AVAILABLE(10_9, 8_0);
是否开启正投影模式 正投影就是说物体在远离或者靠近照相机是,大小保持不变
@property(nonatomic) BOOL usesOrthographicProjection;
设置正投影的比例 (默认为1)
注意,这里设置的比例越大,显示的图像越小,你可以这样理解scale = 屏幕的大小:图片的大小
@property(nonatomic) double orthographicScale NS_AVAILABLE(10_9, 8_0);
设置焦距(默认为10)
@property(nonatomic) CGFloat focalDistance NS_AVAILABLE(10_9, 8_0);
设置聚焦时,模糊物体模糊度(默认为0)
@property(nonatomic) CGFloat focalBlurRadius NS_AVAILABLE(10_9, 8_0);
决定进入焦点和离开焦点的过渡速度
@property(nonatomic) CGFloat aperture NS_AVAILABLE(10_9, 8_0);
用于检测节点碰撞使用
@property(nonatomic) NSUInteger categoryBitMask NS_AVAILABLE(10_10, 8_0);
func setup() {
let scnView = SCNView(frame: view.bounds)
scnView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
scnView.backgroundColor = UIColor.gray
view.addSubview(scnView)
scnView.allowsCameraControl = true
let scene = SCNScene()
scnView.scene = scene
// 添加照相机
let camera = SCNCamera()
let cameraNode = SCNNode()
cameraNode.camera = camera
cameraNode.position = SCNVector3Make(0, 0, 50)
scnView.scene?.rootNode.addChildNode(cameraNode)
// 调节视角
camera.xFov = 50
camera.yFov = 50
//设置焦距
camera.focalDistance = 45;
camera.focalBlurRadius = 1;// 默认为0 你要有模糊度的值才能出现这种效果.
//设置相机的最远能照到的物体
//camera.zFar = 60
//设置正投影
//camera.usesOrthographicProjection = true
//设置正投影比例
//camera.orthographicScale = 10;
let cube1 = SCNBox(width: 10, height: 10, length: 10, chamferRadius: 0)
let cube1Node = SCNNode(geometry: cube1)
cube1Node.position = SCNVector3Make(0, 20, 0)
cube1Node.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/2.jpg"
scene.rootNode.addChildNode(cube1Node)
let cube2 = SCNBox(width: 10, height: 10, length: 10, chamferRadius: 0)
let cube2Node = SCNNode(geometry: cube2)
cube2Node.position = SCNVector3Make(0, -20, 0)
cube2Node.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/1.jpg"
scene.rootNode.addChildNode(cube2Node)
}
补充点内容 上面我们有个操作是开启控制照相机 scnView .allowsCameraControl = true; 到底如何操纵我详细讲解一下 1.一个手指头的时候,照相机对准(0,0,0)沿着球体表面旋转 2.两个手指头平移手势,照相机是在X轴和Y轴移动 3.捏合手势,是在Z轴移动
如何实现照相机视角切换
在游戏中,我们经常可以看到,有视角切换这个功能,第一视角,第三视角切换,那在SceneKit中怎么进行视角切换了,今天就带大家练习这个功能!
import UIKit
import SceneKit
class Test15VC: UIViewController {
var scnView:SCNView!
var firstCameraNode:SCNNode!
var thirdCameraNode:SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
scnView = SCNView(frame: view.bounds)
scnView.scene = SCNScene()
scnView.backgroundColor = UIColor.black
view.addSubview(scnView)
scnView.allowsCameraControl = true
scnView.showsStatistics = true
scnView.preferredFramesPerSecond = 60
let sunNode = SCNNode(geometry: SCNSphere(radius: 3))
sunNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun.jpg"
scnView.scene?.rootNode.addChildNode(sunNode)
let earthMoonGroupNode = SCNNode()
earthMoonGroupNode.position = SCNVector3Make(10, 0, 0)
sunNode.addChildNode(earthMoonGroupNode)
let earthNode = SCNNode(geometry: SCNSphere(radius: 1))
earthNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/earth1.jpg"
earthMoonGroupNode.addChildNode(earthNode)
let moonNode = SCNNode(geometry: SCNSphere(radius: 0.5))
moonNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/moon.jpg"
moonNode.position = SCNVector3Make(2, 0, 0)
earthNode.addChildNode(moonNode)
sunNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 1, z: 0, duration: 1.0)))
earthNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 1, z: 0, duration: 0.3)))
firstCameraNode = SCNNode()
firstCameraNode.camera = SCNCamera()
firstCameraNode.position = SCNVector3Make(0, 0, 20)
scnView.scene?.rootNode.addChildNode(firstCameraNode)
thirdCameraNode = SCNNode()
thirdCameraNode.camera = SCNCamera()
thirdCameraNode.camera?.automaticallyAdjustsZRange = true
thirdCameraNode.position = SCNVector3Make(0, 0, 30)
scnView.scene?.rootNode.addChildNode(thirdCameraNode)
scnView.pointOfView = thirdCameraNode
initUI()
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
let position = earthNode.convertPosition(earthNode.position, to: self.scnView.scene?.rootNode)
self.firstCameraNode.runAction(SCNAction.repeatForever(SCNAction.move(to: SCNVector3Make(position.x, position.y, position.z + 10), duration: 0.1)))
}
}
func initUI() {
let segment = UISegmentedControl(items: ["进入太阳系","进入地月系","离开太阳系"])
segment.frame = CGRect(x: 10, y: view.bounds.height - 44, width: view.bounds.width - 20, height: 44)
view.addSubview(segment)
segment.selectedSegmentIndex = 0
segment.addTarget(self, action: #selector(cameraChange), for: .valueChanged)
}
@objc func cameraChange(sender:UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
scnView.pointOfView = thirdCameraNode
thirdCameraNode.runAction(SCNAction.move(to: SCNVector3Make(0, 0, 30), duration: 1))
} else if sender.selectedSegmentIndex == 1 {
scnView.pointOfView = firstCameraNode
} else {
scnView.pointOfView = thirdCameraNode
thirdCameraNode.runAction(SCNAction.move(to: SCNVector3Make(0, 0, 400), duration: 1))
}
}
}