SceneKit

作者: 小凡凡520 | 来源:发表于2020-02-14 10:57 被阅读0次
一、概述

SceneKit,是用来构建3D场景的框架,且可以与Core Animation和SpriteKit无缝交互。在SceneKit中可以直接引入COLLADA行业标准文件制作好的3D模型或场景。

与SpriteKit一样,SceneKit通过场景(SCNScene)来显示物体,场景包涵在SCNView。场景内同样是以节点的结构来呈现物体。场景里可以包含这些类型的项目:

* 几何体。 代码建立的3D对象或从文件加载的3D模型,在它们上可以附加不同的材料来达成控制颜色,纹理,反光等效果
* 照相机。 这是你观察这个场景的入口,可以设置位置和视角
* 光源。 有各种光源后面会提到
* 物理实体。 受物理特效控制的各种有实体的物体

使用SceneKit的方法不止有在SCNView内部来使用。还可以在Core Animation层的层次结构中使用SCNLayer。使用SCNRender来渲染你自己的OpenGL渲染器。

SceneKit可以同时在IOS和OS X下工作

二、基本概念
  • SCNVector3
    三维向量
  • SCNCamera
    三维摄像头
  • SCNGeometry
    三维几何图形
三、几何图形
  • SCNPlane
    平面矩形
  • SCNBox
    长方体
  • SCNSphere
    球形
  • SCNPyramid
    四棱锥
  • SCNTorus
    圆环
  • SCNCapsule
    胶囊体
  • SCNCylinder
    圆柱
  • SCNCone
    圆台
  • SCNTube
    管道体
四、实战
import UIKit
import SceneKit
import SpriteKit

class TestViewController: UIViewController {
            
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        // 创建游戏专用视图
        let scnView = SCNView(frame: self.view.frame)
        scnView.scene = SCNScene()
        self.view.addSubview(scnView)
        
        // 创建一个摄像机
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        // 自动调节可视范围
        cameraNode.camera?.automaticallyAdjustsZRange = true
        cameraNode.position = SCNVector3(0, 0, 10)
        scnView.scene?.rootNode.addChildNode(cameraNode)
        
        // 创建一个节点并绑定一个平面几何对象
        let boxNode = SCNNode()
        let plane = SCNPlane(width: 16, height: 9)
        boxNode.geometry = plane
        boxNode.geometry?.firstMaterial?.isDoubleSided = true
        boxNode.position = SCNVector3(0, 0, -30)
        scnView.scene?.rootNode.addChildNode(boxNode)
        
        guard let url = Bundle.main.url(forResource: "1", withExtension: "mp4") else {
            return
        }
        let videoNode = SKVideoNode(url: url)
        videoNode.size = CGSize(width: 1600, height: 900)
        videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)
        videoNode.zRotation = CGFloat(M_PI)
        let skScene = SKScene()
        skScene.addChild(videoNode)
        skScene.size = videoNode.size
        
        // 给平面体设置渲染内容
        plane.firstMaterial?.diffuse.contents = skScene
        
        // 播放视频
        videoNode.play()
        
        // 打开摄像头控制查看效果
        scnView.allowsCameraControl = true
    }
}
五、粒子系统
六、光源
  • 环境光源
    它在整个场景内投射均匀光
  • 泛光源
    这是用的最多的,就是点光源,向各个方向投射光
  • 平行光源
    在单个方向投射光
  • 聚光源
    在给定方向从单个位置投射光
// 添加环境光源
let ambientLight = SCNLight()
// 光源的类型,这里是环境光源
ambientLight.type = .ambient
ambientLight.color = UIColor.red
let myAmbientLightNode = SCNNode()
myAmbientLightNode.light = ambientLight
myScene.rootNode.addChildNode(myAmbientLightNode)

