在AR體驗(yàn)的其他文章中基本的開發(fā)注意事項(xiàng)都已經(jīng)有詳細(xì)的描述闷游,本篇是太陽系的基礎(chǔ)篇地月篇。
看看效果
直接上代碼
import UIKit
import ARKit
import SceneKit
//var sceneView = ARSCNView()
class CWBSolarSystemVC: UIViewController,ARSCNViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// self.view.backgroundColor = UIColor.white
//2.創(chuàng)建場(chǎng)景視圖
initSceneView()
}
/// 初始化AR場(chǎng)景視圖
func initSceneView() -> () {
self.view.addSubview(sceneView)
/*
1.先把 太陽節(jié) 點(diǎn)添加到場(chǎng)景視圖
2. 太陽節(jié)點(diǎn) 添加 地球公轉(zhuǎn)節(jié)點(diǎn) (地球繞太陽運(yùn)轉(zhuǎn)的軌道)
3.在地球繞太陽運(yùn)轉(zhuǎn)的軌道上添加 地月節(jié)點(diǎn)
4.在地月節(jié)點(diǎn) 上添加 月轉(zhuǎn)節(jié)點(diǎn)(地球繞月亮轉(zhuǎn)的軌道)
5.在 月轉(zhuǎn)節(jié)點(diǎn) 上添加月亮節(jié)點(diǎn)
6. 太陽自轉(zhuǎn) 地球自轉(zhuǎn) 月球自轉(zhuǎn)
7.地球公轉(zhuǎn)節(jié)點(diǎn) (地球繞太陽運(yùn)轉(zhuǎn)的軌道)旋轉(zhuǎn)
8.月轉(zhuǎn)節(jié)點(diǎn)(地球繞月亮轉(zhuǎn)的軌道)旋轉(zhuǎn)
9.添加太陽的光暈
地球繞太陽轉(zhuǎn)是假象 其實(shí)是軌道在轉(zhuǎn)(后面會(huì)考慮真的繞太陽轉(zhuǎn)動(dòng)畫)
*/
sceneView.scene.rootNode.addChildNode(sunNode)
sunNode.addChildNode(earthRunNode)
earthRunNode.addChildNode(earthMoonNode)
earthMoonNode.addChildNode(earthNode)
earthMoonNode.addChildNode(moonRunNode)
moonRunNode.addChildNode(moonNode)
//
sunTurnsSelf()
earthTurnsAroundTheSun()
erathTurnsSelf()
moonTurnsAroundEarth()
moonTurnsSelf()
}
//開啟會(huì)話
override func viewWillAppear(_ animated: Bool) {
arSession.run(worldTrackingconfig)
}
//視圖消失的時(shí)候暫停會(huì)話
override func viewWillDisappear(_ animated: Bool) {
sceneView.session.pause()
}
//MARK:添加太陽的光暈
//MARK:月球繞地球轉(zhuǎn)
func moonTurnsSelf() -> () {
let animation = CABasicAnimation(keyPath: "rotation")
animation.duration = 1.5
animation.toValue = NSValue(scnVector4: SCNVector4Make(0, 1, 0, 2 * .pi)) //
animation.repeatCount = .greatestFiniteMagnitude
moonNode.addAnimation(animation, forKey: " moon turns around the earth")
}
//MARK:月球繞地球轉(zhuǎn)
func moonTurnsAroundEarth() -> () {
let animation = CABasicAnimation(keyPath: "rotation")
animation.duration = 5
animation.toValue = NSValue(scnVector4: SCNVector4Make(0, 1, 0, 2 * .pi)) //
animation.repeatCount = .greatestFiniteMagnitude
moonRunNode.addAnimation(animation, forKey: " moon turns around the earth")
}
//MARK:地球公轉(zhuǎn)
func earthTurnsAroundTheSun() -> () {
let animation = CABasicAnimation(keyPath: "rotation")
animation.duration = 10
animation.toValue = NSValue(scnVector4: SCNVector4Make(0, 1 , 0, 2 * .pi))
animation.repeatCount = .greatestFiniteMagnitude
earthRunNode.addAnimation(animation, forKey: "earth turns around the sun")
}
//MARK:地球自轉(zhuǎn)
func erathTurnsSelf() -> () {
// earthNode.runAction(SCNAction.repeatForever(SCNAction.moveBy(x: 0, y: 0, z: 0, duration: 0.5)))
earthNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
}
//MARK:太陽自轉(zhuǎn)
func sunTurnsSelf() -> () {
// sunNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
let animation = CABasicAnimation(keyPath: "contentsTransform")
animation.duration = 5
animation.fromValue = NSValue(caTransform3D: CATransform3DConcat(CATransform3DMakeTranslation(0, 0, 0), CATransform3DMakeScale(3, 3, 3)))
animation.repeatCount = .greatestFiniteMagnitude;
animation.toValue = NSValue(caTransform3D: CATransform3DConcat(CATransform3DMakeTranslation(1, 0, 0), CATransform3DMakeScale(5, 5,5 )))
animation.repeatCount = .greatestFiniteMagnitude;
sunNode.geometry?.firstMaterial?.diffuse.addAnimation(animation, forKey: "sun-texture")
}
//MARK:月球節(jié)點(diǎn)
lazy var moonNode: SCNNode = {
let sphere = SCNSphere(radius: 0.5)
let node = SCNNode(geometry: sphere)
node.position = SCNVector3(3, 0, 0)
node.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/moon.jpg"
return node
}()
//MARK: 月球運(yùn)轉(zhuǎn)節(jié)點(diǎn)
lazy var moonRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: 地月節(jié)點(diǎn) 用來裝地球和月球
lazy var earthMoonNode: SCNNode = {
let node = SCNNode()
node.position = SCNVector3(10, 0, 0)
return node
}()
//MARK: 地球軌道節(jié)點(diǎn)
lazy var earthRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: ??節(jié)點(diǎn)
lazy var earthNode:SCNNode = {
let shpere = SCNSphere(radius: 1.0)
let node = SCNNode(geometry: shpere)
node.position = SCNVector3(3, 0, 0)
node.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/earth-diffuse-mini.jpg"
//emission 發(fā)射 發(fā)射的光量跨跨。 這種發(fā)射不會(huì)照亮場(chǎng)景中的其他表面郑藏。 地球夜光圖
node.geometry?.firstMaterial?.emission.contents = "art.scnassets/earth/earth-emissive-mini.jpg"
//鏡面屬性谭期。鏡面特性指定以鏡像方式反射的光量个盆。 當(dāng)觀察點(diǎn)與反射光的方向相對(duì)時(shí),鏡面強(qiáng)度增加舍沙。
node.geometry?.firstMaterial?.specular.contents = "art.scnassets/earth/earth-specular-mini.jpg"
// 反光度 太陽光照射在??上會(huì)反光
node.geometry?.firstMaterial?.shininess = 0.1
//反射光 透明度
node.geometry?.firstMaterial?.specular.intensity = 0.6
return node
}()
lazy var sunHaloNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: 太陽節(jié)點(diǎn)
lazy var sunNode:SCNNode = {
//1.創(chuàng)建一個(gè)球體作為太陽
let sphere = SCNSphere(radius: 3)
// diffuse漫射屬性指定從表面漫反射的光量近上。 漫射光在所有方向上均勻地反射,因此與觀察點(diǎn)無關(guān)拂铡。
//設(shè)置表面的渲染物
sphere.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun.jpg"
//multiply()屬性指定用于將輸出片段乘以的顏色或圖像壹无。 計(jì)算的片段乘以乘法值以產(chǎn)生最終片段。 此屬性可用于陰影貼圖感帅,淡出或淡化3d對(duì)象斗锭。
sphere.firstMaterial?.multiply.contents = "art.scnassets/earth/sun.jpg"
// wrapS 從左到右
// wrapT 從上到下
sphere.firstMaterial?.multiply.wrapS = . repeat
sphere.firstMaterial?.diffuse.wrapS = . repeat
sphere.firstMaterial?.multiply.wrapT = . repeat
sphere.firstMaterial?.diffuse.wrapT = . repeat
let node = SCNNode(geometry: sphere)
//intensity 亮度 強(qiáng)度
node.geometry?.firstMaterial?.multiply.intensity = 0.5
// node.geometry?.firstMaterial?.diffuse.intensity = 0.5
//設(shè)置光照
node.geometry?.firstMaterial?.lightingModel = .constant
//設(shè)置太陽的位置
node.position = SCNVector3(0, 5, -50)
return node
}()
//MARK: 懶加載AR場(chǎng)景視圖
lazy var sceneView:ARSCNView = {
let sceneView = ARSCNView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
sceneView.delegate = self
sceneView.session = self.arSession
return sceneView
}()
//MARK: 懶加載會(huì)話
lazy var arSession:ARSession = {
let session = ARSession()
return session
}()
//MARK: 懶加載AR全局追蹤
lazy var worldTrackingconfig:ARWorldTrackingConfiguration = {
let config = ARWorldTrackingConfiguration()
return config
}()
}