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 ownmDefaultMDLVertexDescriptor
I created earlier and use all over my code. This forces the asset to adopt that vertexDescriptor.So even the
MDLMesh
and theMTKMesh
created from the asset get that vertexDescriptorYou could verify the mesh has that vertexDescriptor with
and even with