SceneKit_入門01_旋轉人物
SceneKit_入門02_如何創建工程
SceneKit_入門03_節點
SceneKit_入門04_燈光
SceneKit_入門05_照相機
SceneKit_入門06_行為動畫
SceneKit_入門07_幾何體
SceneKit_入門08_材質
SceneKit_入門09_物理身體
SceneKit_入門10_物理世界
SceneKit_入門11_粒子系統
SceneKit_入門12_物理行為
SceneKit_入門13_骨骼動畫
SceneKit_中級01_模型之間的過渡動畫
SceneKit_中級02_SCNView 詳細講解
SceneKit_中級03_切換照相機視角
SceneKit_中級04_約束的使用
SceneKit_中級05_力的使用
SceneKit_中級06_場景的切換
SceneKit_中級07_動態修改屬性
SceneKit_中級08_陰影詳解
SceneKit_中級09_碰撞檢測
SceneKit_中級10_濾鏡效果制作
SceneKit_中級11_動畫事件
SceneKit_高級01_GLSL
SceneKit_高級02_粒子系統深入研究
SceneKit_高級03_自定義力
SceneKit_高級04_自定義場景過渡效果
SceneKit_高級05 檢測手勢點擊到節點
SceneKit_高級06_加載頂點、紋理、法線坐標
SceneKit_高級07_SCNProgram用法探究
SceneKit_高級08_天空盒子制作
SceneKit_高級09_霧效果
SceneKit_大神01_掉落的文字
SceneKit_大神02_彈幕來襲
SceneKit_大神03_navigationbar上的3D文字
和你聊聊
學過OpenGL 的同學們,都知道幾個名字頂點坐標,紋理坐標,法線坐標,索引,顏色數據,我們通過相應的api 可以把這些數據加入到GPU 中去,我們知道SceneKit 是封裝了OpenGL 和Metal ,在這里不得不說蘋果公司很人性化,開放給我們的接口還是比較多的,我們經常有一些需求,尤其是3D 開發,后臺會把一些模型數據流傳給前端,前端需要解析出來,然后顯示到頁面上,這個就需要用到今天我們講的技術。
讓人激動不已的兩個類
- SCNGeometrySource
負責加載頂點數據,紋理數據,顏色數據,紋理坐標
- SCNGeometryElement
負責加載索引數據,相信學習過OpenGL 的同學對 Element 這個單詞很熟悉吧。
核心技術實戰
今天就是用這個技術加載一個正方形,效果如下
- 第一步.先定義一下幾個坐標和視圖顏色
/// 創建頂點坐標
let vertex:[Float] = [-1,1,-5,
1,1,-5,
1,-1,-5,
-1,-1,-5]
/// 創建紋理坐標
let texture:[Float] = [0,0,
1,0,
1,1,
0,1]
/// 法線索引
let normal:[Float] = [0,0,1,
0,0,1,
0,0,1,
0,0,1]
/// 顏色坐標
let color:[Float] = [1,0,0,
0,1,0,
0,0,1,
1,1,1]
/// 創建頂點索引
let indices:[GLint] = [0,1,2,0,2,3]
- 第二步 導入游戲框架
import SceneKit
- 第三步 創建視圖
let scnView = SCNView(frame: self.view.bounds)
self.view.addSubview(scnView)
scnView.backgroundColor = UIColor.black
- 第四步 創建場景
let scene = SCNScene()
scnView.scene = scene
- 第五步 創建一個照相機
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x:0,y:0,z:0)
scene.rootNode.addChildNode(cameraNode)
- 第六步 創建一個沒有綁定幾何體的節點
let bindNode = SCNNode()
scene.rootNode.addChildNode(bindNode)
注意了,前方高能,打點雞血,抖擻精神。
我們在加載上面的數據之前,要將其轉換為NSData 類型或者Data 類型,所以我們寫個函數統一處理一下
func getData<T>(array:[T])->Data{
let data:UnsafeMutableRawPointer = malloc(MemoryLayout<T>.size*array.count)
data.initializeMemory(as: T.self, from: array)
return NSData(bytesNoCopy: data, length: MemoryLayout<T>.size*array.count, freeWhenDone: true) as Data
}
提示:
我們定義為泛型接口,因為數組中的值類型不一樣,MemoryLayout<T>.size 這個swift 里面獲取數據占用內存字節的寫法,ObjectC 是sizeof(T) 的寫法
我們創建SCNGeometrySource 和 SCNGeometryElement 對象
/// 創建接受頂點的對象
let vertexSource = SCNGeometrySource(data: getData(array: vertex), semantic: SCNGeometrySource.Semantic.vertex, vectorCount: 4, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<Float>.size*3)
/// 創建紋理坐標對象
let textureSource = SCNGeometrySource(data: getData(array: texture), semantic: SCNGeometrySource.Semantic.texcoord, vectorCount: 4, usesFloatComponents: true, componentsPerVector: 2, bytesPerComponent: MemoryLayout<Float>.size, dataOffset:0, dataStride: MemoryLayout<Float>.size*2)
/// 法線坐標對象
let normalSource = SCNGeometrySource(data: getData(array: normal), semantic: SCNGeometrySource.Semantic.normal, vectorCount: 4, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<Float>.size*3)
/// 顏色對象
let colorSource = SCNGeometrySource(data: getData(array: color), semantic: SCNGeometrySource.Semantic.color, vectorCount: 4, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<Float>.size*3)
/// 頂點索引
let indicesElement = SCNGeometryElement(data: getData(array: indices), primitiveType: SCNGeometryPrimitiveType.triangleStrip, primitiveCount: indices.count, bytesPerIndex: MemoryLayout<GLint>.size)
上面就完成了對應對象的創建,接下來創建幾何對象
let geometry = SCNGeometry(sources: [vertexSource,textureSource,normalSource,colorSource], elements: [indicesElement])
綁定這個幾何對象,到我們對應的節點上去
bindNode.geometry = geometry
總結
本節的內容,教會大家如何動態的加載頂點,紋理,法線,顏色,索引數組,是不是比OpenGL ES 簡單很多,后面還有更神奇的東西要公布出來,敬請期待!
代碼庫,聽說經常給人點贊都當老板了!