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