Creating a Model Object With a Parametric Mesh

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).

49%20pm

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()
  }