// 添加泛光源
let omniLight = SCNLight()
omniLight.type = .omni
omniLight.color = UIColor.black
let omniLightNode = SCNNode()
omniLightNode.light = omniLight
omniLightNode.position = SCNVector3(-10, 8, 5)
myScene.rootNode.addChildNode(omniLightNode)
七、材料
  • diffuse
    材料的基本颜色,纹理等
  • specular
    材料的亮度以及该如何反射光
  • emissive
    材料发光时的样子
  • normal
    又称为法向,设置材料表面更多的细节
//使用材料
let redMetallicMateril = SCNMaterial()
//contents设置为颜色
redMetallicMateril.diffuse.contents = UIColor.blue
redMetallicMateril.specular.contents = UIColor.white
redMetallicMateril.shininess = 1.0
//一个物体的材料是不唯一的,故传进去一个数组
plane.materials = [redMetallicMateril]
        
let noiseTexture = SKTexture(noiseWithSmoothness: 0.25, size: CGSize(width: 512, height: 512), grayscale: true)
let noiseMaterial = SCNMaterial()
//contents设置为SpriteKit纹理
noiseMaterial.diffuse.contents = noiseTexture
text.materials = [noiseMaterial]

//法线贴图
let noiseNormalMapTexture = noiseTexture.generatingNormalMap(withSmoothness: 1, contrast: 1)
redMetallicMateril.normal.contents = noiseNormalMapTexture
八、动画
// 向胶囊节点添加动画
let moveUpDownAnimation = CABasicAnimation(keyPath: "position")
// 移动的坐标
moveUpDownAnimation.byValue = NSValue(scnVector3: SCNVector3(30, 0, 0))
moveUpDownAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)//移动速度的曲线
moveUpDownAnimation.autoreverses = true//是否自动返回
moveUpDownAnimation.repeatCount = Float.infinity//重复次数
moveUpDownAnimation.duration = 10.0//持续时间
plane.addAnimation(moveUpDownAnimation, forKey: "updown")//这里的这个keyPath貌似随便写就可以
        
//胶囊节点的子节点,一个文本
let text = SCNText(string: "BaLaLaLa", extrusionDepth: 1)
text.font = UIFont.systemFont(ofSize: 2)
let textNode = SCNNode(geometry: text)
textNode.position = SCNVector3(-5, 6, 0)
boxNode.addChildNode(textNode)
        
//在一个节点上添加多个动画结果会复合,即便是继承自父节点的动画也同样一起复合
let rotate = CABasicAnimation(keyPath: "eulerAngles")
rotate.byValue = NSValue(scnVector3: SCNVector3(0, M_PI * 2, 0))
rotate.repeatCount = Float.infinity
rotate.duration = 5.0
textNode.addAnimation(rotate, forKey: "rotation")
九、从COLLADA文件中加载文件
//加载一个已经建好的3D模型或场景,会是一个COLLADA文件,后缀名为.dae
guard let critterURL = Bundle.main.url(forResource: "", withExtension: "dae") else {
    return
}
let critterData = SCNSceneSource(url: critterURL, options: nil)
let critterNode = critterData?.entryWithIdentifier("Critter", withClass: SCNNode.self)
if (critterNode != nil) {
    critterNode!.position = SCNVector3(0, 0, -10)
    critterNode?.name = "Critter"
    myScene.rootNode.addChildNode(critterNode!)
}
十、添加物理仿真
//像节点添加物理特性
var critterPhysicsShape: SCNPhysicsShape?
if let geometry = critterNode?.geometry {
    critterPhysicsShape = SCNPhysicsShape(geometry: geometry, options: nil)
}
let critterPhysicsBody = SCNPhysicsBody(type: .dynamic, shape: critterPhysicsShape)
critterPhysicsBody.mass = 1
critterNode?.physicsBody = critterPhysicsBody

//添加一个地板
let floor = SCNFloor()
let floorNode = SCNNode(geometry: floor)
floorNode.position = SCNVector3(0, -10, 0)
myScene.rootNode.addChildNode(floorNode)
let floorPhysicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: floor, options: nil))
floorNode.physicsBody = floorPhysicsBody

相关文章

网友评论

      本文标题:SceneKit

      本文链接:https://www.haomeiwen.com/subject/xbppbftx.html