金属画2个不同的对象,仅显示一个 [英] Metal draw 2 different objects, only one is showing
问题描述
我想用Metal渲染2个不同的对象...我有2个不同的着色器,不同的renderpipeline和命令缓冲区,passDescriptors,它们都是不同的.但是在屏幕上只有一个对象正在绘制,我没有不知道我哪里出了错....这是绘制函数:
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()
}
这是构建管道的功能:
//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)
推荐答案
除非您要跨线程进行编码工作,否则只需要为每帧创建一个命令缓冲区.另外,除非您需要进行多次渲染(不仅是多次绘制调用,而且实际上需要在随后的渲染中从一次渲染中读取图像数据),否则每个命令缓冲区仅需要一个渲染命令编码器.
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()
这篇关于金属画2个不同的对象,仅显示一个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!