SceneKit

                https://github.com/rectinajh/ScenkitDemo  

Scene Kit是一個(gè)蘋(píng)果Cocoa風(fēng)格的3D渲染框架竞阐,該框架被引入OS X是在WWDC 2012 (那時(shí) OS X 系統(tǒng)還在用喵系命名)。在第一版通用 3D 渲染器發(fā)布后,一年內(nèi)又陸續(xù)增加了像 shader (著色器) 修改器、節(jié)點(diǎn)約束桑涎、骨骼動(dòng)畫(huà)等幾個(gè)強(qiáng)大的特性 (隨 Mavericks 發(fā)布)。 今年(2014年)豫喧,Scene Kit 變的更加強(qiáng)大石洗,支持了粒子效果、物理引擎紧显、腳本事件以及多通道分層渲染等多種技術(shù),以及(也許對(duì)許多人來(lái)說(shuō)最重要的)它被引入iOS缕棵,而蘋(píng)果現(xiàn)在指的是把它當(dāng)成“休閑游戲”的套件孵班。

從一開(kāi)始,我發(fā)現(xiàn)Scene Kit的最大優(yōu)勢(shì)和差異在于與其他圖形框架招驴,如Core Image篙程,Core Animation,Sprite Kit的集成别厘。 這在其他游戲引擎中可不常見(jiàn)虱饿,但是如果你是一個(gè)業(yè)余愛(ài)好者,或者主要是Cocoa 或 Cocoa Touch 框架下的開(kāi)發(fā)者,那么這意味著很多東西應(yīng)該很親切了氮发。

Scene Kit 概要

Scene Kit 構(gòu)建在OpenGL之上渴肉,其中燈光,幾何圖形爽冕,材料和相機(jī)等高級(jí)引擎特性仇祭,這些組件都是面向?qū)ο蟮模憧梢杂檬煜さ?Objective-C 或 Swift 語(yǔ)言來(lái)編寫(xiě)代碼颈畸。 如果用過(guò)最早的版本的OpenGL乌奇,那時(shí)還沒(méi)有 shader,只能苦逼的使用各種底層受限制的 API 開(kāi)發(fā)眯娱。 幸運(yùn)的是 Scene Kit 就好了很多礁苗,高級(jí)配置對(duì)于大多數(shù)常見(jiàn)任務(wù)是足夠的 - 甚至更先進(jìn)的功能,如動(dòng)態(tài)陰影和景深效果徙缴,使用它提供的上層 API 來(lái)配置寂屏,就已經(jīng)足夠了。 不僅如此娜搂,Scene Kit 還允許你直接調(diào)用底層 API迁霎,或自己寫(xiě) shader 進(jìn)行手動(dòng)渲染 (GLSL)。

節(jié)點(diǎn) (Nodes)

除了燈光百宇,幾何圖形考廉,材料和相機(jī)這幾個(gè)具體的對(duì)象之外,Scene Kit還使用節(jié)點(diǎn)層次來(lái)組織其內(nèi)容携御。 每個(gè)節(jié)點(diǎn)相對(duì)于其父節(jié)點(diǎn)具有位置昌粤,旋轉(zhuǎn)和縮放,而父節(jié)點(diǎn)又相對(duì)于其父節(jié)點(diǎn)啄刹,一直向上涮坐,直到根節(jié)點(diǎn)。 假如要給一個(gè)節(jié)點(diǎn)確定一個(gè)位置誓军,就必須將它掛載到節(jié)點(diǎn)樹(shù)中的某個(gè)節(jié)點(diǎn)上袱讹。 使用以下方法管理節(jié)點(diǎn)層次結(jié)構(gòu):

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

這些方法與 iOS 和 OS X 中管理 view 和 layer 層級(jí)方法如出一轍。

