在AR體驗的其他文章中基本的開發(fā)注意事項都已經(jīng)有詳細的描述,本篇是太陽系的基礎篇地月篇。
看看效果
AR地月篇.gif
直接上代碼
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)建場景視圖
initSceneView()
}
/// 初始化AR場景視圖
func initSceneView() -> () {
self.view.addSubview(sceneView)
/*
1.先把 太陽節(jié) 點添加到場景視圖
2. 太陽節(jié)點 添加 地球公轉節(jié)點 (地球繞太陽運轉的軌道)
3.在地球繞太陽運轉的軌道上添加 地月節(jié)點
4.在地月節(jié)點 上添加 月轉節(jié)點(地球繞月亮轉的軌道)
5.在 月轉節(jié)點 上添加月亮節(jié)點
6. 太陽自轉 地球自轉 月球自轉
7.地球公轉節(jié)點 (地球繞太陽運轉的軌道)旋轉
8.月轉節(jié)點(地球繞月亮轉的軌道)旋轉
9.添加太陽的光暈
地球繞太陽轉是假象 其實是軌道在轉(后面會考慮真的繞太陽轉動畫)
*/
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()
}
//開啟會話
override func viewWillAppear(_ animated: Bool) {
arSession.run(worldTrackingconfig)
}
//視圖消失的時候暫停會話
override func viewWillDisappear(_ animated: Bool) {
sceneView.session.pause()
}
//MARK:添加太陽的光暈
//MARK:月球繞地球轉
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:月球繞地球轉
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:地球公轉
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:地球自轉
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:太陽自轉
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é)點
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: 月球運轉節(jié)點
lazy var moonRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: 地月節(jié)點 用來裝地球和月球
lazy var earthMoonNode: SCNNode = {
let node = SCNNode()
node.position = SCNVector3(10, 0, 0)
return node
}()
//MARK: 地球軌道節(jié)點
lazy var earthRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: ??節(jié)點
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ā)射不會照亮場景中的其他表面。 地球夜光圖
node.geometry?.firstMaterial?.emission.contents = "art.scnassets/earth/earth-emissive-mini.jpg"
//鏡面屬性。鏡面特性指定以鏡像方式反射的光量。 當觀察點與反射光的方向相對時,鏡面強度增加。
node.geometry?.firstMaterial?.specular.contents = "art.scnassets/earth/earth-specular-mini.jpg"
// 反光度 太陽光照射在??上會反光
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é)點
lazy var sunNode:SCNNode = {
//1.創(chuàng)建一個球體作為太陽
let sphere = SCNSphere(radius: 3)
// diffuse漫射屬性指定從表面漫反射的光量。 漫射光在所有方向上均勻地反射,因此與觀察點無關。
//設置表面的渲染物
sphere.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun.jpg"
//multiply()屬性指定用于將輸出片段乘以的顏色或圖像。 計算的片段乘以乘法值以產生最終片段。 此屬性可用于陰影貼圖,淡出或淡化3d對象。
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 亮度 強度
node.geometry?.firstMaterial?.multiply.intensity = 0.5
// node.geometry?.firstMaterial?.diffuse.intensity = 0.5
//設置光照
node.geometry?.firstMaterial?.lightingModel = .constant
//設置太陽的位置
node.position = SCNVector3(0, 5, -50)
return node
}()
//MARK: 懶加載AR場景視圖
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: 懶加載會話
lazy var arSession:ARSession = {
let session = ARSession()
return session
}()
//MARK: 懶加載AR全局追蹤
lazy var worldTrackingconfig:ARWorldTrackingConfiguration = {
let config = ARWorldTrackingConfiguration()
return config
}()
}