Next, I had time to look at the code today. The reason why the MDL primitive doesn’t load is because of the vertex descriptor.
This is vertexDescriptor
(with the float2 bug, and this screen shot is how I picked it up):

This is the vertex descriptor of the MLD primitive sphere:

Whereas I created vertexDescriptor
to be in two different buffers, Model I/O interweaved position, normal and uv in one buffer.
So I’ve created a new loading method for primitives. Add it in RenderExtension.swift:
func loadPrimitive(name: String, position: float3, scale: Float) {
let allocator = MTKMeshBufferAllocator(device: device)
let mesh: MDLMesh?
switch name {
case "cube":
mesh = MDLMesh(boxWithExtent: [1,1,1], segments: [1, 1, 1], inwardNormals: false, geometryType: .triangles, allocator: allocator)
case "sphere":
mesh = MDLMesh(sphereWithExtent: [1, 1, 1], segments: [50, 50], inwardNormals: false, geometryType: .triangles, allocator: allocator)
case "plane":
mesh = MDLMesh(planeWithExtent: [1, 1, 1], segments: [1, 1], geometryType: .triangles, allocator: allocator)
default:
mesh = nil
}
guard let mdlMesh = mesh else { return }
let positionData = mdlMesh.vertexAttributeData(forAttributeNamed: MDLVertexAttributePosition, as: .float3)!
let normalsdata = mdlMesh.vertexAttributeData(forAttributeNamed: MDLVertexAttributeNormal, as: .float3)!
let positionPtr = positionData.dataStart.bindMemory(to: float3.self, capacity: mdlMesh.vertexCount)
let normalsPtr = normalsdata.dataStart.bindMemory(to: float3.self, capacity: mdlMesh.vertexCount)
guard let submeshes = mdlMesh.submeshes as? [MDLSubmesh] else { return }
for submesh in submeshes {
var indices = submesh.indexBuffer.map().bytes.bindMemory(to: UInt16.self, capacity: submesh.indexCount)
for _ in 0..<submesh.indexCount {
let index = Int(indices.pointee)
vertices.append(positionPtr[index * 2] * scale + position)
normals.append(normalsPtr[index * 2])
indices = indices.advanced(by: 1)
let color: float3
if let baseColor = submesh.material?.property(with: .baseColor),
baseColor.type == .float3 {
color = baseColor.float3Value
} else {
color = [1, 1, 0]
}
colors.append(color)
}
}
}
You use it in the same way as loadAsset(name:position:scale:)
:
func createScene() {
loadAsset(name: "train", position: [-0.3, 0, 0.4], scale: 0.5)
loadAsset(name: "treefir", position: [0.5, 0, -0.2], scale: 0.7)
loadAsset(name: "plane", position: [0, 0, 0], scale: 10)
// loadAsset(name: "sphere", position: [-1.9, 0.0, 0.3], scale: 1)
// loadAsset(name: "sphere", position: [2.9, 0.0, -0.5], scale: 2)
loadPrimitive(name: "sphere", position: [-1.9, 0.0, 0.3], scale: 1)
loadPrimitive(name: "sphere", position: [2.9, 0.0, -0.5], scale: 2)
loadPrimitive(name: "cube", position: [0, 0.0, 0], scale: 1)
loadAsset(name: "plane-back", position: [0, 0, -1.5], scale: 10)
}
I believe there is a bug that I will have to report.
I was expecting:
let positionData = mdlMesh.vertexAttributeData(forAttributeNamed: MDLVertexAttributePosition, as: .float3)!
to return only position data from buffer 0. But it returned position / normal(?) / position / normal(?) / etc.
Which is why I did the index * 2
in the for loop.