幾何模型對(duì)象
Scene Kit 內(nèi)建了幾種簡(jiǎn)單的幾何模型昵时,如盒子捷雕、球體、平面壹甥、圓錐體等救巷,對(duì)于游戲,一般都會(huì)從文件中加載3D模型句柠。你可以通過(guò)制定文件名來(lái)導(dǎo)入 (或?qū)С? COLLADA 格式的模型文件:

        let chessPieces = SCNScene(named: "chess pieces") // SCNScene?

如果一個(gè)從文件里加載的場(chǎng)景可以全部顯示時(shí)浦译,將其設(shè)置成SCNView 的 scene 就好了棒假。 如果場(chǎng)景包含多個(gè)對(duì)象,但是屏幕上只能顯示一些對(duì)象精盅,則可以它們的名稱找到它帽哑,并將其添加到SCNView中呈現(xiàn)的Scene中:

      if let knight =           chessPieces.rootNode.childNodeWithName("Knight", recursively: true) {
sceneView.scene?.rootNode.addChildNode(knight)

}

這是一個(gè)對(duì)導(dǎo)入文件原始節(jié)點(diǎn)的引用,其中包含了任一和每一個(gè)子節(jié)點(diǎn)渤弛,也包括了模型對(duì)象 (包括其材質(zhì))祝拯,光照,以及綁定在這些節(jié)點(diǎn)上的攝像機(jī)她肯。只要傳入的名字一樣佳头,不論調(diào)用多少次,返回的都是對(duì)同一個(gè)對(duì)象的引用晴氨。

textures.png

若需要在場(chǎng)景中擁有一個(gè)節(jié)點(diǎn)的多個(gè)拷貝康嘉,如在一個(gè)國(guó)際象棋棋盤(pán)上顯示兩個(gè)馬,你可以對(duì)馬這個(gè)節(jié)點(diǎn)進(jìn)行 copy 或 clone (遞歸的copy)籽前。這將會(huì)拷貝一份節(jié)點(diǎn)的引用亭珍,但兩份引用所指向的材質(zhì)對(duì)象和模型對(duì)象仍然是原來(lái)那個(gè)。所以枝哄,想要單獨(dú)改變副本材質(zhì)的話肄梨,需要再copy一份模型對(duì)象,并對(duì)這個(gè)新的模型對(duì)象設(shè)置新材質(zhì)挠锥。copy一個(gè)模型對(duì)象的速度仍然很快众羡,開(kāi)銷也不高,因?yàn)楦北疽玫捻旤c(diǎn)數(shù)據(jù)還是同一份蓖租。

帶有骨骼動(dòng)畫(huà)的模型對(duì)象也會(huì)擁有一個(gè)皮膚對(duì)象粱侣,它提供了對(duì)骨骼中各個(gè)節(jié)點(diǎn)的訪問(wèn)接口,以及管理骨骼和模型間連接的功能蓖宦。每個(gè)單獨(dú)的骨骼都可以被移動(dòng)和旋轉(zhuǎn)齐婴,而復(fù)雜的動(dòng)畫(huà)需要同時(shí)對(duì)多塊骨骼進(jìn)行操作,如一個(gè)角色走路的動(dòng)畫(huà)稠茂,很可能就是從文件讀取并加到對(duì)象上的 (而不是用代碼一根骨頭一根骨頭的寫(xiě))柠偶。

光照

Scene Kit 中完全都是動(dòng)態(tài)光照,使用起來(lái)一般會(huì)很簡(jiǎn)單主慰,但也意味著與完整的游戲引擎相比嚣州,光照這塊進(jìn)步并不明顯。Scene Kit 提供四種類型的光照:環(huán)境光共螺、定向光源、點(diǎn)光源和聚光燈情竹。

