我想用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)
答案 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()