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))
        }
    }

}

results matching ""

    No results matching ""