SceneKit

概述

SceneKit是用來(lái)構(gòu)建3D場(chǎng)景的框架,且可以與Core Animation和SpriteKit無(wú)縫交互盼理。在SceneKit中可以直接引入COLLADA行業(yè)標(biāo)準(zhǔn)文件制作好的3D模型或場(chǎng)景犁苏。

與SpriteKit一樣纹蝴,SceneKit通過(guò)場(chǎng)景(SCNScene)來(lái)顯示物體华蜒,場(chǎng)景包涵在SCNView官册。場(chǎng)景內(nèi)同樣是以節(jié)點(diǎn)的結(jié)構(gòu)來(lái)呈現(xiàn)物體宾茂。場(chǎng)景里可以包含這些類型的項(xiàng)目:

  • 幾何體 代碼建立的3D對(duì)象或從文件加載的3D模型瓷马,在它們上可以附加不同的材料來(lái)達(dá)成控制顏色,紋理跨晴,反光等效果
  • 照相機(jī) 這是你觀察這個(gè)場(chǎng)景的入口欧聘,可以設(shè)置位置和視角
  • 光源 有各種光源后面會(huì)提到
  • 物理實(shí)體 受物理特效控制的各種有實(shí)體的物體,也有許多種

使用SceneKit的方法不止有在SCNView內(nèi)部來(lái)使用端盆。還可以在Core Animation層的層次結(jié)構(gòu)中使用SCNLayer怀骤。使用SCNRender來(lái)渲染你自己的OpenGL渲染器。

SceneKit可以同時(shí)在IOS和OS X下工作

添加場(chǎng)景

首先要做的當(dāng)然是添加場(chǎng)景

//獲取SCNView
let scnView = self.view as! SCNView
//我自己的場(chǎng)景
let myScenes = myScene()
//將SCNView的場(chǎng)景設(shè)置為我的場(chǎng)景
scnView.scene = myScenes

添加照相機(jī)

照相機(jī)是你觀察你構(gòu)建的3D場(chǎng)景的眼睛

//創(chuàng)建視角焕妙,可以說(shuō)是整個(gè)場(chǎng)景的入口蒋伦,沒(méi)有視角沒(méi)法觀察一個(gè)3D場(chǎng)景
let myCamera = SCNCamera()
myCamera.xFov = 45
myCamera.yFov = 45
let myCameraNode = SCNNode()
myCameraNode.camera = myCamera
myCameraNode.position = SCNVector3(0, 0, 20)
//向場(chǎng)景添加節(jié)點(diǎn)與SpriteKit有些不一樣
myScenes.rootNode.addChildNode(myCameraNode)

添加3D對(duì)象

//創(chuàng)建膠囊
let capsule = SCNCapsule(capRadius: 2.5, height: 10)
//SCNCapsule是SCNGeomery的一個(gè)子類,通過(guò)這個(gè)類可以創(chuàng)建更多的形狀
let capsuleNode = SCNNode(geometry: capsule)
capsuleNode.position = SCNVector3(-15, -2.8, 0)//節(jié)點(diǎn)的默認(rèn)位置是0焚鹊,0痕届,0
capsuleNode.name = "myCapsule"
myScenes.rootNode.addChildNode(capsuleNode)

添加光源

光源有許多種:

  • 環(huán)境光源,它在整個(gè)場(chǎng)景內(nèi)投射均勻光
  • 泛光源,這是用的最多的研叫,就是點(diǎn)光源锤窑,向各個(gè)方向投射光
  • 平行光源,在單個(gè)方向投射光
  • 聚光源嚷炉,在給定方向從單個(gè)位置投射光
//添加環(huán)境光源
let ambientLight = SCNLight()
//光源的類型渊啰,這里是環(huán)境光源
ambientLight.type = SCNLightTypeAmbient
ambientLight.color = UIColor(white: 0.25, alpha: 1.0)
let myAmbientLightNode = SCNNode()
myAmbientLightNode.light = ambientLight
myScenes.rootNode.addChildNode(myAmbientLightNode)
        
//添加泛光源
let omniLight = SCNLight()
omniLight.type = SCNLightTypeOmni
omniLight.color = UIColor(red: 0, green: 0, blue: 1, alpha: 1)
let omniLightNode = SCNNode()
omniLightNode.light = omniLight
omniLightNode.position = SCNVector3(-10, 8, 5)
myScenes.rootNode.addChildNode(omniLightNode)

添加動(dòng)畫

