How do you alter MTKMesh vertexBuffer data?

I would like to alter vertex data from a model imported with Model I/O in iOS 10. I'm doing this to normalize the vertex positions, change their color values, and some other fun things.


After I create the mesh, I'd like to get to buffer data to change it. So I dive in and grab the MTLBuffer contents:


MTKMesh >> vertexBuffers >> vertexBuffer >> buffer >> contents()


The problem is, on iOS 9 I get back an array with the values I expect, in order, according to the vertexDescriptor I submitted to the MDLAsset. But in iOS 10, what I get back is gibberish.


To demonstrate, in my model object's init method, I'm printing the values of the vertexBuffer:


init(kitMesh: MTKMesh, modelMesh: MDLMesh, device: MTLDevice) {    
     let vertexBuffer = kitMesh.vertexBuffers[0]
     let floatData = vertexBuffer.buffer.contents().bindMemory(to: Float.self, capacity: vertexBuffer.length / MemoryLayout<Float>.stride)
     for i in 0..<100 {
         print("data [\(i)] = \(floatData[i])")
     }
}


Console on iOS 9 (correct - matches vertex descriptor):


data [0] = -1.30764
data [1] = 0.142407
data [2] = 2.24837
data [3] = -0.0059
data [4] = 0.986
data [5] = -0.1665
data [6] = 0.0
data [7] = 0.0
data [8] = 0.0
data [9] = 1.0
data [10] = 0.00255011
data [11] = -1.72002
data [12] = 0.072178
data [13] = 1.84713
etc...

Console on iOS 10:


data [0] = 0.0
data [1] = 1.4013e-45
data [2] = 2.8026e-45
data [3] = 4.2039e-45
data [4] = 5.60519e-45
data [5] = 7.00649e-45
data [6] = 8.40779e-45
data [7] = 9.80909e-45
data [8] = 1.12104e-44
data [9] = 1.26117e-44
data [10] = 1.4013e-44
data [11] = 1.54143e-44
data [12] = 1.68156e-44
etc...

How can I alter the vertex buffer in iOS 10? Is there a different method I don't know about?

Replies

I've created a small test project to show what I mean. The project just creates an MDLAsset from two model objects (an OBJ and a STL). It then prints off what should be the first vertex of each.


On both iOS 9 and 10, the STL works. But on iOS 10 the OBJ does not work.


You can grab it here:

github.com/bitshapesoft/ModelIOVertexBufferContents

First, let me clarify that an MTKMesh is simply a wrapper for data created by Model IO in a MDLMesh. So while you can modify data in a MTKMesh's vertexBuffer, but you can't resize the the MTKMeshBuffer or swap it out one the MTKMesh has been create. For that you need to modify the MDLMesh before you create the MTKMesh.


Also, you should know that there can be data for multiple MTKMeshBuffers in a single MTLBuffer. The data for a given MTKMeshBuffer is stored at the address of the buffer's content plus the value of MTKMeshBuffer.offfset property. In other words, the data for MTKMeshBuffer is at MTKMeshBuffer.buffer.contents + MTKMeshBuffer.offset.


Another thing you need to consider is that the layout of the data may not be a 32-bit float as it was on iOS9. You need to look at the MDLMesh.vertexDescriptor to determine the data type.


For these two reasons, you may be seeing gibberish in iOS10 where you didn't in iOS9


I'm not particularly knowledgeable about swift, but I think this can be pretty tricky to do in Swfit, because the language generally wants to protect you from problems caused by accessing raw memory, which is what buffer.contents is.