#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;