//向膠囊節(jié)點(diǎn)添加動(dòng)畫
let moveUpDownAnimation = CABasicAnimation(keyPath: "position")//這里的這個(gè)keyPath很重要,不是隨便寫一個(gè)就好的
moveUpDownAnimation.byValue = NSValue(SCNVector3: SCNVector3(30, 0, 0))//移動(dòng)的坐標(biāo)
moveUpDownAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)//移動(dòng)速度的曲線
moveUpDownAnimation.autoreverses = true//是否自動(dòng)返回
moveUpDownAnimation.repeatCount = Float.infinity//重復(fù)次數(shù)
moveUpDownAnimation.duration = 10.0//持續(xù)時(shí)間
capsuleNode.addAnimation(moveUpDownAnimation, forKey: "updown")//這里的這個(gè)keyPath貌似隨便寫就可以
        
//膠囊節(jié)點(diǎn)的子節(jié)點(diǎn)申屹,一個(gè)文本
let text = SCNText(string: "BaLaLaLa", extrusionDepth: 1)
text.font = UIFont.systemFontOfSize(2)
let textNode = SCNNode(geometry: text)
textNode.position = SCNVector3(-5, 6, 0)
capsuleNode.addChildNode(textNode)
        
//在一個(gè)節(jié)點(diǎn)上添加多個(gè)動(dòng)畫結(jié)果會(huì)復(fù)合虽抄,即便是繼承自父節(jié)點(diǎn)的動(dòng)畫也同樣一起復(fù)合
let rotate = CABasicAnimation(keyPath: "eulerAngles")
rotate.byValue = NSValue(SCNVector3: SCNVector3(Float(0), Float(M_PI * 2), Float(0)))
rotate.repeatCount = Float.infinity
rotate.duration = 5.0
textNode.addAnimation(rotate, forKey: "rotation")

使用材料

材料可以用來(lái)改變物體表面的樣子,材料使用SCNMaterial類來(lái)表示独柑,材料對(duì)象擁有許多許多屬性迈窟,比如:

  • diffuse(材料的基本顏色,紋理等)
  • specular(材料的亮度以及該如何反射光)
  • emissive(材料發(fā)光時(shí)的樣子)
  • normal(又稱為法向忌栅,設(shè)置材料表面更多的細(xì)節(jié))

每個(gè)屬性都擁有contents屬性车酣,給這個(gè)屬性設(shè)置不同的內(nèi)容來(lái)設(shè)置這些屬性的樣子:

  • 顏色
  • 圖像(NSImage等)
  • SpriteKit場(chǎng)景
  • SpriteKit紋理
//使用材料
let redMetallicMateril = SCNMaterial()
//contents設(shè)置為顏色
redMetallicMateril.diffuse.contents = UIColor.blueColor()
redMetallicMateril.specular.contents = UIColor.whiteColor()
redMetallicMateril.shininess = 1.0
//一個(gè)物體的材料是不唯一的,故傳進(jìn)去一個(gè)數(shù)組
capsule.materials = [redMetallicMateril]
        
let noiseTexture = SKTexture(noiseWithSmoothness: 0.25, size: CGSize(width: 512, height: 512), grayscale: true)
let noiseMaterial = SCNMaterial()
//contents設(shè)置為SpriteKit紋理
noiseMaterial.diffuse.contents = noiseTexture
text.materials = [noiseMaterial]

//法線貼圖
let noiseNormalMapTexture = noiseTexture.textureByGeneratingNormalMapWithSmoothness(1, contrast: 1.0)
redMetallicMateril.normal.contents = noiseNormalMapTexture

命中檢測(cè)

這個(gè)說(shuō)白了就是監(jiān)測(cè)你點(diǎn)擊了哪個(gè)物體索绪,首先當(dāng)然要添加手勢(shì)湖员。

//命中檢測(cè)
let tapRecognizer = UITapGestureRecognizer(target: self, action: "tapped:")
let longTapRecoginizer = UILongPressGestureRecognizer(target: self, action: "longTapped:")
scnView.addGestureRecognizer(tapRecognizer)
scnView.addGestureRecognizer(longTapRecoginizer)
scnView.userInteractionEnabled = true

