How to animate 3d asset (.obj) file loaded with Model I/O framework on metal
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
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.
swift 3d metal vertex-buffer metalkit
|
show 6 more comments
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.
swift 3d metal vertex-buffer metalkit
It seems to me that you could load the vertex offsets into your ownMTLBuffer
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
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
|
show 6 more comments
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.
swift 3d metal vertex-buffer metalkit
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.
swift 3d metal vertex-buffer metalkit
swift 3d metal vertex-buffer metalkit
asked Nov 16 '18 at 16:01
Ivan TkachenkoIvan Tkachenko
11615
11615
It seems to me that you could load the vertex offsets into your ownMTLBuffer
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
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
|
show 6 more comments
It seems to me that you could load the vertex offsets into your ownMTLBuffer
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
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
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
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
@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
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
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
1
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
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
|
show 6 more comments
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53341430%2fhow-to-animate-3d-asset-obj-file-loaded-with-model-i-o-framework-on-metal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53341430%2fhow-to-animate-3d-asset-obj-file-loaded-with-model-i-o-framework-on-metal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
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
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