在金属中如何清除深度缓冲区或模板缓冲区?

洛基

在Metal中,当我已经有了RenderCommandEncoder并且已经对其进行了某些工作时,如何清除深度缓冲区模板缓冲区(但我俩都不需要保留一个)?例如,在OpenGl中,我们有glClearDepthf/GL_DEPTH_BUFFER_BITglClearStencil/,GL_STENCIL_BUFFER_BIT但是我没有找到任何等效的金属。

门罗·威廉姆斯

虽然Metal确实没有提供在渲染过程中间清除深度或模板缓冲区的机制,但可以创建近乎平凡的流水线状态,使您可以根据需要选择性地进行操作。

在将一些OpenGL代码移植到Metal的过程中,我发现自己需要清除深度缓冲区的一部分,该部分与当前设置的视口的边界相对应。这是我的解决方案:

在我的设置代码中,我创建了一个专门的MTLRenderPipelineState和MTLDepthStencilState,它们仅用于清除深度缓冲区,并将它们与其他长期存在的资源一起存储在我的MTKView子类中:

@property (nonatomic, retain) id<MTLRenderPipelineState> pipelineDepthClear;
@property (nonatomic, retain) id<MTLDepthStencilState> depthStencilClear;

[...]

// Special depth stencil state for clearing the depth buffer
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];

// Don't actually perform a depth test, just always write the buffer
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
depthStencilDescriptor.depthWriteEnabled = YES;
depthStencilDescriptor.label = @"depthStencilClear";
depthStencilClear = [self.device newDepthStencilStateWithDescriptor:depthStencilDescriptor];

// Special pipeline state just for clearing the depth buffer.
MTLRenderPipelineDescriptor *renderPipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];

// Omit the color attachment, since we don't want to write the color buffer for this case.

renderPipelineDescriptor.depthAttachmentPixelFormat = self.depthStencilPixelFormat;
renderPipelineDescriptor.rasterSampleCount = self.sampleCount;

renderPipelineDescriptor.vertexFunction = [self.library newFunctionWithName:@"vertex_depth_clear"];
renderPipelineDescriptor.vertexFunction.label = @"vertexDepthClear";

renderPipelineDescriptor.fragmentFunction = [self.library newFunctionWithName:@"fragment_depth_clear"];
renderPipelineDescriptor.fragmentFunction.label = @"fragmentDepthClear";

MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor alloc] init];
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2;
vertexDescriptor.attributes[0].offset = 0;
vertexDescriptor.attributes[0].bufferIndex = 0;
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stride = 8;

renderPipelineDescriptor.vertexDescriptor = vertexDescriptor;

NSError* error = NULL;
renderPipelineDescriptor.label = @"pipelineDepthClear";
self.pipelineDepthClear = [self.device newRenderPipelineStateWithDescriptor:renderPipelineDescriptor error:&error];

并在我的.metal文件中设置匹配的顶点和片段函数:

struct DepthClearVertexIn
{
    float2 position [[ attribute(0) ]];
};

struct DepthClearVertexOut
{
    float4 position [[ position ]];
};

struct DepthClearFragmentOut
{
    float depth [[depth(any)]];
};

vertex DepthClearVertexOut 
vertex_depth_clear(     DepthClearVertexIn in [[ stage_in ]])
{
    DepthClearVertexOut out;
    // Just pass the position through. We're clearing in NDC space.
    out.position = float4(in.position, 0.5, 1.0);
    return out;
}

fragment DepthClearFragmentOut fragment_depth_clear()
{
    DepthClearFragmentOut out;
    out.depth = 1.0;
    return out;
}

最后,我的clearDepthBuffer()方法的主体如下所示:

// Set up the pipeline and depth/stencil state to write a clear value to only the depth buffer.
[view.commandEncoder setDepthStencilState:view.depthStencilClear];
[view.commandEncoder setRenderPipelineState:view.pipelineDepthClear];

// Normalized Device Coordinates of a tristrip we'll draw to clear the buffer
// (the vertex shader set in pipelineDepthClear ignores all transforms and just passes these through)
float clearCoords[8] = {
    -1, -1,
    1, -1,
    -1, 1,
    1, 1
};

[view.commandEncoder setVertexBytes:clearCoords length:sizeof(float) * 8 atIndex:0];
[view.commandEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];

// Be sure to reset the setDepthStencilState and setRenderPipelineState for further drawing

由于顶点着色器根本不转换坐标,因此我在NDC空间中指定了输入几何形状,因此从(-1,-1)到(1,1)的矩形覆盖了整个视口。如果适当设置几何和/或变换,则可以使用相同的技术清除深度缓冲区的任何部分。

类似的技术应该可以清除模板缓冲区,但我将其留给读者练习。;)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

深度+模板帧缓冲区问题

来自分类Dev

在OpenGL中查看深度缓冲区

来自分类Dev

如何清除ReplaySubject上的缓冲区?

来自分类Dev

如何清除Neovim缓冲区

来自分类Dev

Python中的Memset(),清除缓冲区

来自分类Dev

强制在scanf中清除缓冲区

来自分类Dev

Python中的Memset(),清除缓冲区

来自分类Dev

清除键盘缓冲区

来自分类Dev

如何从bash清除konsole中的回滚缓冲区?

来自分类Dev

读取c中的输入后如何清除缓冲区?

来自分类Dev

WebGL中的模板缓冲区

来自分类Dev

深度缓冲区和模板缓冲区问题QML

来自分类Dev

金属着色器在缓冲区中插入值

来自分类Dev

OpenGL:清除模板缓冲区,除了某些位?

来自分类Dev

如何在到达缓冲区而不是缓冲区已满时读取缓冲区中的数据?

来自分类Dev

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

来自分类Dev

OpenGL:glLoadMatrix和深度缓冲区

来自分类Dev

FBO深度缓冲区为红色

来自分类Dev

清除cout缓冲区(C ++)

来自分类Dev

何时清除顶点缓冲区对象

来自分类Dev

清除MIDI输出缓冲区

来自分类Dev

Python:清除标准输入缓冲区

来自分类Dev

何时清除顶点缓冲区对象

来自分类Dev

Tmux,禁用缓冲区清除功能

来自分类Dev

如何获得WGL创建32位深度的缓冲区?

来自分类Dev

LibGDX 如何从 FrameBuffer 获取深度缓冲区?

来自分类Dev

在C ++中实现栅格化和深度缓冲区

来自分类Dev

在C ++中实现栅格化和深度缓冲区

来自分类Dev

如何在 Vulkan 深度缓冲区中存储不受限制的深度范围