我使用Blender创建了3D对象,并将其导出为OBJ文件,并按照此http://metalbyexample.com/modern-metal-1教程尝试使用Metal渲染它。但是我的某些3D对象零件丢失了。它们显示不正确。
这是我的搅拌器文件:- 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)
}
这是我的顶点和片段着色器:-
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);
}
这是我的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()
}
呈现可绘制对象的位置在另一个位置。
如何使用Metal正确渲染3D对象?
答案 0 :(得分:0)
如果未正确对3D模型进行三角剖分,则会错过Metal中的行为。为了正确地渲染3D模型,从建模软件导出到OBJ文件时,请启用Triangulate Faces选项。这会将所有面变成三角形。因此,Metal不必重新对这些面进行三角剖分。但是此过程可能会更改顶点顺序。但是3D模型不会改变。只有顶点的顺序会改变。
答案 1 :(得分:0)
我发布了这个公共仓库:https://github.com/danielrosero/ios-touchingMetal,我认为这是使用Metal,纹理和计算功能进行3d渲染的一个很好的起点。
您应该只更改内部模型,检查Renderer.swift init(view: MTKView)
方法。
// Create the MTLTextureLoader options that we need according to each model case. Some of them are flipped, and so on.
let textureLoaderOptionsWithFlip: [MTKTextureLoader.Option : Any] = [.generateMipmaps : true, .SRGB : true, .origin : MTKTextureLoader.Origin.bottomLeft]
let textureLoaderOptionsWithoutFlip: [MTKTextureLoader.Option : Any] = [.generateMipmaps : true, .SRGB : true]
// ****
// Initializing the models, set their position, scale and do a rotation transformation
// Cat model
cat = Model(name: "cat",vertexDescriptor: vertexDescriptor,textureFile: "cat.tga", textureLoaderOptions: textureLoaderOptionsWithFlip)
cat.transform.position = [-1, -0.5, 1.5]
cat.transform.scale = 0.08
cat.transform.rotation = vector_float3(0,radians(fromDegrees: 180),0)
// ****
// Dog model
dog = Model(name: "dog",vertexDescriptor: vertexDescriptor,textureFile: "dog.tga", textureLoaderOptions: textureLoaderOptionsWithFlip)
dog.transform.position = [1, -0.5, 1.5]
dog.transform.scale = 0.018
dog.transform.rotation = vector_float3(0,radians(fromDegrees: 180),0)
// ****
这是我在实现中导入模型的方式,请检查Model.swift
//
// Model.swift
// touchingMetal
//
// Created by Daniel Rosero on 1/8/20.
// Copyright © 2020 Daniel Rosero. All rights reserved.
//
import Foundation
import MetalKit
//This extension allows to create a MTLTexture attribute inside this Model class
//in order to be identified and used in the Renderer. This is to ease the loading in case of multiple models in the scene
extension Model : Texturable{
}
class Model {
let mdlMeshes: [MDLMesh]
let mtkMeshes: [MTKMesh]
var texture: MTLTexture?
var transform = Transform()
let name: String
//In order to create a model, you need to pass a name to use it as an identifier,
// a reference to the vertexDescriptor, the imagename with the extension of the texture,
//the dictionary of MTKTextureLoader.Options
init(name: String, vertexDescriptor: MDLVertexDescriptor, textureFile: String, textureLoaderOptions: [MTKTextureLoader.Option : Any]) {
let assetUrl = Bundle.main.url(forResource: name, withExtension: "obj")
let allocator = MTKMeshBufferAllocator(device: Renderer.device)
let asset = MDLAsset(url: assetUrl, vertexDescriptor: vertexDescriptor, bufferAllocator: allocator)
let (mdlMeshes, mtkMeshes) = try! MTKMesh.newMeshes(asset: asset, device: Renderer.device)
self.mdlMeshes = mdlMeshes
self.mtkMeshes = mtkMeshes
self.name = name
texture = setTexture(device: Renderer.device, imageName: textureFile, textureLoaderOptions: textureLoaderOptions)
}
}