ARKit如何將太陽系裝進(jìn)iPhone(二)

轉(zhuǎn)載請注明原作者

上篇文章我們介紹如何創(chuàng)建一個ARKit項目筑凫,并且創(chuàng)建太陽决侈、地球這些球體,接下來我們來談一談如何讓它們動起來。

演示視頻

ARSolarPlay.gif


天文科普

首先科普下太陽系的結(jié)構(gòu)叠必,太陽系共有八大行星肚逸,水星货徙、金星区拳、地球浅蚪、火星、木星烫罩、土星惜傲、天王星、海王星贝攒,還有顆矮行星冥王星盗誊。木星體積最大,且自轉(zhuǎn)周期最快饿这,它和土星浊伙、天王星都自帶行星環(huán)撞秋,地球衛(wèi)星是月球长捧,金星和水星是太陽系中唯二不帶衛(wèi)星的行星。太陽作為恒星本身會自轉(zhuǎn)吻贿,而行星除了自轉(zhuǎn)外還會圍繞它的恒心公轉(zhuǎn)串结,由于行星軌道多是橢圓,為了簡化難度(偷懶)我們假定他們的公轉(zhuǎn)軌道都是圓形舅列,而地球的自轉(zhuǎn)軌道也是斜的肌割,這些細(xì)節(jié)后面會進(jìn)一步完善。

圣斗士星矢.jpg

3D模型創(chuàng)建--SceneKit

AR工程中有一個ARSCNView帐要,它用來加載3D模型的AR視圖的把敞,它繼承于SCNView,相對的加載2D視圖的就是ARSKView榨惠,視圖中的那些模型的創(chuàng)建運(yùn)動就需要用到本章所說的SceneKit和SpriteKit奋早。它們是iOS中用來開發(fā)3D模型和2D模型的引擎,由于沒用過Unity3D開發(fā)赠橙,所以此處不介紹耽装。

Sprite是用來創(chuàng)建2D模型,在游戲開發(fā)中期揪,指的是以圖像方式呈現(xiàn)在屏幕上的一個圖像掉奄。這個圖像也許可以移動,用戶可以與其交互凤薛,也有可能僅只是游戲的一個靜止的背景圖姓建。而在AR中,2D模型會隨著手機(jī)的遠(yuǎn)近放大縮小缤苫,而不能像3D模型那樣可以從側(cè)面觀察引瀑。

SceneKit 建立在 OpenGL 的基礎(chǔ)上,包含了如光照榨馁、模型憨栽、材質(zhì)、攝像機(jī)等高級引擎特性,我們可以基于它做出很多逼真的3D物理模型屑柔。

SCeneKit結(jié)構(gòu)圖.jpg
SCNScene & SCNNode

每個ARSCNView中都帶有一個場景SCNScene屡萤,它用來承載那些帶有幾何結(jié)構(gòu)、光度掸宛、相機(jī)以及其他屬性的節(jié)點(diǎn)SCNNode死陆,一個完整的3D場景就這么展現(xiàn)出來了。一個SCNScene可以包含多個SCNNode子節(jié)點(diǎn)唧瘾,它們一般都是呈樹狀結(jié)構(gòu)措译,一個子節(jié)點(diǎn)SCNNode可以有多個childNode,而SCNNode只有一個parentNode饰序,rootNode作為根節(jié)點(diǎn)领虹,我們通過rootNode添加自己的子節(jié)點(diǎn)SCNNode。
SCNNode的常用方法:

addChildNode(_:)
insertChildNode(_: atIndex:)
removeFromParentNode()

接下來介紹下SCNNode的幾種常用的屬性對象
** 1. SCNGeometry **
??SceneNode提供幾種幾何模型求豫,例如六面體(SCNBox)塌衰、平面(SCNPlane,只有一面)蝠嘉、無限平面(SCNFloor最疆,沿著x-z平面無限延伸)、球體(SCNSphere)等等蚤告。
例如我們創(chuàng)建一個半徑為0.25的球體

SCNNode *sunNode = [SCNNode new];
sunNode.geometry = [SCNSphere sphereWithRadius:0.25];

為了突出行星運(yùn)動軌跡努酸,我們給每顆星星添加了軌道,一開始我使用的是SCNPlane后來發(fā)現(xiàn)它只有一個平面杜恰,你從反面是看不到的获诈,于是我使用的是SCNBox

