【问题标题】:iOS-Metal: How to clear Depth Buffer ? Similar to glClear(GL_DEPTH_BUFFER_BIT) in OpenGLiOS-Metal:如何清除深度缓冲区?类似于 OpenGL 中的 glClear(GL_DEPTH_BUFFER_BIT)
【发布时间】:2015-06-12 06:34:06
【问题描述】:

我需要清除深度缓冲区,为此我在 OpenGL 中使用 glClear(GL_DEPTH_BUFFER_BIT),如何在金属中执行?我已经浏览了苹果的文档,没有任何提示。

【问题讨论】:

    标签: ios objective-c opengl-es depth-buffer metal


    【解决方案1】:

    简短的回答是,要清除深度缓冲区,请在开始渲染通道之前添加以下两行: 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 设置为MTLLoadActionClear 再次开始编码。

    【讨论】:

    • 感谢 muzza 清晰准确的回答。我已经用下面的示例代码进行了解释。
    • 不看代码是无法理解的。
    • 如果你到了这一步,你已经有了一个MTLRenderPassDescriptor、MTLCommandBuffer、renderCommandEncoderWithDescriptor和endEncoding。在现有的描述符上设置四个参数并不是真的“无法理解”
    • 为了回答您之前的评论(现已删除),Apple 并没有这样做是为了让“开发人员的难度增加 1400%”。他们这样做是因为在平铺的 GPU 上,清晰的操作本质上与启动渲染通道相关联。 Metal 就是将代码和硬件捆绑在一起,而不是隐藏幕后发生的事情。
    【解决方案2】:

    用示例代码更清楚地解释解决方案

    开始渲染之前:

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

    【讨论】:

    • 如果要清除颜色附件但保留深度缓冲区怎么办?
    【解决方案3】:

    这是 Swift 5 版本。运行你的第一个渲染通道:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多