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 类型,所以我们写个函数统一处理一下
代码语言:javascript复制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 对象
代码语言:javascript复制 /// 创建接受顶点的对象
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)
上面就完成了对应对象的创建,接下来创建几何对象
代码语言:javascript复制 let geometry = SCNGeometry(sources: [vertexSource,textureSource,normalSource,colorSource], elements: [indicesElement])
绑定这个几何对象,到我们对应的节点上去
代码语言:javascript复制bindNode.geometry = geometry
总结
本节的内容,教会大家如何动态的加载顶点,纹理,法线,颜色,索引数组,是不是比OpenGL ES 简单很多,后面还有更神奇的东西要公布出来,敬请期待!
代码库,听说经常给人点赞都当老板了!