在AR体验的其他文章中基本的开发注意事项都已经有详细的描述,本篇是太阳系的基础篇地月篇。
看看效果
![](https://img.haomeiwen.com/i1798026/52f7f23178a838d2.gif)
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.创建场景视图
initSceneView()
}
/// 初始化AR场景视图
func initSceneView() -> () {
self.view.addSubview(sceneView)
/*
1.先把 太阳节 点添加到场景视图
2. 太阳节点 添加 地球公转节点 (地球绕太阳运转的轨道)
3.在地球绕太阳运转的轨道上添加 地月节点
4.在地月节点 上添加 月转节点(地球绕月亮转的轨道)
5.在 月转节点 上添加月亮节点
6. 太阳自转 地球自转 月球自转
7.地球公转节点 (地球绕太阳运转的轨道)旋转
8.月转节点(地球绕月亮转的轨道)旋转
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:月球节点
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: 月球运转节点
lazy var moonRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: 地月节点 用来装地球和月球
lazy var earthMoonNode: SCNNode = {
let node = SCNNode()
node.position = SCNVector3(10, 0, 0)
return node
}()
//MARK: 地球轨道节点
lazy var earthRunNode: SCNNode = {
let node = SCNNode()
return node
}()
//MARK: 🌎节点
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 发射 发射的光量。 这种发射不会照亮场景中的其他表面。 地球夜光圖
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: 太阳节点
lazy var sunNode:SCNNode = {
//1.创建一个球体作为太阳
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
}()
}
网友评论