Hi John
When you say it doesn’t execute properly, what happens? I copied your code into Model.swift and it worked for me in Chapter 7 final project code (after fixing the unfortunate typedef
problem in Common.h - if you are getting a segmentation fault, that’s the reason. See here for the fix).
Having said that, you might find it hard to adjust material properties with the primitive. I cheat and export from Blender. You can create primitives cubes and cones and spheres there and export them as objs. You can then edit the .mtl file in Xcode to adjust material properties more easily.
The render won’t look great until you introduce reflection and IBL (Image Based Lighting) in Chapter 12, “Environment”.
The best link for understanding PBR is Substance becomes Adobe Substance 3D
P. S. There is a correction to chapter 7 which will hopefully appear in the next edition. If you’re not using maps, roughness
and metallic
need to be defined in the .mtl file as three floats. In Submesh.swift where you read the roughness
and metallic
properties, you check for a float3
and then use floatValue
as before. Only the first of the three floats is used, but Model I/O won’t recognise the roughness
property without it being a float3
.
Full init(name:)
:
init(name: String) {
let allocator = MTKMeshBufferAllocator(device: Renderer.device)
let mdlMesh = MDLMesh(sphereWithExtent: [0.5, 0.5, 0.5],
segments: [40, 40],
inwardNormals: false,
geometryType: .triangles,
allocator: allocator)
mdlMesh.addTangentBasis(forTextureCoordinateAttributeNamed:
MDLVertexAttributeTextureCoordinate,
tangentAttributeNamed: MDLVertexAttributeTangent,
bitangentAttributeNamed:
MDLVertexAttributeBitangent)
Model.defaultVertexDescriptor = mdlMesh.vertexDescriptor
let mesh = try! MTKMesh(mesh: mdlMesh, device: Renderer.device)
self.mesh = mesh
vertexBuffer = mesh.vertexBuffers[0].buffer
submeshes = mdlMesh.submeshes?.enumerated().compactMap {index, submesh in
(submesh as? MDLSubmesh).map {
Submesh(submesh: mesh.submeshes[index],
mdlSubmesh: $0)
}
}
?? []
samplerState = Model.buildSamplerState()
super.init()
}