使用 2 个管道进行金属渲染,第二个对象与第一个对象重叠

Posted

技术标签:

【中文标题】使用 2 个管道进行金属渲染,第二个对象与第一个对象重叠【英文标题】:Metal render with 2 pipelines, the second object overlap the first object 【发布时间】:2016-06-15 21:34:49 【问题描述】:

我有 2 个对象,一个有纹理,另一个没有纹理。我使用 2 个着色器并使用 2 个渲染管道来绘制 2 个对象。 2个对象画得很好......但是当第二个对象被绘制时......它与第一个对象重叠,所以只有第二个对象在屏幕上......不知道哪里出了问题......也许是因为管道在 draw() 函数的最后一部分没有正确使用。模型首先正确绘制,但是当天空被绘制时,模型消失了......请帮助我,,,谢谢 这是我的代码:

    class PanoViewController: GameViewController  
    //sky
    var depthStencilState: MTLDepthStencilState! = nil
    var vertexBufferSky: MTLBuffer! = nil
    var uniformBufferSky: MTLBuffer! = nil
    var depthTextureSky: MTLTexture! = nil
    var diffuseTextureSky: MTLTexture! = nil
    var samplerStateSky: MTLSamplerState! = nil
    //model
    var depthStencilStateModel: MTLDepthStencilState! = nil
    var vertexBufferModel: MTLBuffer! = nil
    var normalBufferModel: MTLBuffer! = nil
    var colorBufferModel: MTLBuffer! = nil
    var uniformBufferModel: MTLBuffer! = nil

    override func buildPipeline() 
        //Model
        let library = device!.newDefaultLibrary()!
        //pipeline descriptor
//        buildPipelinForSky(library)
//        buildPipelineForModel(library)
        //pipeline
        do 
            pipelineSky = try device!.newRenderPipelineStateWithDescriptor(buildPipelinForSky(library))
            pipelineModel = try device!.newRenderPipelineStateWithDescriptor(buildPipelineForModel(library))

         catch 
            print("error with device.newRenderPipelineStateWithDescriptor")
        

        let depthStencilDescriptor = MTLDepthStencilDescriptor()
        depthStencilDescriptor.depthCompareFunction = .Less
        depthStencilDescriptor.depthWriteEnabled = true
        depthStencilState = device!.newDepthStencilStateWithDescriptor(depthStencilDescriptor)
        commandQueue = device!.newCommandQueue()

    

    func buildPipelineForModel(library: MTLLibrary) -> MTLRenderPipelineDescriptor 
        let pipeLineDesc = MTLRenderPipelineDescriptor()

        let vertexFunctionModel = library.newFunctionWithName("vertex_ply")
        let fragmentFunctionModel = library.newFunctionWithName("fragment_ply")

        let vertexDescriptorModel = MTLVertexDescriptor()
        vertexDescriptorModel.attributes[0].offset = 0
        vertexDescriptorModel.attributes[0].format = .Float4
        vertexDescriptorModel.attributes[0].bufferIndex = 0
        vertexDescriptorModel.layouts[0].stepFunction = .PerVertex
        vertexDescriptorModel.layouts[0].stride = sizeof(Float) * 4

        pipeLineDesc.vertexFunction = vertexFunctionModel
        pipeLineDesc.vertexDescriptor = vertexDescriptorModel
        pipeLineDesc.fragmentFunction = fragmentFunctionModel
        pipeLineDesc.colorAttachments[0].pixelFormat = .BGRA8Unorm

        return pipeLineDesc
    

    func buildPipelinForSky(library: MTLLibrary ) -> MTLRenderPipelineDescriptor
        let pipeLineDesc = MTLRenderPipelineDescriptor()

        let vertexFunctionSky = library.newFunctionWithName("vertex_sky")
        let fragmentFunctionSky = library.newFunctionWithName("fragment_sky")

        let vertexDescriptorSky = MTLVertexDescriptor()
        vertexDescriptorSky.attributes[0].offset = 0
        vertexDescriptorSky.attributes[0].format = .Float4
        vertexDescriptorSky.attributes[0].bufferIndex = 0
        vertexDescriptorSky.attributes[1].offset = sizeof(Float32) * 4
        vertexDescriptorSky.attributes[1].format = .Float4
        vertexDescriptorSky.attributes[1].bufferIndex = 0
        vertexDescriptorSky.attributes[2].offset = sizeof(Float32) * 8
        vertexDescriptorSky.attributes[2].format = .Float2
        vertexDescriptorSky.attributes[2].bufferIndex = 0
        vertexDescriptorSky.layouts[0].stepFunction = .PerVertex
        vertexDescriptorSky.layouts[0].stride = sizeof(Vertex)

        pipeLineDesc.vertexFunction = vertexFunctionSky
        pipeLineDesc.vertexDescriptor = vertexDescriptorSky
        pipeLineDesc.fragmentFunction = fragmentFunctionSky
        pipeLineDesc.colorAttachments[0].pixelFormat = .BGRA8Unorm
        pipeLineDesc.depthAttachmentPixelFormat = .Depth32Float

        let samplerDescriptorSky = MTLSamplerDescriptor()
        samplerDescriptorSky.minFilter = .Nearest
        samplerDescriptorSky.magFilter = .Linear
        samplerStateSky = device!.newSamplerStateWithDescriptor(samplerDescriptorSky)

        return pipeLineDesc

    

    override func buildResources() 
        //Model
        (vertexBufferModel,normalBufferModel,colorBufferModel) = PointCloud.model(device!)
        uniformBufferModel = device!.newBufferWithLength(sizeof(M4f) * 2, options: .OptionCPUCacheModeDefault)
        //Sky
        vertexBufferSky = SkySphere.sphere(device!)
        uniformBufferSky = device!.newBufferWithLength(sizeof(M4f) * 2, options: .OptionCPUCacheModeDefault)
        diffuseTextureSky = self.textureForImage(UIImage(named: "bluemarble")!, device: device!)


    

    override func resize() 
        //Model
        super.resize()
        //Sky
        let layerSizeSky = metalLayer.drawableSize
        let depthTextureDescriptorSky = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.Depth32Float,
                                                                                                width: Int(layerSizeSky.width),
                                                                                                height: Int(layerSizeSky.height),
                                                                                                mipmapped: false)
        depthTextureSky = device!.newTextureWithDescriptor(depthTextureDescriptorSky)
    

    override func draw() 
        dispatch_semaphore_wait(inflightSemaphore, DISPATCH_TIME_FOREVER)

        if let drawable = metalLayer.nextDrawable()
        
            var modelMatrixTransSky = M4f()
            var modelMatrixRotSky = M4f()
            var modelMatrixScaleSky = M4f()

            modelMatrixTransSky = translate(0, y: 0, z: 0)
            modelMatrixRotSky = rotate(90, r: V3f(1,0,0)) * modelMatrixRotSky
            modelMatrixScaleSky = scaling(10, y: 10, z: 10)

            let modelMatrixSky = modelMatrixTransSky * modelMatrixRotSky * modelMatrixScaleSky
            var viewMatrixSky = M4f()
            viewMatrixSky = myCamera.setLookAt(viewMatrixSky)

            let modelViewMatrixSky = viewMatrixSky * modelMatrixSky

            let aspect = Float32(metalLayer.drawableSize.width) / Float32(metalLayer.drawableSize.height)
            let kFOVY:Float = 85.0
            let projectionMatrix = perspective_fov(kFOVY, aspect: aspect, near: 0.1, far: 180.0)

            let matricesSky = [projectionMatrix, modelViewMatrixSky]
            memcpy(uniformBufferSky.contents(), matricesSky, Int(sizeof(M4f) * 2))

            //Model
            var modelMatrixTransModel = M4f()
            var modelMatrixRotModel = M4f()
            var modelMatrixScaleModel = M4f()

            modelMatrixTransModel = translate(0, y: 0, z: 0)
            modelMatrixRotModel = rotate(0, r: V3f(1,0,0))
            modelMatrixScaleModel = scaling(10, y: 10, z: 10)

            let modelMatrixModel = modelMatrixTransModel * modelMatrixRotModel * modelMatrixScaleModel
            var viewMatrixModel = M4f()
            viewMatrixModel = myCamera.setLookAt(viewMatrixModel)

            let modelViewMatrixModel = viewMatrixModel * modelMatrixModel

            let matricesModel = [projectionMatrix, modelViewMatrixModel]
            memcpy(uniformBufferModel.contents(), matricesModel, Int(sizeof(M4f) * 2))

            //command buffer
            let commandBuffer = commandQueue.commandBuffer()
            commandBuffer.addCompletedHandler [weak self] commandBuffer in
                if let strongSelf = self 
                    dispatch_semaphore_signal(strongSelf.inflightSemaphore)
                
                return
            

            //model
        var passDescriptor = MTLRenderPassDescriptor()
        passDescriptor = passDescrForModel(drawable,passDescriptor: passDescriptor)
        var commandEncoder = commandBuffer.renderCommandEncoderWithDescriptor(passDescriptor)
        commandEncoder.pushDebugGroup("model pass")
        commandEncoder.label = "model buffer"
        pointCloudDraw(commandEncoder)
        commandEncoder.endEncoding()
        commandEncoder.popDebugGroup()

        passDescriptor = passDescrForSky(drawable,passDescriptor: passDescriptor)
        commandEncoder = commandBuffer.renderCommandEncoderWithDescriptor(passDescriptor)
        commandEncoder.pushDebugGroup("sky pass")
        commandEncoder.label = "sky buffer"
        skyDraw(commandEncoder)
        commandEncoder.popDebugGroup()
        commandEncoder.endEncoding()

        commandBuffer.presentDrawable(drawable)

        // bufferIndex matches the current semaphore controled frame index to ensure writing occurs at the correct region in the vertex buffer
        bufferIndex = (bufferIndex + 1) % MaxBuffers
        commandBuffer.commit()
      
    

    func passDescrForModel(drawable: CAMetalDrawable, passDescriptor:MTLRenderPassDescriptor) -> MTLRenderPassDescriptor
        passDescriptor.colorAttachments[0].texture = drawable.texture
//        passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.5, 0.5, 0.5, 1)
        passDescriptor.colorAttachments[0].loadAction = .Clear
        passDescriptor.colorAttachments[0].storeAction = .Store
        return passDescriptor
    

    func passDescrForSky(drawable: CAMetalDrawable, passDescriptor:MTLRenderPassDescriptor) -> MTLRenderPassDescriptor
        passDescriptor.colorAttachments[0].texture = drawable.texture
//        passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.5, 0.5, 0.5, 1)
        passDescriptor.colorAttachments[0].loadAction = .Clear
        passDescriptor.colorAttachments[0].storeAction = .Store

        passDescriptor.depthAttachment.texture = depthTextureSky
        passDescriptor.depthAttachment.clearDepth = 1
        passDescriptor.depthAttachment.loadAction = .Clear
        passDescriptor.depthAttachment.storeAction = .DontCare

        return passDescriptor

    

    func pointCloudDraw(commandencodeModel: MTLRenderCommandEncoder)
        commandencodeModel.setRenderPipelineState(pipelineModel)
        commandencodeModel.setDepthStencilState(depthStencilState)
        commandencodeModel.setFrontFacingWinding(.CounterClockwise)
        commandencodeModel.setCullMode(.Back)
        commandencodeModel.setVertexBuffer(vertexBufferModel, offset:0, atIndex:0)
        commandencodeModel.setVertexBuffer(normalBufferModel, offset:0, atIndex:1)
        commandencodeModel.setVertexBuffer(colorBufferModel, offset:0, atIndex:2)
        commandencodeModel.setVertexBuffer(uniformBufferModel, offset:0, atIndex:3)
        commandencodeModel.setFragmentBuffer(uniformBufferModel, offset: 0, atIndex: 0)
        commandencodeModel.drawPrimitives(.Point, vertexStart: 0, vertexCount: vertextCountModel)

    

    func skyDraw(commandencodeSky: MTLRenderCommandEncoder) 
        commandencodeSky.setRenderPipelineState(pipelineSky)
        commandencodeSky.setDepthStencilState(depthStencilState)
        commandencodeSky.setFrontFacingWinding(.CounterClockwise)
        commandencodeSky.setCullMode(.Back)
        commandencodeSky.setVertexBuffer(vertexBufferSky, offset:0, atIndex:0)
        commandencodeSky.setVertexBuffer(uniformBufferSky, offset:0, atIndex:1)
        commandencodeSky.setFragmentTexture(diffuseTextureSky, atIndex: 0)
        commandencodeSky.setFragmentSamplerState(samplerStateSky, atIndex: 0)
        commandencodeSky.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCountSky)

    
    

【问题讨论】:

【参考方案1】:

更改 passDescrForSky 函数passDescriptor.colorAttachments[0].loadAction = .Load 然后2个物体都显示出来了...位置出了点问题...第一个需要调整...

【讨论】:

以上是关于使用 2 个管道进行金属渲染,第二个对象与第一个对象重叠的主要内容,如果未能解决你的问题,请参考以下文章

Flask_socketIO 不与第二个客户端通信

需要将AoH中的一个值与第二个AoH中的另一个值进行比较

如何将第二个表格视图的值与第一个表格视图的单击行的关系分开?

通过将第一个列表中的第一行项与第二个列表中的项进行比较来创建新列表

使用与第一个下拉列表相同的值填充第二个下拉列表

在 C# 中使用管道在进程之间进行通信