接下來(lái)添加手勢(shì)對(duì)應(yīng)的執(zhí)行函數(shù)

    func tapped(tapRecognize: UIGestureRecognizer){
        if tapRecognize.state == UIGestureRecognizerState.Ended {
            let scnView = self.view as! SCNView
            //檢測(cè)點(diǎn)擊到哪個(gè),返回被點(diǎn)到的物體瑞驱,這里返回的數(shù)組里包含了你點(diǎn)擊的點(diǎn)順著屏幕法線穿過(guò)的所有的物體
            let hits = scnView.hitTest(tapRecognize.locationInView(tapRecognize.view), options: nil) as [SCNHitTestResult]
            for hit in hits {
                if let theMaterial = hit.node.geometry?.materials[0] {
                    let hightLightAnimation = CABasicAnimation(keyPath: "contents")
                    hightLightAnimation.fromValue = UIColor.blackColor()
                    hightLightAnimation.toValue = UIColor.yellowColor()
                    hightLightAnimation.autoreverses = true
                    hightLightAnimation.repeatCount = 2
                    hightLightAnimation.duration = 1
                    theMaterial.emission.addAnimation(hightLightAnimation, forKey: "heightLight")
                }
            }
        }
    }

為節(jié)點(diǎn)添加約束

//添加指向膠囊節(jié)點(diǎn)這個(gè)約束
let lookAtConstraint = SCNLookAtConstraint(target: capsuleNode)
//使其只圍繞一個(gè)軸轉(zhuǎn)動(dòng)
lookAtConstraint.gimbalLockEnabled = true
pointerNode.constraints = [lookAtConstraint]

從COLLADA文件中加載文件

//加載一個(gè)已經(jīng)建好的3D模型或場(chǎng)景娘摔,會(huì)是一個(gè)COLLADA文件,后綴名為.dae
let critterURL = NSBundle.mainBundle().URLForResource("Critter", withExtension: "dae")
let critterData = SCNSceneSource(URL: critterURL!, options: nil)
let critterNode = critterData?.entryWithIdentifier("Critter", withClass: SCNNode.self)
if (critterNode != nil) {
    critterNode!.position = SCNVector3(0, 0, -10)
    critterNode?.name = "Critter"
    myScenes.rootNode.addChildNode(critterNode!)
}

添加物理仿真

物理仿真和SpriteKit中的很像唤反,物理實(shí)體的類別有一些不同:

  • 靜態(tài)實(shí)體凳寺,從不移動(dòng),不受重力影響彤侍,但會(huì)碰撞
  • 運(yùn)動(dòng)學(xué)實(shí)體不受物理力的作用肠缨,但是它是有實(shí)體的,在動(dòng)畫中碰到其他物體會(huì)將它們推開盏阶。
  • 動(dòng)態(tài)實(shí)體受物理力及碰撞影響

神奇的是SceneKit為我們提供了地板類晒奕,它的幾何形狀就是一個(gè)地板

//像節(jié)點(diǎn)添加物理特性
var critterPhysicsShape: SCNPhysicsShape?
if let geometry = critterNode?.geometry {
    critterPhysicsShape = SCNPhysicsShape(geometry: geometry, options: nil)
}
let critterPhysicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Dynamic, shape: critterPhysicsShape)
critterPhysicsBody.mass = 1
critterNode?.physicsBody = critterPhysicsBody
        
//添加一個(gè)地板
let floor = SCNFloor()
let floorNode = SCNNode(geometry: floor)
floorNode.position = SCNVector3(0, -10, 0)
myScenes.rootNode.addChildNode(floorNode)
let floorPhysicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: SCNPhysicsShape(geometry: floor, options: nil))
floorNode.physicsBody = floorPhysicsBody
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市名斟,隨后出現(xiàn)的幾起案子脑慧,更是在濱河造成了極大的恐慌,老刑警劉巖砰盐,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闷袒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡楞卡,警方通過(guò)查閱死者的電腦和手機(jī)霜运,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門脾歇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人淘捡,你說(shuō)我怎么就攤上這事藕各。” “怎么了焦除?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵激况,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我膘魄,道長(zhǎng)乌逐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任创葡,我火速辦了婚禮浙踢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘灿渴。我一直安慰自己洛波,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布骚露。 她就那樣靜靜地躺著蹬挤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棘幸。 梳的紋絲不亂的頭發(fā)上焰扳,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音误续,去河邊找鬼吨悍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛女嘲,可吹牛的內(nèi)容都是我干的畜份。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼欣尼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了停蕉?” 一聲冷哼從身側(cè)響起愕鼓,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慧起,沒(méi)想到半個(gè)月后菇晃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚓挤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年磺送,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驻子。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡估灿,死狀恐怖崇呵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情馅袁,我是刑警寧澤域慷,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站汗销,受9級(jí)特大地震影響犹褒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜弛针,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一叠骑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧削茁,春花似錦宙枷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至厌衔,卻和暖如春璧帝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背富寿。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工睬隶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人页徐。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓苏潜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親变勇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恤左,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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