I am developing a Metal macOS app that displays my own 3D models and some other 3D model.obj I import through the Model I/O. I am getting some conflict between my own vertexDescriptor and the vertexDescriptor embedded into the model.obj.
I have found a patch to the trouble creating a brand new MTLRenderPipelineState per each model.obj imported (with its own vertexDescriptor), but I think this is not the proper way to do. I cannot imagine that I have to create a brand new MTLRenderPipelineState per each model (read each "different vertexDescriptor") imported. Any clue to work with a unique MTLRenderPipelineState for all the models in the app?
Here's a sample case. I create my own vertexDescriptor
Buffer 0:
stepFunction = MTLVertexStepFunctionPerVertex
stride = 64
Attribute 0: // Position
offset = 0
format = MTLAttributeFormatFloat3
Attribute 1: // Normal
offset = 16
format = MTLAttributeFormatFloat3
Attribute 2: // Texture Coords
offset = 32
format = MTLAttributeFormatFloat2
Attribute 3: // Vertex Color
offset = 48
format = MTLAttributeFormatFloat4
and I use it to configure my MTLRenderPipelineState accordingly with my vertex shader MyVertexShader's argument
struct VertexIn
{
float4 position[[attribute(0)]];
float4 normal[[attribute(1)]];
float2 uvTex[[attribute(2)]];
float4 color[[attribute(3)]];
};
Everything works well with the models I create myself using always the same VertexIn structure. But when I import a model.obj file with Model I/O and automatically get this vertexDescriptor
Buffer 0:
stepFunction = MTLVertexStepFunctionPerVertex
stride = 32
Attribute 0: // Position
offset = 0
format = MTLAttributeFormatFloat3
Attribute 1: // Normal
offset = 12
format = MTLAttributeFormatFloat3
Attribute 2: // Texture Coords
offset = 24
format = MTLAttributeFormatFloat2
the stride is 32 (mine above is 64), the 4th attribute (color) is missed, so the model.obj looks jerky on the MTKView.
So, I created a brand new MTLRenderPipelineState only to draw this model.obj using the model.obj's vertexDescriptor and my own vertex shader function MyVertexShader. Well, I got this error
*Error: Vertex attribute color(3) is missing from the vertex descriptor*
So I added the 4th attribute color to the model.obj vertexDescriptor
if(objVertexDescriptor.attributes[3].format == MTLVertexFormatInvalid)
{
// add the color attribute to the model.obj vertexDescriptor
objVertexDescriptor.attributes[3].format = MTLVertexFormatFloat4;
objVertexDescriptor.attributes[3].offset = sizeof(simd_float3) + sizeof(simd_float3) + sizeof(simd_float3);
objVertexDescriptor.attributes[3].bufferIndex = 0;
}
then I created a brand new MTLRenderPipelineState with this objVertexDescriptor and my own vertex shader function MyVertexShader, and the model.obj finally looked well on the MTKView.
I feel that what I'm doing it's just a bad patch to this trouble and I think there should be a better and reusable way to solve the conflict hopefully using the same MTLRenderPipelineState for all the models. I can't accept I should create a new pipeline per each model the user will import. Any idea?
I have found the solution. When I create the
MDLAsset, I pass my ownmDefaultMDLVertexDescriptorI created earlier and use all over my code. This forces the asset to adopt that vertexDescriptor.So even the
MDLMeshand theMTKMeshcreated from the asset get that vertexDescriptorYou could verify the mesh has that vertexDescriptor with
and even with