SCNNode *mercuryOrbit = [SCNNode node];
//設(shè)置不透明度
mercuryOrbit.opacity = 0.4;
//設(shè)置軌道的結(jié)構(gòu)體,height為0
mercuryOrbit.geometry = [SCNBox boxWithWidth:0.86 height:0 length:0.86 chamferRadius:0];
mercuryOrbit.geometry.firstMaterial.diffuse.contents = @"art.scnassets/solar/orbit.png";
//紋理濾波
mercuryOrbit.geometry.firstMaterial.diffuse.mipFilter = SCNFilterModeLinear;
mercuryOrbit.rotation = SCNVector4Make(0, 1, 0, M_PI_2);
//光照模式
mercuryOrbit.geometry.firstMaterial.lightingModelName = SCNLightingModelConstant; // no lighting
[_sunNode addChildNode:mercuryOrbit];

補(bǔ)充一下紋理濾波這個屬性有什么用?
當(dāng)材料表面的部分出現(xiàn)較大或小于原來的紋理圖像時箫章,紋理過濾決定了材料屬性的內(nèi)容的外觀

@property(nonatomic) SCNFilterMode minificationFilter
可選項
typedef enum : NSInteger { 
SCNFilterModeNone = 0, // 當(dāng)這個位置沒有紋理顏色時烙荷,會采樣離他最近的顏色值 
SCNFilterModeNearest = 1, //當(dāng)這個位置沒有紋理顏色時,線性插值顏色作為自己的顏色
SCNFilterModeLinear = 2, } SCNFilterMode;
默認(rèn)值為 SCNFilterModeLinear

** 2. SCNMaterial **
SceneNode提供8種屬性用來設(shè)置模型材質(zhì)

  • Diffuse 漫發(fā)射屬性表示光和顏色在各個方向上的反射量
  • Ambient 環(huán)境光以固定的強(qiáng)度和固定的顏色從表面上的所有點(diǎn)反射出來。如果場景中沒有環(huán)境光對象檬寂,這個屬性對節(jié)點(diǎn)沒有影響
  • Specular 鏡面反射是直接反射到使用者身上的光線终抽,類似于鏡子反射光線的方式。此屬性默認(rèn)為黑色桶至,這將導(dǎo)致材料顯得呆滯
  • Normal 正常照明是一種用于制造材料表面光反射的技術(shù)昼伴,基本上,它試圖找出材料的顛簸和凹痕镣屹,以提供更現(xiàn)實(shí)發(fā)光效果
  • Reflective 反射光屬性是一個鏡像表面反射環(huán)境圃郊。表面不會真實(shí)地反映場景中的其他物體
  • Emission 該屬性是由模型表面發(fā)出的顏色。默認(rèn)情況下女蜈,此屬性設(shè)置為黑色持舆。如果你提供了一個顏色色瘩,這個顏色就會體現(xiàn)出來,你可以提供一個圖像逸寓。SceneKit將使用此圖像提供“基于材料的發(fā)光效應(yīng)”居兆。
  • Transparent 用來設(shè)置材質(zhì)的透明度
  • Multiply 通過計算其他所有屬性的因素生成最終的合成的顏色
// 地球貼圖
    _earthNode.geometry.firstMaterial.diffuse.contents = @"art.scnassets/solar/earth-diffuse-mini.jpg";
    _earthNode.geometry.firstMaterial.emission.contents = @"art.scnassets/solar/earth-emissive-mini.jpg";
    _earthNode.geometry.firstMaterial.specular.contents = @"art.scnassets/solar/earth-specular-mini.jpg";

另外我們對SCNNode進(jìn)行copy時,其屬性SCNMaterial并不會執(zhí)行深拷貝竹伸,也就是說被拷貝對象屬性只是對原來屬性的引用而已泥栖。
**3. SCNLight **
SceneNode中完全都是動態(tài)光照,提供四種類型的光照

  • SCNLightTypeAmbient 環(huán)境光
  • SCNLightTypeOmni 聚光燈
  • SCNLightTypeDirectional 定向光源
  • SCNLightTypeSpot 點(diǎn)光源
    由于太陽作為太陽系的光源勋篓,所以我們需要能從各個角度看到它發(fā)光吧享,所以它的type = SCNLightTypeOmni,也就是聚光燈
//給sunNode添加光照
SCNNode *lightNode = [SCNNode node];
lightNode.light = [SCNLight light];
lightNode.light.color = [UIColor blackColor]; // initially switched off
lightNode.light.type = SCNLightTypeOmni;
[_sunNode addChildNode:lightNode];
    
 // Configure attenuation distances because we don't want to light the floor
