[SceneKit] [Metal]是否能够基于深度缓冲区渲染透明节点,而不是渲染顺序

时间:2017-08-23 15:25:10

标签: rendering transparency scenekit

我在场景中有很多透明节点。 如果场景在某些方向上旋转,则整个对象会闪烁并且不会渲染

  1. 有人建议调整渲染顺序,但这部分解决问题,最终会出现视觉错误

  2. 可以取消选中"读取深度"但它会引起眨眼,我几乎可以肯定这不是解决方案

  3. 问题:

    是否有一些正确的着色器正在使用正确的深度缓冲区,以便透明节点不会随机隐藏

    还是有另一种正确的方法可以解决这个问题吗?

    PS:使用Metal渲染,所以如果你提到从OpenGL建议一些技术,那就留下吧

    感谢

    以下是截图示例:

    在这个例子中,为了简单地使用3个不透明度为0.5的平面双面平面,透明度也可以用纹理的alpha Chanel设置。在实际项目中,对象可以具有任何形状,可以是透明的,也可以不是,彼此放置在一起或不是

    跨越飞机可见性问题1:

    跨越飞机可见性问题2:

    好的,看起来像#34;订单独立透明度",A缓冲区和更改每个像素的片段数应该解决这个问题 但常见的是,如何实现这一目标?我们可以使用GLSL着色器,直到它与SceneKit和Metal渲染一起使用

    http://www.openglsuperbible.com/2013/08/20/is-order-independent-transparency-really-necessary/

1 个答案:

答案 0 :(得分:0)

对于金属渲染,可以使用一种方法来渲染场景,而我成功了。

我想您已经参考了id <MTLRenderPipelineState>,所以我要做的是创建了另一个并且禁止写入颜色缓冲区(将writeMask的设置添加为空)。

之后,我每一次通过调用渲染器两次渲染模型(第一次使用第二次创建的id <MTLRenderPipelineState>,其中禁止写入颜色缓冲区)。

第一个管道:

MTLRenderPipelineDescriptor *volumetricPipelineDescriptor = [MTLRenderPipelineDescriptor new];
volumetricPipelineDescriptor.vertexFunction = vertexFunction;
volumetricPipelineDescriptor.fragmentFunction = fragmentFunction;
volumetricPipelineDescriptor.vertexDescriptor = vertexDescriptor;

volumetricPipelineDescriptor.colorAttachments[0].blendingEnabled             = YES;
volumetricPipelineDescriptor.colorAttachments[0].rgbBlendOperation           = MTLBlendOperationAdd;
volumetricPipelineDescriptor.colorAttachments[0].alphaBlendOperation         = MTLBlendOperationAdd;
volumetricPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor        = MTLBlendFactorSourceAlpha;
volumetricPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor      = MTLBlendFactorSourceAlpha;
volumetricPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor   = MTLBlendFactorOneMinusSourceAlpha;
volumetricPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;

volumetricPipelineDescriptor.colorAttachments[0].pixelFormat = _renderDestination.colorPixelFormat;
volumetricPipelineDescriptor.depthAttachmentPixelFormat = _renderDestination.depthStencilPixelFormat;
volumetricPipelineDescriptor.stencilAttachmentPixelFormat = _renderDestination.depthStencilPixelFormat;

error = nil;
_volumetricPipelineState = [_device newRenderPipelineStateWithDescriptor:volumetricPipelineDescriptor
                                                                   error:&error];

if (!_volumetricPipelineState) {
    NSLog(@"Error occurred when creating render pipeline state: %@", error);
}

第二条管道:

MTLRenderPipelineDescriptor *volumetricPipelineDescriptor = [MTLRenderPipelineDescriptor new];
volumetricPipelineDescriptor.vertexFunction = vertexFunction;
volumetricPipelineDescriptor.fragmentFunction = fragmentFunction;
volumetricPipelineDescriptor.vertexDescriptor = vertexDescriptor;
volumetricPipelineDescriptor.colorAttachments[0].writeMask = MTLColorWriteMaskNone;
volumetricPipelineDescriptor.colorAttachments[0].pixelFormat = _renderDestination.colorPixelFormat;
volumetricPipelineDescriptor.depthAttachmentPixelFormat = _renderDestination.depthStencilPixelFormat;
volumetricPipelineDescriptor.stencilAttachmentPixelFormat = _renderDestination.depthStencilPixelFormat;

error = nil;
_volumetricPipelineState2 = [_device newRenderPipelineStateWithDescriptor:volumetricPipelineDescriptor
                                                                   error:&error];

if (!_volumetricPipelineState2) {
    NSLog(@"Error occurred when creating render pipeline state: %@", error);
}

深度状态:

MTLDepthStencilDescriptor *volumetricDepthStateDescriptor = [MTLDepthStencilDescriptor new];
volumetricDepthStateDescriptor.depthCompareFunction = MTLCompareFunctionLessEqual;
volumetricDepthStateDescriptor.depthWriteEnabled = YES;
_volumetricDepthState = [_device newDepthStencilStateWithDescriptor:volumetricDepthStateDescriptor];