金属绘制2个不同的对象,只显示一个

时间:2016-05-24 15:12:36

标签: metal

我想用Metal渲染2个不同的对象...我有2个不同的着色器,不同的renderpipeline和命令缓冲区,passDescriptors,它们都是不同的。但是屏幕上只有一个对象正在绘制,我不知道我不知道我哪里出错了......这是绘图功能:

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

            }

以下是构建管道的功能:

//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 个答案:

答案 0 :(得分:4)

除非您想跨线程进行编码工作,否则您只需要为每个帧创建一个命令缓冲区。此外,除非您需要在多个传递中执行渲染(不仅仅是多个绘制调用,实际上在后续传递中从一个传递中读取图像数据),每个命令缓冲区只需要一个渲染命令编码器。

在伪代码中,这是一帧的样子:

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