1
votes

I'm trying to render a mesh with an additional attribute present in the vertex data, but I'm noticing that the offset value I've set in the vertex descriptor for this attribute doesn't seem to be respected. It's acting like the offset is zero, thus pulling in vertex values instead of the data I'm looking for.

My vertex data is defined like so:

vertices      metadata
0, 1, 0, 1,   1, 0,
0, 1, 0, 0,   4, 0,

In the shader, I pull this in like so:

typedef struct {
  float4 data [[attribute(0)]];
  float2 index [[attribute(1)]];
} Vertex;

vertex ColorInOut vertexShader(Vertex in [[stage_in]], 
                  constant VertexShaderUniforms & u [[ buffer(2) ]]) {...}

I'm then setting up the vertex descriptor to handle this format:

auto _mtlVertexDescriptor = [[MTLVertexDescriptor alloc] init];

_mtlVertexDescriptor.attributes[0].format = MTLVertexFormatFloat4;
_mtlVertexDescriptor.attributes[0].offset = 0;
_mtlVertexDescriptor.attributes[0].bufferIndex = 0;

_mtlVertexDescriptor.attributes[1].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[1].offset = sizeof(vector_float4);
_mtlVertexDescriptor.attributes[1].bufferIndex = 0;

_mtlVertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
_mtlVertexDescriptor.layouts[0].stepRate = 1;
_mtlVertexDescriptor.layouts[0].stride = sizeof(vector_float4) + sizeof(vector_float2);

In the Metal debugger, I'm noticing that instead of the data entries above, I'm seeing the following output in the Geometry viewer:

vertices      metadata
0, 1, 0, 1,   0, 1,
0, 1, 0, 0,   0, 1,

As it might be important to this situation, I should point out that I load my models manually as I'm plugging this in as an extra render option to my application, I'm doing this in the following way:

std::vector<float> vertices = {...};
auto allocator = [[MTKMeshBufferAllocator alloc] initWithDevice:device];
auto vertexData = [NSData dataWithBytes: vertices.data() length:vertices.size() * sizeof(float)];
auto vertexBuffer = [allocator newBufferWithData:vertexData type:MDLMeshBufferTypeVertex];

auto mdlVertexDescriptor = MTKModelIOVertexDescriptorFromMetal(vertexDescriptor);
// For this particlular example, `row_size` is 6, corresponding to the number of values in each vertex
auto mdlMesh = [[MDLMesh alloc] initWithVertexBuffer:vertexBuffer vertexCount:vertices.size() / row_size descriptor:mdlVertexDescriptor submeshes:@[]];
mdlMesh.vertexDescriptor = mdlVertexDescriptor;

NSError* error = nil;
auto m = [[MTKMesh alloc] initWithMesh:mdlMesh
                              device:device
                               error:&error];

Is there any magic invocation I'm missing to get the offset applying properly?

[edit]

I've verified that the same issue is present in the vertex buffer object itself. I've confirmed that the vertex descriptor being passed into the MTKModelIOVertexDescriptorFromMetal call is the expected descriptor, and I've also confirmed that the raw data in the NSData object is identical to the std::vector values, so the issue may lie in how I'm interacting with MDLMesh.

1
You show your vertex data in the abstract. How are you actually filling in the vertex buffer? Show the code. Also, try examining that buffer directly (rather than the geometry viewer) in the Metal debugger to confirm that it contains the data you expect.Ken Thomases
Hey @KenThomases, I've just added that info as I agree it may be important.lyptt
@KenThomases I've inspected the vertex buffer directly and it looks like it's exhibiting the same issue, so this looks like an issue with how I'm loading the mesh.lyptt
a simpler Metal question .. stackoverflow.com/questions/57040279Fattie

1 Answers

0
votes

It seems that ModelIO expects the vertex descriptor attributes to all have names matching the field names used in the vertex buffer struct for the above scenario to work. I fixed this like so:

vertexDescriptor.attributes[0].name = @"data";
vertexDescriptor.attributes[1].name = @"index";

After attaching names to each attribute, the correct data was loaded by the shader.

I managed to find this information out through a random chance run-in with the header that declares the MTKModelIOVertexDescriptorFromMetal method. The requirement is mentioned right at the end:

This method can only set vertex format, offset, bufferIndex, and stride information in the produced Model I/O vertex descriptor. It does not add any semantic information such at attributes names. Names must be set in the returned Model I/O vertex descriptor before it can be applied to a a Model I/O mesh.