SceneKit_高级06_加载顶点、纹理、法线坐标

2022-05-13 16:10:37 浏览数 (1)

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 这个单词很熟悉吧。

核心技术实战

今天就是用这个技术加载一个正方形,效果如下

让学习成为一种习惯

  • 第一步.先定义一下几个坐标和视图颜色
代码语言:javascript复制
    /// 创建顶点坐标
    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]
  • 第二步 导入游戏框架
代码语言:javascript复制
 import SceneKit
  • 第三步 创建视图
代码语言:javascript复制
  let scnView = SCNView(frame: self.view.bounds)
  self.view.addSubview(scnView)
  scnView.backgroundColor = UIColor.black
  • 第四步 创建场景
代码语言:javascript复制
  let scene = SCNScene()
  scnView.scene = scene
  • 第五步 创建一个照相机
代码语言:javascript复制
  let cameraNode  = SCNNode()
  cameraNode.camera = SCNCamera()
  cameraNode.position = SCNVector3(x:0,y:0,z:0)
  scene.rootNode.addChildNode(cameraNode)
  • 第六步 创建一个没有绑定几何体的节点
代码语言:javascript复制
  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 简单很多,后面还有更神奇的东西要公布出来,敬请期待!


代码库,听说经常给人点赞都当老板了!

0 人点赞