通常來(lái)說(shuō)藐不,旋轉(zhuǎn)坐標(biāo)軸和變換角度并不是設(shè)定光照的最佳方法。下面的例子表示一個(gè)光照對(duì)象通過(guò)一個(gè)節(jié)點(diǎn)對(duì)象來(lái)設(shè)置空間坐標(biāo),再通過(guò) "look at" 約束雏蛮,將光照對(duì)象約束到了目標(biāo)對(duì)象上涎嚼,即使它移動(dòng),光照也會(huì)一直朝向目標(biāo)對(duì)象挑秉。

    let spot = SCNLight()
    spot.type = SCNLightTypeSpot
    spot.castsShadow = true

    let spotNode = SCNNode()
    spotNode.light = spot
    spotNode.position = SCNVector3(x: 4, y: 7, z: 6)

    let lookAt = SCNLookAtConstraint(target: knight)
    spotNode.constraints = [lookAt]
spinning.gif

動(dòng)畫(huà)

Scene Kit 的對(duì)象中絕大多數(shù)屬性都是可以進(jìn)行動(dòng)畫(huà)的法梯,就像 Cocoa (或 Cocoa Touch) 框架一樣,你可以創(chuàng)建一個(gè) CAAnimation 對(duì)象犀概,并指定一個(gè) key path (甚至可以 "position.x") 立哑,然后向一個(gè)對(duì)象施加這個(gè)動(dòng)畫(huà)。同樣的姻灶,你可以在 SCNTransaction 的 "begin" 和 "commit" 調(diào)用間去改變值铛绰,和剛才的 CAAnimation 非常相似:

    let move = CABasicAnimation(keyPath: "position.x")
    move.byValue  = 10
    move.duration = 1.0
    knight.addAnimation(move, forKey: "slide right")

Scene Kit 也提供了像 Sprite Kit 那樣的 action 形式的動(dòng)畫(huà) API,你可以創(chuàng)建串行的動(dòng)畫(huà)組产喉,也支持自定義 action 來(lái)協(xié)同使用捂掰。與 Core Animation 不同的是,這些 action 作為游戲循環(huán)的一部分執(zhí)行曾沈,在每一幀都更新模型對(duì)象的值这嚣,而不只是更新表現(xiàn)層的節(jié)點(diǎn)。

