Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Metal draw 2 different objects, only one is showing

Tags:

metal

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)
like image 476
Eleanor Avatar asked Jan 07 '23 00:01

Eleanor


1 Answers

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()
like image 162
warrenm Avatar answered Apr 28 '23 21:04

warrenm