首页 > 解决方案 > How to build data for a SCNGeometrySource in Swift

问题描述

I try to build a SCNGeometrySource in swift.

I want to use the SCNGeometrySource(data: Data, semantic: SCNGeometrySource.Semantic, vectorCount: Int, usesFloatComponents: Bool, componentsPerVector: Int, bytesPerComponent: Int, dataOffset: Int, dataStride: Int) initializer, because I have already a buffer giving vertex position, normal and colors - or at least, I can build it.

But how do I transform my buffer into a Data type (for the data parameter) ?

Using Data(bytesNoCopy: buffer as! UnsafeMutableRawPointer ...) gives me a warning that the cast will fail (and I believed it).

I have also tried with no success to use Data.append(xxx)functions, but there is no way I could find to just cast the address of my larger buffer into an UnsafePointer of any kind (and it also implies an additional copy of the large buffer).

So what's the way ?

Edit: the "large buffer" is a concatenation of

struct VertexInfo {
    var x: Float
    var y: Float
    var z: Float
    var nx: Float
    var ny: Float
    var nz: Float
    var a: Float
    var r: Float
    var g: Float
    var b: Float
}

I can provide it under any type, but for the time being, I build it with a UnsafeMutableBufferPointer<VertexInfo>

标签: swiftscenekit

解决方案


这就是我解决问题的方法:我使用 anUnsafeMutableRawPointer直接使用分配“大缓冲区”malloc()并构建Data使用Data(bytesNoCopy:length:freeWhenDone:),这并不意味着数据的另一个副本。

现在,为了填充“大缓冲区”,我使用了 aUnsafeMutablePointer<VertexInfo>来简化操作,但秘诀是使用bindMemory(to:capacity:).

这样, UnsafeMutableRawPointer 和 UnsafeMutablePointer 实际指向同一个缓冲区。UnsafeMutablePointer 可用于轻松地用数据填充缓冲区,UnsafeMutableRawPointer 可轻松用于创建数据。

// Assuming VertexInfo type holds the information for a vertex
// Assuming we have vectorMaxCount as the number of vertices we want

// Compute the size of the buffer to allocate
var size       = vectorMaxCount * MemoryLayout<VertexInfo>.stride
// Allocate the buffer as a UnsafeMutableRawPointer
var buffer     = malloc(size)
// Create a UnsafeMutablePointer<VertexInfo> that points to the allocated buffer
var vertexList = buffer!.bindMemory(to: VertexInfo.self, capacity: vectorMaxCount)

// Fill the buffer with the needed data
for index in 0..< vectorMaxCount {
    let vertex = // Compute here your vertex info as a VertexInfo
    // Easily fill the buffer thanks to the UnsafeMutablePointer<VertexInfo>
    vertexList[index] = vertex
}

// Create the Data thanks to the UnsafeMutableRawPointer
let data = NSData(bytesNoCopy: buffer, length: size, freeWhenDone: true) as Data

请注意,缓冲区的所有权是通过参数赋予数据的freeWhenDone: true

这是非常通用的,可用于构建任何压缩的数据缓冲区,不仅适用于 SceneKit。


推荐阅读