假如你之前用過(guò) Sprite Kit塞俱,會(huì)發(fā)現(xiàn) Scene Kit 除了變成了 3D 之外姐帚,沒(méi)有太多陌生的東西。目前敛腌,在 iOS8 (首次支持 Scene Kit) 和 OS X 10.10 下卧土,Scene Kit 和 Sprite Kit 可以協(xié)同工作:對(duì) Sprite Kit 來(lái)說(shuō),3D 模型可以與 2D 精靈混合使用像樊;對(duì) Scene Kit 來(lái)說(shuō)尤莺,Sprite Kit 中的場(chǎng)景和紋理可以作為 Scene Kit 的紋理貼圖,而且 Sprite Kit 的場(chǎng)景可以作為 Scene Kit 場(chǎng)景的蒙層 (如3D游戲中的2D菜單面板生棍,譯者注颤霎。兩套非常像的API和概念 (像場(chǎng)景啊,節(jié)點(diǎn)啊涂滴,約束啊兩邊都有)友酱, 讓人容易混淆。

開(kāi)始用 Scene Kit 寫(xiě)游戲

不僅是動(dòng)作和紋理柔纵,Scene Kit 和 Sprite Kit 還有很多相同之處缔杉。當(dāng)開(kāi)始寫(xiě)游戲的時(shí)候,Scene Kit 和它 2D 版本的小伙伴非常相似搁料,它們的游戲循環(huán)步驟完全一致或详,使用下面幾個(gè)代理回調(diào):

1系羞,更新場(chǎng)景
2,應(yīng)用動(dòng)畫(huà)/動(dòng)作
3霸琴,模擬物理效果
4椒振,應(yīng)用約束
5,渲染
gameloop.png

這些回調(diào)在每幀被調(diào)用梧乘,并用來(lái)執(zhí)行游戲相關(guān)的邏輯澎迎,如用戶輸入,AI (人工智能) 和游戲腳本选调。

處理用戶輸入
Scene Kit 與普通 Cocoa 或 Cocoa Touch 應(yīng)用使用一樣的機(jī)制來(lái)處理用戶輸入夹供,如鍵盤(pán)事件、鼠標(biāo)事件学歧、觸摸事件和手勢(shì)識(shí)別罩引,而主要區(qū)別在于 Scene Kit 中只有一個(gè)視圖,場(chǎng)景視圖 (scene view) 枝笨。像鍵盤(pán)事件或如捏取袁铐、滑動(dòng)、旋轉(zhuǎn)的手勢(shì)横浑,只要知道事件的發(fā)生就好了剔桨,但像鼠標(biāo)點(diǎn)擊,或觸碰徙融、拖動(dòng)手勢(shì)等就需要知道具體的事件信息了洒缀。

這些情況下,scene view 可以使用 -hitTest(_: options:) 來(lái)做點(diǎn)擊測(cè)試欺冀。與通常的視圖只返回被點(diǎn)擊的子 view 或子 layer 不同树绩,Scene Kit 返回一個(gè)數(shù)組,里面存有每個(gè)相交的模型對(duì)象以及從攝像機(jī)投向這個(gè)測(cè)試點(diǎn)的射線隐轩。每個(gè) hit test 的結(jié)果包含被擊中模型的節(jié)點(diǎn)對(duì)象饺饭,也包含了交點(diǎn)的詳細(xì)信息 (交點(diǎn)坐標(biāo)、交點(diǎn)表面法線职车,交點(diǎn)的紋理坐標(biāo))瘫俊。多數(shù)情況下,知道第一個(gè)被擊中的節(jié)點(diǎn)就足夠了:

      if let firstHit = sceneView.hitTest(tapLocation, options: nil)?.first as? SCNHitTestResult     {
let hitNode = firstHit.node
// do something with the node that was hit...

}

擴(kuò)展默認(rèn)渲染流程

光照和材質(zhì)的配置方法很易用悴灵,但有局限性扛芽。假如你有寫(xiě)好的 OpenGL 著色器 (shader),可以用于完全自定制的進(jìn)行材質(zhì)渲染积瞒;如果你只想修改下默認(rèn)的渲染川尖,Scene Kit 暴露了 4 個(gè)入口用于插入 shader代碼 (GLSL) 來(lái)改變默認(rèn)渲染。Scene Kit 在不同入口點(diǎn)分別提供了對(duì)旋轉(zhuǎn)矩陣茫孔、模型數(shù)據(jù)空厌、樣本貼圖及渲染后輸出的色值的訪問(wèn)庐船。
比如银酬,下面的 GLSL 代碼被用在模型數(shù)據(jù)的入口點(diǎn)中嘲更,可以將模型對(duì)象上所有點(diǎn)沿 x 軸扭曲。這是通過(guò)定義一個(gè)函數(shù)來(lái)創(chuàng)建一個(gè)旋轉(zhuǎn)變換揩瞪,并將其應(yīng)用在模型的位置和法線上赋朦。同時(shí),也自定義了一個(gè) "uniform" 變量來(lái)決定對(duì)象該如何被扭曲李破。

// a function that creates a rotation transform matrix around X
mat4 rotationAroundX(float angle)
{
return mat4(1.0, 0.0, 0.0, 0.0,
0.0, cos(angle), -sin(angle), 0.0,
0.0, sin(angle), cos(angle), 0.0,
0.0, 0.0, 0.0, 1.0);
}

    #pragma body

    uniform float twistFactor = 1.0;
    float rotationAngle = _geometry.position.x * twistFactor;
    mat4 rotationMatrix = rotationAroundX(rotationAngle);

    // position is a vec4
    _geometry.position *= rotationMatrix;

    // normal is a vec3
    vec4 twistedNormal = vec4(_geometry.normal, 1.0) *             rotationMatrix;
  _geometry.normal   = twistedNormal.xyz;

著色修改器 (Shader modifier) 既可以綁定在模型對(duì)象上宠哄,也可以綁定在它的材質(zhì)對(duì)象上。這兩個(gè)類都完全支持 key-value coding (KVC)嗤攻,你可以指定任意 key 進(jìn)行賦值毛嫉。在 shader 中聲明的 "twistFactor" uniform 變量使得 Scene Kit 在這個(gè)值改變時(shí)自動(dòng)重新綁定 uniform,這使得你也可以用 KVC 來(lái)實(shí)現(xiàn):

    torus.setValue(5.0, forKey: "twistFactor")

使用這個(gè) key path 的 CAAnimation 也 ok:

    let twist = CABasicAnimation(keyPath: "twistFactor")
    twist.fromValue = 5
    twist.toValue   = 0
    twist.duration  = 2.0

    torus.addAnimation(twist, forKey: "Twist the torus")
twist.gif

延時(shí)著色

即使在純 OpenGL 環(huán)境下妇菱,有些圖像效果也無(wú)法通過(guò)一次渲染 pass 完成承粤,我們可以將不同 shader 進(jìn)行序列操作,以達(dá)到后續(xù)處理的目的闯团,稱為延時(shí)著色辛臊。Scene Kit 使用 SCNTechnique 類來(lái)表示這種技術(shù)。它使用字典來(lái)創(chuàng)建房交,字典中定義了繪圖步驟彻舰、輸入輸出、shader 文件候味、符號(hào)等等刃唤。
第一個(gè)渲染 pass 永遠(yuǎn)是 Scene Kit 的默認(rèn)渲染,它輸出場(chǎng)景的顏色和景深白群。如果你不想這時(shí)計(jì)算色值尚胞,可以將材質(zhì)設(shè)置成"恒定"的光照模型,或者將場(chǎng)景里所有光照都設(shè)置成環(huán)境光川抡。
比如辐真,從 Scene Kit 渲染流程的第一個(gè) pass 獲取景深,第二個(gè)獲取法線崖堤,第三個(gè)對(duì)其執(zhí)行邊界檢測(cè)侍咱,你即可以沿輪廓也可以沿邊緣畫(huà)粗線:

參考資料:
https://developer.apple.com/documentation/scenekit
https://developer.apple.com/videos/play/wwdc2014/609/
https://developer.apple.com/videos/play/wwdc2013/500/
https://www.objc.io/issues/18-games/scenekit/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市密幔,隨后出現(xiàn)的幾起案子楔脯,更是在濱河造成了極大的恐慌,老刑警劉巖胯甩,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昧廷,死亡現(xiàn)場(chǎng)離奇詭異堪嫂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)木柬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)皆串,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人眉枕,你說(shuō)我怎么就攤上這事恶复。” “怎么了速挑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵谤牡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我姥宝,道長(zhǎng)翅萤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任腊满,我火速辦了婚禮套么,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糜烹。我一直安慰自己违诗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布疮蹦。 她就那樣靜靜地躺著诸迟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愕乎。 梳的紋絲不亂的頭發(fā)上阵苇,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音感论,去河邊找鬼绅项。 笑死,一個(gè)胖子當(dāng)著我的面吹牛比肄,可吹牛的內(nèi)容都是我干的快耿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芳绩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掀亥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起妥色,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤搪花,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體撮竿,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吮便,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幢踏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片髓需。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖惑折,靈堂內(nèi)的尸體忽然破棺而出授账,到底是詐尸還是另有隱情,我是刑警寧澤惨驶,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站敛助,受9級(jí)特大地震影響粗卜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纳击,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一续扔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧焕数,春花似錦纱昧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至善已,卻和暖如春灼捂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背换团。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工悉稠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艘包。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓的猛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親想虎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卦尊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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