简体   繁体   中英

iOS-Metal: How to clear Depth Buffer ? Similar to glClear(GL_DEPTH_BUFFER_BIT) in OpenGL

I need to clear the depth buffer, for which i use glClear(GL_DEPTH_BUFFER_BIT) in OpenGL, how to do in metal ? I have gone through apple's documentation, there is no hint about it.

The short answer is that to clear the depth buffer you add these two lines before beginning a render pass: mRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear; mRenderPassDescriptor.depthAttachment.clearDepth = 1.0f; mRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear; mRenderPassDescriptor.depthAttachment.clearDepth = 1.0f; And you cannot do a clear without ending and restarting a render pass.

Long answer:

In Metal, you have to define that you want the colour and depth buffers cleared when you start rendering to a MTLTexture . There is no clear function like in OpenGL.

To do this, in your MTLRenderPassDescriptor , set depthAttachment.loadAction to MTLLoadActionClear and depthAttachment.clearDepth to 1.0f . You may also want to set colorAttachments[0].loadAction to MTLLoadActionClear to clear the colour buffer.

This render pass descriptor is then passed in to your call to MTLCommandBuffer::renderCommandEncoderWithDescriptor .

If you do want to clear a depth or colour buffer midway through rendering you have to call endEncoding on MTLRenderCommandEncoder , and then start encoding again with depthAttachment.loadAction set to MTLLoadActionClear .

To explain the solution more clear with sample codes

Before start rendering:

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 Your contents here

Render();

After rendering

similar to ogles2 method [_context presentRenderbuffer:_colorRenderBuffer];

void endDisplay()
{
    [RenderCMDBuffer popDebugGroup];
    [RenderCMDBuffer endEncoding];
    [CMDBuffer presentDrawable:drawable];
    [CMDBuffer commit];
    _currentDrawable = nil;
}

The above methods clears the depth and colour buffers after rendering each frame

To clear the depth buffer in midway

    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"];
        }

Here is the Swift 5 version. Run your first render pass:

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

Then clear the depth buffer, but keep the colour buffer:

        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

Then run your second render:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM