Metal draw 2 different objects, only one is showing

二次信任 提交于 2019-12-10 18:24:34

问题


I want to render 2 different objects with Metal...I have 2 different shaders, different renderpipeline, and command buffers, passDescriptors, they are all different..But there is only one object is drawing on the screen, I don't know where i went wrong.... Here is the draw function:

 dispatch_semaphore_wait(inflightSemaphore, DISPATCH_TIME_FOREVER)

            //Sky
            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))

                let commandBufferSky = commandQueue.commandBuffer()
                commandBufferSky.addCompletedHandler{ [weak self] commandBufferSky in
                    if let strongSelf = self {
                        dispatch_semaphore_signal(strongSelf.inflightSemaphore)
                    }
                    return
                }

                //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))

                let commandBufferModel = commandQueue.commandBuffer()
                commandBufferModel.addCompletedHandler{ [weak self] commandBufferModel in
                    if let strongSelf = self {
                        dispatch_semaphore_signal(strongSelf.inflightSemaphore)
                    }
                    return
                }

                //Sky
                let passDescriptorSky = MTLRenderPassDescriptor()
                passDescriptorSky.colorAttachments[0].texture = drawable.texture
                passDescriptorSky.colorAttachments[0].clearColor = MTLClearColorMake(0.05, 0.05, 0.05, 1)
                passDescriptorSky.colorAttachments[0].loadAction = .Clear
                passDescriptorSky.colorAttachments[0].storeAction = .Store

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


                //Model
                let passDescriptorModel = MTLRenderPassDescriptor()
                passDescriptorModel.colorAttachments[0].texture = drawable.texture
                passDescriptorModel.colorAttachments[0].clearColor = MTLClearColorMake(0.5, 0.5, 0.5, 1)
                passDescriptorModel.colorAttachments[0].loadAction = .Clear
                passDescriptorModel.colorAttachments[0].storeAction = .Store

                //Sky
                let commandEncoderSky = commandBufferSky.renderCommandEncoderWithDescriptor(passDescriptorSky)
                let commandEncoderModel = commandBufferModel.renderCommandEncoderWithDescriptor(passDescriptorModel)

                commandEncoderSky.setRenderPipelineState(pipelineSky)
                commandEncoderSky.setDepthStencilState(depthStencilState)
                commandEncoderSky.setFrontFacingWinding(.CounterClockwise)
                commandEncoderSky.setCullMode(.Back)
                commandEncoderSky.setVertexBuffer(vertexBufferSky, offset:0, atIndex:0)
                commandEncoderSky.setVertexBuffer(uniformBufferSky, offset:0, atIndex:1)
                commandEncoderSky.setFragmentTexture(diffuseTextureSky, atIndex: 0)
                commandEncoderSky.setFragmentSamplerState(samplerStateSky, atIndex: 0)
                commandEncoderSky.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCountSky)
                commandEncoderSky.endEncoding()
                commandBufferSky.presentDrawable(drawable)

                //Model
                commandEncoderModel.setRenderPipelineState(pipelineModel)
                commandEncoderModel.setDepthStencilState(depthStencilState)
                commandEncoderModel.setFrontFacingWinding(.CounterClockwise)
                commandEncoderModel.setCullMode(.Back)
                commandEncoderModel.setVertexBuffer(vertexBufferModel, offset:0, atIndex:0)
                commandEncoderModel.setVertexBuffer(normalBufferModel, offset:0, atIndex:1)
                commandEncoderModel.setVertexBuffer(colorBufferModel, offset:0, atIndex:2)
                commandEncoderModel.setVertexBuffer(uniformBufferModel, offset:0, atIndex:3)
                commandEncoderModel.setFragmentBuffer(uniformBufferModel, offset: 0, atIndex: 0)
                commandEncoderModel.drawPrimitives(.Point, vertexStart: 0, vertexCount: vertextCountModel)
                commandEncoderModel.endEncoding()
                commandBufferModel.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
                commandBufferSky.commit()

                bufferIndex = (bufferIndex + 1) % MaxBuffers
                commandBufferModel.commit()

            }

and here is the function for building the pipeline:

//Model
        let library = device!.newDefaultLibrary()!

        let vertexFunctionModel = library.newFunctionWithName("vertex_ply")
        let fragmentFunctionModel = library.newFunctionWithName("fragment_ply")
        let vertexFunctionSky = library.newFunctionWithName("vertex_sky")
        let fragmentFunctionSky = library.newFunctionWithName("fragment_sky")

        //Model
        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

        //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)

        //Model
        let pipelineDescriptorModel = MTLRenderPipelineDescriptor()
        pipelineDescriptorModel.vertexFunction = vertexFunctionModel
        pipelineDescriptorModel.vertexDescriptor = vertexDescriptorModel
        pipelineDescriptorModel.fragmentFunction = fragmentFunctionModel
        pipelineDescriptorModel.colorAttachments[0].pixelFormat = .BGRA8Unorm

        //Sky
        let pipelineDescriptorSky = MTLRenderPipelineDescriptor()
        pipelineDescriptorSky.vertexFunction = vertexFunctionSky
        pipelineDescriptorSky.vertexDescriptor = vertexDescriptorSky
        pipelineDescriptorSky.fragmentFunction = fragmentFunctionSky
        pipelineDescriptorSky.colorAttachments[0].pixelFormat = .BGRA8Unorm
        pipelineDescriptorSky.depthAttachmentPixelFormat = .Depth32Float

        //Model
        do {
            pipelineModel = try device!.newRenderPipelineStateWithDescriptor(pipelineDescriptorModel)
        } catch {
            print("error with device.newRenderPipelineStateWithDescriptor")
        }

//        //Sky
        do {
            pipelineSky = try device!.newRenderPipelineStateWithDescriptor(pipelineDescriptorSky)
        } catch {
            print("error with device.newRenderPipelineStateWithDescriptor")
        }

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

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

回答1:


Unless you want to do encoding work across threads, you only need to create one command buffer per frame. Also, unless you need to perform rendering in multiple passes (not just multiple draw calls, actually reading image data back from one pass in a subsequent pass), you only need one render command encoder per command buffer.

In pseudocode, here's what one frame looks like:

// semaphore wait
commandBuffer = commandQueue.makeCommandBuffer()!
commandBuffer.addCompletedHandler {
    // semaphore signal
}
commandEncoder = commandBuffer.makeRenderCommandEncoder()!
for obj in objects {
    commandEncoder.setRenderPipelineState(renderPipeline)
    commandEncoder.setVertexBuffer(...)
    // set other per-draw state on the encoder
    commandEncoder.drawPrimitives(...)
}
commandEncoder.endEncoding()
commandBuffer.presentDrawable(currentDrawable)
commandBuffer.commit()


来源:https://stackoverflow.com/questions/37417552/metal-draw-2-different-objects-only-one-is-showing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!