iOS-Metal:如何清除深度缓冲?类似于 OpenGL 中的 glClear(GL_DEPTH_BUFFER_BIT)
iOS-Metal: How to clear Depth Buffer ? Similar to glClear(GL_DEPTH_BUFFER_BIT) in OpenGL
我需要清除深度缓冲区,为此我在 OpenGL 中使用 glClear(GL_DEPTH_BUFFER_BIT)
,在金属中如何做?我已经浏览了苹果的文档,没有任何提示。
简短的回答是,要清除深度缓冲区,您可以在开始渲染过程之前添加这两行:
mRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
mRenderPassDescriptor.depthAttachment.clearDepth = 1.0f;
而且你不能在不结束并重新启动渲染过程的情况下进行清除。
长答案:
在 Metal 中,您必须定义要在开始渲染到 MTLTexture
时清除颜色和深度缓冲区。没有像OpenGL那样清晰的功能。
为此,在您的 MTLRenderPassDescriptor
中,将 depthAttachment.loadAction
设置为 MTLLoadActionClear
,将 depthAttachment.clearDepth
设置为 1.0f
。
您可能还想将 colorAttachments[0].loadAction
设置为 MTLLoadActionClear
以清除颜色缓冲区。
然后将此渲染过程描述符传递给您对 MTLCommandBuffer::renderCommandEncoderWithDescriptor
的调用。
如果你确实想在渲染中途清除深度或颜色缓冲区,你必须在 MTLRenderCommandEncoder
上调用 endEncoding
,然后将 depthAttachment.loadAction
设置为 [=] 再次开始编码14=].
用示例代码更清楚地解释解决方案
开始渲染之前:
void prepareRendering(){
CMDBuffer = [_commandQueue commandBuffer]; // get command Buffer
drawable = [_metalLayer nextDrawable]; // get drawable from metalLayer
renderingTexture = drawable.texture; // set that as rendering te
setupRenderPassDescriptorForTexture(drawable.texture); // set the depth and colour buffer properties
RenderCMDBuffer = [CMDBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor];
RenderCMDBuffer.label = @"MyRenderEncoder";
setUpDepthState(CompareFunctionLessEqual,true,false); //
[RenderCMDBuffer setDepthStencilState:_depthState];
[RenderCMDBuffer pushDebugGroup:@"DrawCube"];
}
void setupRenderPassDescriptorForTexture(id <MTLTexture> texture)
{
if (_renderPassDescriptor == nil)
_renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
// set color buffer properties
_renderPassDescriptor.colorAttachments[0].texture = texture;
_renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
_renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0f, 1.0f,1.0f, 1.0f);
_renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
// set depth buffer properties
MTLTextureDescriptor* desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatDepth32Float width: texture.width height: texture.height mipmapped: NO];
_depthTex = [device newTextureWithDescriptor: desc];
_depthTex.label = @"Depth";
_renderPassDescriptor.depthAttachment.texture = _depthTex;
_renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
_renderPassDescriptor.depthAttachment.clearDepth = 1.0f;
_renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
}
在此处呈现您的内容
Render();
渲染后
类似于ogles2方法[_context presentRenderbuffer:_colorRenderBuffer];
void endDisplay()
{
[RenderCMDBuffer popDebugGroup];
[RenderCMDBuffer endEncoding];
[CMDBuffer presentDrawable:drawable];
[CMDBuffer commit];
_currentDrawable = nil;
}
上述方法在渲染每一帧后清除深度和颜色缓冲区
中途清除深度缓冲区
void clearDepthBuffer(){
// end encoding the render command buffer
[RenderCMDBuffer popDebugGroup];
[RenderCMDBuffer endEncoding];
// here MTLLoadActionClear will clear your last drawn depth values
_renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear; _renderPassDescriptor.depthAttachment.clearDepth = 1.0f;
_renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
// here MTLLoadActionLoad will reuse your last drawn color buffer
_renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
_renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
RenderCMDBuffer = [CMDBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor];
RenderCMDBuffer.label = @"MyRenderEncoder";
[RenderCMDBuffer pushDebugGroup:@"DrawCube"];
}
这里是 Swift5 版本。 运行 您的第一个渲染通道:
// RENDER PASS 1
renderPassDescriptor = view.currentRenderPassDescriptor
if let renderPassDescriptor = renderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
renderEncoder.label = "First Render Encoder"
renderEncoder.pushDebugGroup("First Render Debug")
// render stuff here...
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
}
然后清除深度缓冲区,但保留颜色缓冲区:
renderPassDescriptor = view.currentRenderPassDescriptor
// Schedule Metal to clear the depth buffer
renderPassDescriptor!.depthAttachment.loadAction = MTLLoadAction.clear
renderPassDescriptor!.depthAttachment.clearDepth = 1.0
renderPassDescriptor!.depthAttachment.storeAction = MTLStoreAction.dontCare
// Schedule Metal to reuse the previous colour buffer
renderPassDescriptor!.colorAttachments[0].loadAction = MTLLoadAction.load
renderPassDescriptor!.colorAttachments[0].storeAction = MTLStoreAction.store
然后 运行 你的第二个渲染:
if let renderPassDescriptor = renderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
renderEncoder.label = "Second Render"
renderEncoder.pushDebugGroup("Second Render Debug")
// render stuff here...
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
}
我需要清除深度缓冲区,为此我在 OpenGL 中使用 glClear(GL_DEPTH_BUFFER_BIT)
,在金属中如何做?我已经浏览了苹果的文档,没有任何提示。
简短的回答是,要清除深度缓冲区,您可以在开始渲染过程之前添加这两行:
mRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
mRenderPassDescriptor.depthAttachment.clearDepth = 1.0f;
而且你不能在不结束并重新启动渲染过程的情况下进行清除。
长答案:
在 Metal 中,您必须定义要在开始渲染到 MTLTexture
时清除颜色和深度缓冲区。没有像OpenGL那样清晰的功能。
为此,在您的 MTLRenderPassDescriptor
中,将 depthAttachment.loadAction
设置为 MTLLoadActionClear
,将 depthAttachment.clearDepth
设置为 1.0f
。
您可能还想将 colorAttachments[0].loadAction
设置为 MTLLoadActionClear
以清除颜色缓冲区。
然后将此渲染过程描述符传递给您对 MTLCommandBuffer::renderCommandEncoderWithDescriptor
的调用。
如果你确实想在渲染中途清除深度或颜色缓冲区,你必须在 MTLRenderCommandEncoder
上调用 endEncoding
,然后将 depthAttachment.loadAction
设置为 [=] 再次开始编码14=].
用示例代码更清楚地解释解决方案
开始渲染之前:
void prepareRendering(){
CMDBuffer = [_commandQueue commandBuffer]; // get command Buffer
drawable = [_metalLayer nextDrawable]; // get drawable from metalLayer
renderingTexture = drawable.texture; // set that as rendering te
setupRenderPassDescriptorForTexture(drawable.texture); // set the depth and colour buffer properties
RenderCMDBuffer = [CMDBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor];
RenderCMDBuffer.label = @"MyRenderEncoder";
setUpDepthState(CompareFunctionLessEqual,true,false); //
[RenderCMDBuffer setDepthStencilState:_depthState];
[RenderCMDBuffer pushDebugGroup:@"DrawCube"];
}
void setupRenderPassDescriptorForTexture(id <MTLTexture> texture)
{
if (_renderPassDescriptor == nil)
_renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
// set color buffer properties
_renderPassDescriptor.colorAttachments[0].texture = texture;
_renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
_renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0f, 1.0f,1.0f, 1.0f);
_renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
// set depth buffer properties
MTLTextureDescriptor* desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatDepth32Float width: texture.width height: texture.height mipmapped: NO];
_depthTex = [device newTextureWithDescriptor: desc];
_depthTex.label = @"Depth";
_renderPassDescriptor.depthAttachment.texture = _depthTex;
_renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
_renderPassDescriptor.depthAttachment.clearDepth = 1.0f;
_renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
}
在此处呈现您的内容
Render();
渲染后
类似于ogles2方法[_context presentRenderbuffer:_colorRenderBuffer];
void endDisplay()
{
[RenderCMDBuffer popDebugGroup];
[RenderCMDBuffer endEncoding];
[CMDBuffer presentDrawable:drawable];
[CMDBuffer commit];
_currentDrawable = nil;
}
上述方法在渲染每一帧后清除深度和颜色缓冲区
中途清除深度缓冲区
void clearDepthBuffer(){
// end encoding the render command buffer
[RenderCMDBuffer popDebugGroup];
[RenderCMDBuffer endEncoding];
// here MTLLoadActionClear will clear your last drawn depth values
_renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear; _renderPassDescriptor.depthAttachment.clearDepth = 1.0f;
_renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
// here MTLLoadActionLoad will reuse your last drawn color buffer
_renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
_renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
RenderCMDBuffer = [CMDBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor];
RenderCMDBuffer.label = @"MyRenderEncoder";
[RenderCMDBuffer pushDebugGroup:@"DrawCube"];
}
这里是 Swift5 版本。 运行 您的第一个渲染通道:
// RENDER PASS 1
renderPassDescriptor = view.currentRenderPassDescriptor
if let renderPassDescriptor = renderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
renderEncoder.label = "First Render Encoder"
renderEncoder.pushDebugGroup("First Render Debug")
// render stuff here...
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
}
然后清除深度缓冲区,但保留颜色缓冲区:
renderPassDescriptor = view.currentRenderPassDescriptor
// Schedule Metal to clear the depth buffer
renderPassDescriptor!.depthAttachment.loadAction = MTLLoadAction.clear
renderPassDescriptor!.depthAttachment.clearDepth = 1.0
renderPassDescriptor!.depthAttachment.storeAction = MTLStoreAction.dontCare
// Schedule Metal to reuse the previous colour buffer
renderPassDescriptor!.colorAttachments[0].loadAction = MTLLoadAction.load
renderPassDescriptor!.colorAttachments[0].storeAction = MTLStoreAction.store
然后 运行 你的第二个渲染:
if let renderPassDescriptor = renderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
renderEncoder.label = "Second Render"
renderEncoder.pushDebugGroup("Second Render Debug")
// render stuff here...
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
}