如何使用 Metal IOS 正确渲染 3D 模型?

Nil*_*epa 5 ios swift metal metalkit

我使用 Blender 创建了一个 3D 对象并将其导出为 OBJ 文件,并尝试按照此http://metalbyexample.com/modern-metal-1教程使用 Metal 渲染它。但我的一些 3D 物体部件丢失了。它们未正确呈现。

这是我在搅拌机中的 3D 对象:- 在此输入图像描述

这是我在 Metal 中渲染的对象:- 在此输入图像描述

这是我的搅拌机文件:- https://gofile.io/?c=XfQYLK

我应该如何解决这个问题?

我已经成功渲染了一些其他形状,如矩形、圆形、星形。但问题就出在这个形状上。我没有改变创建形状的方式,也没有改变从搅拌机导出形状的方式。即使我以同样的方式做了所有事情,问题仍然存在。

这是我加载 OBJ 文件的方法

private var vertexDescriptor: MTLVertexDescriptor!
private var meshes: [MTKMesh] = []

private func loadResource() {
        let modelUrl = Bundle.main.url(forResource: self.meshName, withExtension: "obj")
        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)
        self.vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(vertexDescriptor)

        let bufferAllocator = MTKMeshBufferAllocator(device: self.device)
        let asset = MDLAsset(url: modelUrl, vertexDescriptor: vertexDescriptor, bufferAllocator: bufferAllocator)
        (_, meshes) = try! MTKMesh.newMeshes(asset: asset, device: device)
}
Run Code Online (Sandbox Code Playgroud)

这是我的顶点和片段着色器:-

struct VertexOut {
    float4 position [[position]];
    float4 eyeNormal;
    float4 eyePosition;
    float2 texCoords;
};

vertex VertexOut vertex_3d(VertexIn vertexIn [[stage_in]])
{
    VertexOut vertexOut;
    vertexOut.position = float4(vertexIn.position, 1);
    vertexOut.eyeNormal = float4(vertexIn.normal, 1);
    vertexOut.eyePosition = float4(vertexIn.position, 1);
    vertexOut.texCoords = vertexIn.texCoords;
    return vertexOut;
}

fragment float4 fragment_3d(VertexOut fragmentIn [[stage_in]]) {
    return float4(0.33, 0.53, 0.25, 0.5);
}
Run Code Online (Sandbox Code Playgroud)

这是我的 CommandEncoder :-

func render(commandEncoder: MTLRenderCommandEncoder) {
    commandEncoder.setRenderPipelineState(self.renderPipelineState)
    let mesh = meshes[0]
    let vertexBuffer = mesh.vertexBuffers.first!
    commandEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: 0)
    let indexBuffer = mesh.submeshes[0].indexBuffer
    commandEncoder.drawIndexedPrimitives(type: mesh.submeshes[0].primitiveType,
                                                 indexCount: mesh.submeshes[0].indexCount,
                                                 indexType: mesh.submeshes[0].indexType,
                                                 indexBuffer: indexBuffer.buffer,
                                                 indexBufferOffset: indexBuffer.offset)
    commandEncoder.endEncoding()
}
Run Code Online (Sandbox Code Playgroud)

呈现给可绘制对象是在不同的地方处理的。

我应该如何使用 Metal 正确渲染 3D 对象?

Nil*_*epa 1

如果 3D 模型未正确进行三角测量,它将无法在 Metal 中表现。为了正确渲染 3D 模型,从建模软件导出到 OBJ 文件时,请打开 Triangulate Faces 选项。这会将所有面变成三角形。因此 Metal 不必重新对面进行三角测量。但这个过程可能会改变顶点顺序。但3D模型不会改变。只有顶点的顺序会改变。