從零開始實現太陽公轉AR專案(swift)
阿新 • • 發佈:2018-12-25
前言
我們一般建立ar專案都是Augumented Reality App,系統會給我們生成一些程式碼。今天我們我們就從普通的Single View App一步步建立實現ar專案
太陽公轉ar小專案
建立專案
這一部分是建立專案、然後建立從一個viewcontroller點選按鈕present進入到我們的SunRevolutionViewController。這些比較簡單,我就一筆帶過
ps 由於用到相機,所以我們要新增相機許可權
<key>NSCameraUsageDescription</key>
<string>應用將要使用您的照相機</string >
核心地帶
1. 初始化arview必須的類
- 初始化arview必須的類
ARSCNView(展示ar)
ARSession (負責相機與模型的互動)
ARWorldTrackingConfiguration(追蹤裝置方向的基本配置)
let arSCNView = ARSCNView()
let arSession = ARSession()
let arConfiguration = ARWorldTrackingConfiguration()
- 重寫viewviewapper,讓ARWorldTrackingConfiguration追蹤我們的配置
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
arConfiguration.isLightEstimationEnabled = true//自適應燈光(室內到室外的話 畫面會比較柔和)
arSession.run(arConfiguration)
}
- 新增arview,並設定代理
class SunRevolutionViewController: UIViewController,ARSCNViewDelegate {
//設定arSCNView屬性
arSCNView.frame = self.view.frame
arSCNView.session = arSession
arSCNView.automaticallyUpdatesLighting = true//自動調節亮度
self.view.addSubview(arSCNView)
arSCNView.delegate = self
此時的效果圖
2 新增太陽、地球、月亮節點
新增太陽、地球、月亮節點,讓他們顯示在我們的螢幕上
我們讓月亮節點放到地球節點上,地球節點放到太陽節點上
//初始化節點資訊
func initNode() {
//1.設定幾何
sunNode.geometry = SCNSphere(radius: 3)
earthNode.geometry = SCNSphere(radius: 1)
moonNode.geometry = SCNSphere(radius: 0.5)
//2.渲染圖
// multiply: 把整張圖拉伸,之後會變淡
//diffuse:平均擴散到整個物體的表面,平切光澤透亮
// AMBIENT、DIFFUSE、SPECULAR屬性。這三個屬性與光源的三個對應屬性類似,每一屬性都由四個值組成。AMBIENT表示各種光線照射到該材質上,經過很多次反射後最終遺留在環境中的光線強度(顏色)。DIFFUSE表示光線照射到該材質上,經過漫反射後形成的光線強度(顏色)。SPECULAR表示光線照射到該材質上,經過鏡面反射後形成的光線強度(顏色)。通常,AMBIENT和DIFFUSE都取相同的值,可以達到比較真實的效果。
// EMISSION屬性。該屬性由四個值組成,表示一種顏色。OpenGL認為該材質本身就微微的向外發射光線,以至於眼睛感覺到它有這樣的顏色,但這光線又比較微弱,以至於不會影響到其它物體的顏色。
// SHININESS屬性。該屬性只有一個值,稱為“鏡面指數”,取值範圍是0到128。該值越小,表示材質越粗糙,點光源發射的光線照射到上面,也可以產生較大的亮點。該值越大,表示材質越類似於鏡面,光源照射到上面後,產生較小的亮點。
sunNode.geometry?.firstMaterial?.multiply.contents = "art.scnassets/earth/sun.jpg"
sunNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun.jpg"
sunNode.geometry?.firstMaterial?.multiply.intensity = 0.5 //強度
sunNode.geometry?.firstMaterial?.lightingModel = SCNMaterial.LightingModel.constant
// 地球圖
earthNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/earth-diffuse-mini.jpg"
// 地球夜光圖
earthNode.geometry?.firstMaterial?.emission.contents = "art.scnassets/earth/earth-emissive-mini.jpg";
earthNode.geometry?.firstMaterial?.specular.contents = "art.scnassets/earth/earth-specular-mini.jpg";
// 月球圖
moonNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/moon.jpg";
//3.設定位置
sunNode.position = SCNVector3(0, 5, -20)
earthNode.position = SCNVector3(10, 0, 0)
moonNode.position = SCNVector3(3, 0, 0)
//4.讓rootnode為sun sun上新增earth earth新增moon
sunNode.addChildNode(earthNode)
earthNode.addChildNode(moonNode)
self.arSCNView.scene.rootNode.addChildNode(sunNode)
}
此時我們的三個節點顯示出來了
3 設定轉動
設定太陽自轉
//MARK:設定太陽自轉
func sunRotation() {
let animation = CABasicAnimation(keyPath: "rotation")
animation.duration = 10.0//速度
animation.toValue = NSValue(scnVector4: SCNVector4(0, 1, 0, Double.pi * 2))//圍繞自己的y軸轉動
animation.repeatCount = Float.greatestFiniteMagnitude
sunNode.addAnimation(animation, forKey: "sun-texture")
}
由於地球和月球都放到了太陽節點上,所以地球和月球會跟著太陽轉動
設定地球地球和月球之間的轉動
earthNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)), forKey: "earth-texture")//duration標識速度 數字越小數字速度越快
//設定月球自轉
duration標識速度 數字越小數字速度越快 比如修改數字為0.1後的效果
由於月球公轉和地球自轉的週期不一致,所以月球不能放到地球節點上
建立一個月球圍繞地球節點(與地球節點位置相同),讓月球放到地月節點上,讓這個節點自轉,設定轉動速度即可
程式碼修改為
let moonRotationNode = SCNNode()//月球圍繞地球轉動的節點
earthNode.position = SCNVector3(3, 0, 0)
moonRotationNode.position = earthNode.position //設定月球圍繞地球轉動的節點位置與地球的位置相同
func earthTurn() {
//蘋果有一套自帶的動畫
earthNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)), forKey: "earth-texture")//duration標識速度 數字越小數字速度越快
//設定月球自轉
let animation = CABasicAnimation(keyPath: "rotation")
animation.duration = 1.5//速度
animation.toValue = NSValue(scnVector4: SCNVector4(0, 1, 0, Double.pi * 2))//圍繞自己的y軸轉動
animation.repeatCount = Float.greatestFiniteMagnitude
moonNode.addAnimation(animation, forKey: "moon-rotation")//月球自轉
//設定月球公轉
let moonRotationAnimation = CABasicAnimation(keyPath: "rotation")
moonRotationAnimation.duration = 5//速度
moonRotationAnimation.toValue = NSValue(scnVector4: SCNVector4(0, 1, 0, Double.pi * 2))//圍繞自己的y軸轉動
moonRotationAnimation.repeatCount = Float.greatestFiniteMagnitude
moonRotationNode.addAnimation(moonRotationAnimation, forKey: "moon rotation around earth")
}
設定公轉
公轉和月球圍繞地球轉動類似,建立一個地月節點,地月節點上防止地球節點和月球圍繞地球節點,月球圍繞地球節點放置月球節點,如圖所示
程式碼
let earthGroupNode = SCNNode()//地球和月球當做一個整體的節點 圍繞太陽公轉需要
//3.設定位置
sunNode.position = SCNVector3(0, 5, -20)
earthGroupNode.position = SCNVector3(10,0,0)//地月節點距離太陽的10
earthNode.position = SCNVector3(3, 0, 0)
moonRotationNode.position = earthNode.position //設定月球圍繞地球轉動的節點位置與地球的位置相同
moonNode.position = SCNVector3(3, 0, 0)//月球距離月球圍繞地球轉動距離3
//4.讓rootnode為sun sun上新增earth earth新增moon
// sunNode.addChildNode(earthNode)
// earthNode.addChildNode(moonNode)
moonRotationNode.addChildNode(moonNode)
earthGroupNode.addChildNode(earthNode)
earthGroupNode.addChildNode(moonRotationNode)
sunNode.addChildNode(earthGroupNode)
self.arSCNView.scene.rootNode.addChildNode(sunNode)
最終效果圖
新增光的效果
//MARK://設定太陽光暈和被光找到的地方
func addLight() {
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.color = UIColor.red //被光找到的地方顏色
sunNode.addChildNode(lightNode)
lightNode.light?.attenuationEndDistance = 20.0 //光照的亮度隨著距離改變
lightNode.light?.attenuationStartDistance = 1.0
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
lightNode.light?.color = UIColor.white
lightNode.opacity = 0.5 // make the halo stronger
SCNTransaction.commit()
sunHaloNode.geometry = SCNPlane.init(width: 25, height: 25)
sunHaloNode.rotation = SCNVector4Make(1, 0, 0, Float(0 * Double.pi / 180.0))
sunHaloNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun-halo.png"
sunHaloNode.geometry?.firstMaterial?.lightingModel = SCNMaterial.LightingModel.constant // no lighting
sunHaloNode.geometry?.firstMaterial?.writesToDepthBuffer = false // 不要有厚度,看起來薄薄的一層
sunHaloNode.opacity = 5
sunHaloNode.addChildNode(sunHaloNode)
}
可以看到地球被光找到的地方會發亮,還有太陽周圍有一層光暈