首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS使用MetalKit和Swift深度的3D查看器不起作用

iOS使用MetalKit和Swift深度的3D查看器不起作用
EN

Stack Overflow用户
提问于 2022-09-17 11:05:26
回答 2查看 148关注 0票数 0

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

我认为飞机总是在四边形之前的屏幕上绘制(不管相机的位置),因为drawPrimitives对飞机的调用是在调用四边形之前完成的。但是,我认为所有的深度和模板设置都会正确地处理这个问题。我不知道深度是否有效,因为深度纹理、模具状态等没有正确设置,或者每个形状都是在不同的drawPrimitives调用中绘制的。

换句话说,我是否必须在drawPrimitives的同一个调用中绘制所有形状才能使深度工作?这个对drawPrimitives的多次调用的思想是针对每个形状(三角形、直线或…)处理不同类型的原语类型。。

以下是我如何设置深度模板状态、深度纹理和呈现管道:

代码语言:javascript
复制
   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)
   }

而抽签功能:

代码语言:javascript
复制
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:代码更新

EN

回答 2

Stack Overflow用户

发布于 2022-09-20 19:13:20

我头上没有几样东西:

  • First

let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .depth32Float_stencil8, width: 576, height: 723, mipmapped: false)

  • Second

renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float_stencil8

注意,两个地方的pixeFormat应该是相同的,而且由于您似乎也在使用模具测试,所以depth32Float_stencil8将是完美的。

  • Third

现在你似乎缺少的另一件事是,在每次渲染之前清除深度纹理,对吗?因此,您应该将深度附件的加载操作设置为renderPassDescriptor.depthAttachment.loadAction = .clear,如下所示:

  • Fourth (主观对你的使用)*

如果上述任何一种方法都不起作用,则可能需要在返回的颜色有alpha 0时调用,从而丢弃片段函数中带有alpha =0的框架。

还注意到了未来:

理想情况下,当每个新框架开始呈现时,深度纹理都是新鲜的和空的(首先绘制呈现传递的调用),然后通过设置load操作.load和存储操作.store,将其重用到后续的绘制调用中。

例:假设你有3次绘图调用,假设在一个框架中绘制多边形-- wiz三角形、矩形、球体,那么您的深度附件设置应该如下所示:

框架1启动:

  • 第一张画:三角形

代码语言:javascript
复制
- loadAction: Clear
- storeAction: Store

  • 第二绘图:矩形

代码语言:javascript
复制
- loadAction: load
- storeAction: Store

  • 第三次抽签:球形

代码语言:javascript
复制
- loadAction: load
- storeAction: store/dontcare

框架2启动:通知您清除新帧的第一次绘制调用的深度缓冲区

  • 第一张画:三角形

代码语言:javascript
复制
- loadAction: Clear
- storeAction: Store

  • 第二绘图:矩形

代码语言:javascript
复制
- loadAction: load
- storeAction: Store

  • 第三次抽签:球形

代码语言:javascript
复制
- loadAction: load
- storeAction: store/dontcare
票数 1
EN

Stack Overflow用户

发布于 2022-09-17 14:10:22

深度纹理像素格式不正确,请尝试将其像素格式更改为:MTLPixelFormatDepth32FloatMTLPixelFormatDepth32Float_Stencil8

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73754319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档