简体   繁体   English

iOS-Metal:如何清除深度缓冲区? 类似于 OpenGL 中的 glClear(GL_DEPTH_BUFFER_BIT)

[英]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 ?我需要清除深度缓冲区,为此我在 OpenGL 中使用glClear(GL_DEPTH_BUFFER_BIT) ,如何在金属中做? 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; 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 .在 Metal 中,您必须定义在开始渲染到MTLTexture时要清除颜色和深度缓冲区。 There is no clear function like in OpenGL.没有像 OpenGL 那样清晰的函数。

To do this, in your MTLRenderPassDescriptor , set depthAttachment.loadAction to MTLLoadActionClear and depthAttachment.clearDepth to 1.0f .为此,在您的MTLRenderPassDescriptor ,将depthAttachment.loadAction设置为MTLLoadActionClear并将depthAttachment.clearDepth1.0f You may also want to set colorAttachments[0].loadAction to MTLLoadActionClear to clear the colour buffer.您可能还想将colorAttachments[0].loadActionMTLLoadActionClear以清除颜色缓冲区。

This render pass descriptor is then passed in to your call to MTLCommandBuffer::renderCommandEncoderWithDescriptor .然后将此渲染过程描述符传递给您对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 .如果您确实想在渲染过程中清除深度或颜色缓冲区,您必须在endEncoding上调用MTLRenderCommandEncoder ,然后再次开始编码,将depthAttachment.loadAction设置为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];类似于ogles2方法[_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.这是 Swift 5 版本。 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()
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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