lightNode.light.attenuationEndDistance = 19;
lightNode.light.attenuationStartDistance = 21;

添加動畫--CoreAnimation

地球自轉(zhuǎn)動畫

//earthNode以y軸不停的旋轉(zhuǎn)譬嚣,每次旋轉(zhuǎn)的周期為1s钢颂。
[_earthNoderunAction:[SCNActionrepeatActionForever:[SCNActionrotateByX:0y:2z:0duration:1]]];

月球自轉(zhuǎn)動畫

CABasicAnimation*animation = [CABasicAnimationanimationWithKeyPath:@"rotation"];//月球自轉(zhuǎn)
animation.duration=1.5; //自轉(zhuǎn)周期1.5s
animation.toValue= [NSValuevalueWithSCNVector4:SCNVector4Make(0,1,0,M_PI*2)];//此處的意思是圍繞y軸([0,0,0]->[0,1,0])旋轉(zhuǎn)360°
animation.repeatCount=FLT_MAX;//重復(fù)次數(shù),此處無限次
[_moonNode addAnimation:animation forKey:@"moon rotation"];//將動畫添加至moonNode節(jié)點(diǎn)

接下來我們來實(shí)現(xiàn)月球隨著地球公轉(zhuǎn)
??moonRotationNode添加moonNode孤荣,moonNode由于與原點(diǎn)有偏移甸陌,moonRotation自轉(zhuǎn)后就實(shí)現(xiàn)了moonNode圍繞原點(diǎn)公轉(zhuǎn)了须揣,然后再加moonRotationNode添加至earthGroupNode即可盐股。

_moonNode.position=SCNVector3Make(0.1,0,0);//設(shè)置moon的位置
SCNNode*moonRotationNode = [SCNNodenode];
[moonRotationNodeaddChildNode:_moonNode];
// Rotate the moon around the Earth
CABasicAnimation*moonRotationAnimation = [CABasicAnimationanimationWithKeyPath:@"rotation"];
moonRotationAnimation.duration=15.0;
moonRotationAnimation.toValue= [NSValuevalueWithSCNVector4:SCNVector4Make(0,1,0,M_PI*2)];
moonRotationAnimation.repeatCount=FLT_MAX;
[moonRotationNodeaddAnimation:animationforKey:@"moon rotation around earth"];
[_earthGroupNodeaddChildNode:moonRotationNode];//將moonRotationNode添加至earthGroupNode節(jié)點(diǎn)

如何實(shí)現(xiàn)地球子系統(tǒng)圍繞太陽公轉(zhuǎn)

SCNNode*earthRotationNode = [SCNNodenode];
[_sunNodeaddChildNode:earthRotationNode];
// Earth-group (will contain the Earth, and the Moon)
[earthRotationNodeaddChildNode:_earthGroupNode];
// Rotate the Earth around the Sun
animation = [CABasicAnimationanimationWithKeyPath:@"rotation"];
animation.duration=30.0;
animation.toValue= [NSValuevalueWithSCNVector4:SCNVector4Make(0,1,0,M_PI*2)];
animation.repeatCount=FLT_MAX;
[earthRotationNodeaddAnimation:animationforKey:@"earth rotation around sun"];

同理其他幾顆星體也可以如此,由于土星自帶行星環(huán)耻卡,需要額外處理一下疯汁。

CABasicAnimation*animation = [CABasicAnimationanimationWithKeyPath:@"rotation"];//月球自轉(zhuǎn)
animation.duration=1.5; //自轉(zhuǎn)周期1.5s
animation.toValue= [NSValuevalueWithSCNVector4:SCNVector4Make(0,1,0,M_PI*2)];//此處的意思是圍繞y軸([0,0,0]->[0,1,0])旋轉(zhuǎn)360°
animation.repeatCount=FLT_MAX;//重復(fù)次數(shù),此處無限次
[_moonNode addAnimation:animation forKey:@"moon rotation"];//將動畫添加至moonNode節(jié)點(diǎn)

為了讓太陽的效果更佳逼真卵酪,我們給它增加了光環(huán)

    // Add a halo to the Sun (a simple textured plane that does not write to depth)
    _sunHaloNode = [SCNNode node];
    _sunHaloNode.geometry = [SCNPlane planeWithWidth:2.5 height:2.5];
    _sunHaloNode.rotation = SCNVector4Make(1, 0, 0, 0 * M_PI / 180.0);
    _sunHaloNode.geometry.firstMaterial.diffuse.contents = @"art.scnassets/solar/sun-halo.png";
    _sunHaloNode.geometry.firstMaterial.lightingModelName = SCNLightingModelConstant; // no lighting
    _sunHaloNode.geometry.firstMaterial.writesToDepthBuffer = NO; // do not write to depth
    _sunHaloNode.opacity = 0.2;
    [_sunNode addChildNode:_sunHaloNode];

