0

The obj file loaded with Model I/O. I receive vertex buffer and index buffer from mesh and submesh. I draw it with index buffer. In GPU buffer unpacked and load all triangles. When I load asset I am creating vertex descriptor, to say what should be loaded from 3D asset. When I pass it to shader I am using [[ stage_in ]] vertex parameter.

But somehow I need to change the structure of vertex that is created by loading model asset in parameter of vertex-shader function to pass more data with animation offset for each vertex. For example I need to pass data that in an 3D asset, to apply offset to all vertices.

vertex VertexOut vertex_main(VertexIn vertexIn [[ stage_in ]], constant Uniforms &uniforms [[ buffer(1) ]], uint vertexID [[ vertex_id ]]) {
    float4 worldPosition = uniforms.modelMatrix *float4(vertexIn.position, 1);
    VertexOut vertexOut;
    vertexOut.position = uniforms.viewProjectionMatrix * worldPosition;
    vertexOut.worldPosition = worldPosition.xyz;
    vertexOut.worldNormal = uniforms.normalMatrix * vertexIn.normal;
    vertexOut.texCoords = vertexIn.texCoords;
    return vertexOut; 
}

That how looks VertexIn

struct VertexIn {
    float3 position  [[attribute(0)]];
    float3 normal    [[attribute(1)]];
    float2 texCoords [[attribute(2)]];
};

Drawing of 3D asset

for mesh in meshes {
        for i in 0..<mesh.vertexBuffers.count {
            let vertexBuffer = mesh.vertexBuffers[i]
            commandEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: i)
        }

        for submesh in mesh.submeshes {
            let indexBuffer = submesh.indexBuffer
            commandEncoder.drawIndexedPrimitives(type: submesh.primitiveType,
                                                 indexCount: submesh.indexCount,
                                                 indexType: submesh.indexType,
                                                 indexBuffer: indexBuffer.buffer,
                                                 indexBufferOffset: indexBuffer.offset)
        }
}

Vertex descriptor for loading 3D Model asset

    let vertexDescriptor = MDLVertexDescriptor()
    vertexDescriptor.attributes[0] = MDLVertexAttribute(name: MDLVertexAttributePosition, format: .float3, offset: 0, bufferIndex: 0)
    vertexDescriptor.attributes[1] = MDLVertexAttribute(name: MDLVertexAttributeNormal, format: .float3, offset: MemoryLayout<Float>.size * 3, bufferIndex: 0)
    vertexDescriptor.attributes[2] = MDLVertexAttribute(name: MDLVertexAttributeTextureCoordinate, format: .float2, offset: MemoryLayout<Float>.size * 6, bufferIndex: 0)

    vertexDescriptor.layouts[0] = MDLVertexBufferLayout(stride: MemoryLayout<Float>.size * 8)

Thank you for help. P.S. I was trying to change after loading of 3d asset, but it fails, because I can't change the vertex buffer created with Model I/O.

Ivan Tkachenko
  • 489
  • 3
  • 10
  • It seems to me that you could load the vertex offsets into your own `MTLBuffer` and pass that as an argument to your vertex function. You'd probably want to use triple buffering to keep three "frames" of animation data in flight at once. – warrenm Nov 16 '18 at 17:10
  • @warrenm I've made it with buffer, just with one, without triple buffering, and it came out that the order of my buffer that consist of animation offset for each vertices is wrong. And that strange. Because I thought that is unpacked in same order as it goes in my .obj file with defined faces example(f 1/1/1'). But it appeared that no. Could I be wrong ? – Ivan Tkachenko Nov 19 '18 at 14:16
  • You absolutely can't rely on the order of vertices in the file to correspond 1:1 with the vertices in your buffer after loading. OBJ allows separate indexing of position, normal, and texcoord data, so the data in the resulting buffers is almost always in a completely different order than the input. Admittedly, that makes vertex animation based on offsets a challenge. – warrenm Nov 19 '18 at 18:00
  • If your animation data is dense (i.e., every frame has an offset for every vertex), you might be better off using a series of OBJ files that have absolute positions instead. Or use a format like glTF that has a notion of animation built into the format. – warrenm Nov 19 '18 at 18:02
  • And what you think about parsing 3D asset by myself. So that I can control Vertex struct that is sent to GPU? – Ivan Tkachenko Nov 21 '18 at 15:49
  • You can use an `MDLVertexDescriptor` to specify how data should be laid out. You can provide a vertex descriptor when loading an `MDLAsset`, or set the vertex descriptor of an `MDLMesh` to change its internal layout. – warrenm Nov 22 '18 at 03:47
  • But how I will add data to vertexbuffer created after asset loading? – Ivan Tkachenko Nov 22 '18 at 11:25
  • 1
    You can leave room in the vertex buffers by configuring the offsets of the attributes and the strides of the layouts. Then you can write the offsets into the "blank" space between vertices. But it seems you'd still need a way to determine the mapping from the vertices in the original model and the loaded vertices. – warrenm Nov 22 '18 at 16:58
  • And how to write offset in already created MTLBuffer? I thought, I should create a new one. But that's bad, because I should create such kind of data before rendering. – Ivan Tkachenko Dec 12 '18 at 17:02
  • You can use the `contents` property of a buffer to get a mutable pointer that you can write to. You're still responsible for ensuring correct synchronization, but buffers with shared or managed storage are mutable. – warrenm Dec 12 '18 at 18:25
  • You mean to use UnsafeMutableRawPointer? But how to use it. With store bytes method ? And how to count the offset after what I should write my new data ? – Ivan Tkachenko Dec 14 '18 at 15:29

0 Answers0