从零开始实现太阳公转AR项目(swift)

前言

我们一般创建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)
    }
    
最终效果

可以看到地球被光找到的地方会发亮,还有太阳周围有一层光晕

代码地址:

https://github.com/jinliyuelong/TheSunRevelution

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容