我正在使用金属与Swift为iOS构建一个3D查看器,我有一些问题,以使深度工作。从现在开始,我可以在3D中正确地绘制和渲染单个形状(比如一个简单的方形平面(4个三角形(每个面2个)或一个四面体(4个三角形))。然而,当我试图把两个形状画在一起时,这两个形状之间的深度是不起作用的。例如,平面放置在Z轴= 0后面的四边形,该四边形放置在Z>0。如果我从后面看这个场景(相机放在Z<0的某个地方),那就没问题了。但是当我从前面看这个场景(相机放置在Z>0的某个地方)时,它就不工作了。即使平面被放置在四边形后面,它也是在四边形之前绘制的。


我认为飞机总是在四边形之前的屏幕上绘制(不管相机的位置),因为drawPrimitives对飞机的调用是在调用四边形之前完成的。但是,我认为所有的深度和模板设置都会正确地处理这个问题。我不知道深度是否有效,因为深度纹理、模具状态等没有正确设置,或者每个形状都是在不同的drawPrimitives调用中绘制的。
换句话说,我是否必须在drawPrimitives的同一个调用中绘制所有形状才能使深度工作?这个对drawPrimitives的多次调用的思想是针对每个形状(三角形、直线或…)处理不同类型的原语类型。。
以下是我如何设置深度模板状态、深度纹理和呈现管道:
init() {
// some miscellaneous initialisation …
// …
// all MTL stuff :
commandQueue = device.makeCommandQueue()
// Stencil descriptor
let depthStencilDescriptor = MTLDepthStencilDescriptor()
depthStencilDescriptor.depthCompareFunction = .less
depthStencilDescriptor.isDepthWriteEnabled = true
depthStencilState = device.makeDepthStencilState(descriptor: depthStencilDescriptor)!
// Library and pipeline descriptor & state
let library = try! device.makeLibrary(source: shaders, options: nil)
// Our vertex function name
let vertexFunction = library.makeFunction(name: "basic_vertex_function")
// Our fragment function name
let fragmentFunction = library.makeFunction(name: "basic_fragment_function")
// Create basic descriptor
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
// Attach the pixel format that si the same as the MetalView
renderPipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float_stencil8
renderPipelineDescriptor.stencilAttachmentPixelFormat = .depth32Float_stencil8
//renderPipelineDescriptor.stencilAttachmentPixelFormat = .stencil8
// Attach the shader functions
renderPipelineDescriptor.vertexFunction = vertexFunction
renderPipelineDescriptor.fragmentFunction = fragmentFunction
// Try to update the state of the renderPipeline
do {
renderPipelineState = try device.makeRenderPipelineState(descriptor: renderPipelineDescriptor)
} catch {
print(error.localizedDescription)
}
// Depth Texture
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .stencil8, width: 576, height: 723, mipmapped: false)
desc.storageMode = .private
desc.usage = .pixelFormatView
depthTexture = device.makeTexture(descriptor: desc)!
// Uniforms buffer
modelMatrix = Matrix4()
modelMatrix.multiplyLeft(worldMatrix)
uniformBuffer = device.makeBuffer( length: MemoryLayout<Float>.stride*16*2, options: [])
let bufferPointer = uniformBuffer.contents()
memcpy(bufferPointer, &modelMatrix.matrix.m, MemoryLayout<Float>.stride * 16)
memcpy(bufferPointer + MemoryLayout<Float>.stride * 16, &projectionMatrix.matrix.m, MemoryLayout<Float>.stride * 16)
}而抽签功能:
function draw(in view: MTKView) {
// create render pass descriptor
guard let drawable = view.currentDrawable,
let renderPassDescriptor = view.currentRenderPassDescriptor else {
return
}
renderPassDescriptor.depthAttachment.texture = depthTexture
renderPassDescriptor.depthAttachment.clearDepth = 1.0
//renderPassDescriptor.depthAttachment.loadAction = .load
renderPassDescriptor.depthAttachment.loadAction = .clear
renderPassDescriptor.depthAttachment.storeAction = .store
// Create a buffer from the commandQueue
let commandBuffer = commandQueue.makeCommandBuffer()
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
commandEncoder?.setRenderPipelineState(renderPipelineState)
commandEncoder?.setFrontFacing(.counterClockwise)
commandEncoder?.setCullMode(.back)
commandEncoder?.setDepthStencilState(depthStencilState)
// Draw all obj in objects
// objects = array of Object; each object describing vertices and primitive type of a shape
// objects[0] = Plane, objects[1] = Tetra
for obj in objects {
createVertexBuffers(device: view.device!, vertices: obj.vertices)
commandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
commandEncoder?.setVertexBuffer(uniformBuffer, offset: 0, index: 1)
commandEncoder?.drawPrimitives(type: obj.primitive, vertexStart: 0, vertexCount: obj.vertices.count)
}
commandEncoder?.endEncoding()
commandBuffer?.present(drawable)
commandBuffer?.commit()
}有没有人知道什么是错的,什么是缺失的?欢迎任何建议!
编辑09/23/2022:代码更新
发布于 2022-09-20 19:13:20
我头上没有几样东西:
let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .depth32Float_stencil8, width: 576, height: 723, mipmapped: false)
renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float_stencil8
注意,两个地方的pixeFormat应该是相同的,而且由于您似乎也在使用模具测试,所以depth32Float_stencil8将是完美的。
现在你似乎缺少的另一件事是,在每次渲染之前清除深度纹理,对吗?因此,您应该将深度附件的加载操作设置为renderPassDescriptor.depthAttachment.loadAction = .clear,如下所示:
如果上述任何一种方法都不起作用,则可能需要在返回的颜色有alpha 0时调用,从而丢弃片段函数中带有alpha =0的框架。
还注意到了未来:
理想情况下,当每个新框架开始呈现时,深度纹理都是新鲜的和空的(首先绘制呈现传递的调用),然后通过设置load操作.load和存储操作.store,将其重用到后续的绘制调用中。
例:假设你有3次绘图调用,假设在一个框架中绘制多边形-- wiz三角形、矩形、球体,那么您的深度附件设置应该如下所示:
框架1启动:
- loadAction: Clear
- storeAction: Store- loadAction: load
- storeAction: Store- loadAction: load
- storeAction: store/dontcare框架2启动:通知您清除新帧的第一次绘制调用的深度缓冲区
- loadAction: Clear
- storeAction: Store- loadAction: load
- storeAction: Store- loadAction: load
- storeAction: store/dontcare发布于 2022-09-17 14:10:22
深度纹理像素格式不正确,请尝试将其像素格式更改为:MTLPixelFormatDepth32Float或MTLPixelFormatDepth32Float_Stencil8。
https://stackoverflow.com/questions/73754319
复制相似问题