我們還給地球增加云層

SCNNode *cloudsNode = [SCNNode node];
    cloudsNode.geometry = [SCNSphere sphereWithRadius:0.06];
    [_earthNode addChildNode:cloudsNode];
    
    cloudsNode.opacity = 0.5;
    // This effect can also be achieved with an image with some transparency set as the contents of the 'diffuse' property
    cloudsNode.geometry.firstMaterial.transparent.contents = @"art.scnassets/solar/cloudsTransparency.png";
    cloudsNode.geometry.firstMaterial.transparencyMode = SCNTransparencyModeRGBZero;

以上我們就實(shí)現(xiàn)了太陽系的模型創(chuàng)建以及行星的自轉(zhuǎn)并周期的圍繞太陽公轉(zhuǎn)幌蚊,但是如何才能有更好的觀看效果呢,于是我們記起了上章講到的ARKit溃卡,通過ARSession的一個Delegate函數(shù)

//pragma mark -ARSessionDelegate
//會話位置更新
-- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame
{
    //監(jiān)聽手機(jī)的移動溢豆,實(shí)現(xiàn)近距離查看太陽系細(xì)節(jié),為了凸顯效果變化值*3
    [_sunNode setPosition:SCNVector3Make(
                          -3 * frame.camera.transform.columns[3].x, 
                          -0.1 - 3 * frame.camera.transform.columns[3].y, 
                          -2 - 3 * frame.camera.transform.columns[3].z)];
}

小結(jié)

這樣我們就完成了一個通過ARKit+SceneKit實(shí)現(xiàn)將太陽系裝進(jìn)iPhone的夢想了瘸羡,女朋友說我想要天上的星星漩仙,于是我打開了ARSolarPlay抓住了Solar,你看整個太陽系盡在我的掌中犹赖,說吧队他,你想要哪顆?簡直撩妹/漢神器有木有峻村。

代碼見同性交友網(wǎng)站:https://github.com/miliPolo/ARSolarPlay(OC實(shí)現(xiàn))
????????????????????https://github.com/miliPolo/ARSolarPlaySwift(Swift實(shí)現(xiàn))

上一篇文章:如何用ARKit將太陽系裝進(jìn)iPhone(一)


如果您覺得有價值麸折,請在github賞個star,不勝感激粘昨。
如果有什么想交流的垢啼,歡迎私信窜锯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市芭析,隨后出現(xiàn)的幾起案子衬浑,更是在濱河造成了極大的恐慌,老刑警劉巖放刨,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件工秩,死亡現(xiàn)場離奇詭異,居然都是意外死亡进统,警方通過查閱死者的電腦和手機(jī)助币,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來螟碎,“玉大人眉菱,你說我怎么就攤上這事〉舴郑” “怎么了俭缓?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長酥郭。 經(jīng)常有香客問我华坦,道長,這世上最難降的妖魔是什么不从? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任惜姐,我火速辦了婚禮,結(jié)果婚禮上椿息,老公的妹妹穿的比我還像新娘歹袁。我一直安慰自己,他們只是感情好寝优,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布条舔。 她就那樣靜靜地躺著,像睡著了一般乏矾。 火紅的嫁衣襯著肌膚如雪孟抗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天妻熊,我揣著相機(jī)與錄音夸浅,去河邊找鬼。 笑死扔役,一個胖子當(dāng)著我的面吹牛帆喇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亿胸,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼坯钦,長吁一口氣:“原來是場噩夢啊……” “哼预皇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起婉刀,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吟温,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后突颊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鲁豪,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年律秃,在試婚紗的時候發(fā)現(xiàn)自己被綠了爬橡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡棒动,死狀恐怖糙申,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情船惨,我是刑警寧澤柜裸,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站粱锐,受9級特大地震影響疙挺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卜范,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一衔统、第九天 我趴在偏房一處隱蔽的房頂上張望鹿榜。 院中可真熱鬧海雪,春花似錦、人聲如沸舱殿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沪袭。三九已至湾宙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冈绊,已是汗流浹背侠鳄。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留死宣,地道東北人伟恶。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像毅该,于是被迫代替她去往敵國和親博秫。 傳聞我的和親對象是個殘疾皇子潦牛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容