Альфа-смешение с двумя прозрачными текстурами работает неправильно - PullRequest
0 голосов
/ 08 января 2020

У меня есть текстура назначения: enter image description here

Здесь вся текстура будет прозрачной (альфа = 0), за исключением части красного цвета. Красный цвет будет иметь альфа-значение 0,5. Я использовал прямоугольник, чтобы представить эту текстуру.

Тогда у меня есть исходная текстура. Это также прозрачная текстура с черной цветовой частью. Черный цвет будет иметь альфа-значение 0,5. Я использовал другую плоскость прямоугольника, чтобы представить эту текстуру, и я изменил MTLRenderPipelineDescriptor blending на

pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .one
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

Здесь смешивание отлично работает между двумя текстурами.

enter image description here

Затем я пытаюсь объединить эти две текстуры в одну целевую текстуру. используя MTLComputeCommandEncoder. Моя функция ядра:

kernel void compute(
                    texture2d<float, access::read_write> des [[texture(0)]],
                    texture2d<float, access::read> src [[texture(1)]],
                    uint2 gid [[thread_position_in_grid]])
{
    float4 srcColor = src.read(gid);
    float4 desColor = des.read(gid);
    float srcAlpha = srcColor.a;

    float4 outColor = srcColor  + desColor * (1 - srcAlpha);

    des.write(outColor, gid);
}

Но после этого смешанный цвет будет отличаться от предыдущего. Цвет смешивания светлее, чем предыдущий. enter image description here

Как правильно смешать две прозрачные текстуры в функции ядра? Что не так с моим решением?

1 Ответ

2 голосов
/ 08 января 2020

Я думаю, что вы используете предварительно умноженную альфа ...

Попробуйте вместо этого (которая не является предварительно умноженной альфа):

float4 srcColor = src.read(gid);
float4 desColor = des.read(gid);

float4 outColor;
outColor.a = srcColor.a + desColor.a * (1f - srcColor.a);
if (outColor.a == 0f) {
  outColor.r = 0f;
  outColor.g = 0f;
  outColor.b = 0f;
} else {
  outColor.r = (srcColor.r * srcColor.a + desColor.r * desColor.a * (1f - srcColor.a)) / outColor.a;
  outColor.g = (srcColor.g * srcColor.a + desColor.g * desColor.a * (1f - srcColor.a)) / outColor.a;
  outColor.b = (srcColor.b * srcColor.a + desColor.b * desColor.a * (1f - srcColor.a)) / outColor.a;
}
...