Альфа-версия для наложения металла ниже 0,5

#graphics #metal

#графика #Металлические

Вопрос:

Когда я пытаюсь смешаться с цветом с альфой 0,5 или ниже, металл, по-видимому, отбрасывает цвет, как будто у него альфа 0. Когда я устанавливаю альфа-значение 0,51, я вижу его нормально. Когда я устанавливаю его на 0,5, он невидим. Вот простая реализация проблемы:

 @implementation Renderer
{
    id <MTLDevice> _device;
    id <MTLCommandQueue> _commandQueue;

    id<MTLLibrary> defaultLibrary;
    id <MTLBuffer> _vertexBuffer;
    id <MTLBuffer> _indexBuffer;
    
    id <MTLRenderPipelineState> _pipelineState;
}

-(nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view;
{
    self = [super init];
    if(self)
    {
        _device = view.device;
        view.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;

        _commandQueue = [_device newCommandQueue];
        [self _createRenderObject];
    }

    return self;
}

-(void)_createRenderObject
{
    Vertex verts[4] = {
        simd_make_float2(-0.5f, -0.5f),
        simd_make_float2(0.5f,-0.5f),
        simd_make_float2(0.5f,0.5f)
    };

    uint16_t indices[3] = {0,1,2};

    _vertexBuffer = [_device newBufferWithBytes:amp;verts length:sizeof(verts) options:MTLResourceStorageModeShared];

    _indexBuffer = [_device newBufferWithBytes:amp;indices length:sizeof(indices) options:MTLResourceStorageModeShared];
    
    // Create Pipeline State
    defaultLibrary = [_device newDefaultLibrary];
    MTLRenderPipelineDescriptor *pd = [[MTLRenderPipelineDescriptor alloc] init];

    pd.vertexFunction = [defaultLibrary newFunctionWithName: @"VertShader"];
    pd.fragmentFunction = [defaultLibrary newFunctionWithName: @"FragShader"];
    pd.alphaToCoverageEnabled = YES;
    
    MTLRenderPipelineColorAttachmentDescriptor *cad = pd.colorAttachments[0];
    cad.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
    cad.blendingEnabled = YES;
    cad.alphaBlendOperation = MTLBlendOperationAdd;
    cad.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
    cad.destinationAlphaBlendFactor = MTLBlendFactorDestinationAlpha;
    cad.rgbBlendOperation = MTLBlendOperationAdd;
    cad.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
    cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;

    NSError *error = NULL;
    _pipelineState = [_device newRenderPipelineStateWithDescriptor:pd error:amp;error];
}

- (void)drawInMTKView:(nonnull MTKView *)view
{
    id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];

    MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor;

    id <MTLRenderCommandEncoder> renderEncoder =
    [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

    [renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];
    [renderEncoder setCullMode:MTLCullModeBack];
    [renderEncoder setRenderPipelineState:_pipelineState];

    [renderEncoder setVertexBuffer:_vertexBuffer offset:0 atIndex:0];

    [renderEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
                                  indexCount:3
                                   indexType:MTLIndexTypeUInt16
                                 indexBuffer:_indexBuffer
                           indexBufferOffset:0];
    

    [renderEncoder endEncoding];

    [commandBuffer presentDrawable:view.currentDrawable];
    
    [commandBuffer commit];
}
@end
 

Шейдер.металл:

 typedef struct {
    float4 position [[position]];
} VertexOut;

vertex VertexOut
VertShader(const uint vertexID [[vertex_id]],
            constant Vertex *vertices [[buffer(0)]])
{
    VertexOut out;
    Vertex v = vertices[vertexID];
    
    out.position = (float4){v.position.x,v.position.y,0,1};
    return out;
}

fragment half4
FragShader(VertexOut in [[stage_in]])
{
    return half4(1,1,1,0.50f);
}
 

С помощью этого кода, в частности фрагшейдера, имеющего 0,50f в качестве альфа-значения, я получаю чистый холст:
треугольник не виден

Если я изменю значение альфа на 0,51f:

 fragment half4
FragShader(VertexOut in [[stage_in]])
{
    return half4(1,1,1,0.51f);
}
 

Затем я получаю это:
Виден треугольник

Любая помощь приветствуется!

Комментарии:

1. Мне кажется , что где-то у вас включен «альфа-тест» с порогом альфа-теста, установленным на 0,5, хотя я не использовал металл, я не мог сказать наверняка. Возможно, вы могли бы попробовать спросить на computergraphics.stackexchange.com ?

2. Спасибо @simon-f, ваше предложение привело меня к ответу.

Ответ №1:

Решаемая. Проблема заключалась в том, что для alphaToCoverageEnabled было установлено значение true, в то время как целевой тип текстуры для рендеринга НЕ был MTLTextureType2DMultisample . Похоже, что они работают в тандеме, но я не понимаю, как это сделать.

Если не используется множественная выборка, установите для alphaToCoverageEnabled значение false.

В противном случае убедитесь, что цель рендеринга имеет тип MTLTextureType2DMultisample .

При использовании MTKView задайте тип целевой текстуры для рендеринга, установив значение sampleCount для объекта MTKView:

     _view = (MTKView *)self.view;
    _view.sampleCount = 2;
 

и дескриптор конвейера визуализации состояния конвейера:

     MTLRenderPipelineDescriptor *pd = [[MTLRenderPipelineDescriptor alloc] init];
    pd.sampleCount = 2;