金属片段着色器-颜色值是否已量化为8位?

时间:2018-08-16 21:03:12

标签: fragment-shader metal dithering

我正在尝试在我的Metal片段着色器中实现一些简单的抖动处理,以消除渐变中的条纹。它不起作用,我想知道这是否只是一个错误,或者是否已将传递给着色器的颜色值量化(如果正确的话)为8位。换句话说,片段着色器处理浮点值,但是那些已经处于8位rgb空间所施加的离散级别了吗?

这是我的着色器和用于抖动的矩阵。我基于这两篇文章/帖子:

OpenGL gradient "banding" artifacts

http://www.anisopteragames.com/how-to-fix-color-banding-with-dithering/

var dither_pattern:[UInt8] = 
   [0, 32,  8, 40,  2, 34, 10, 42,   /* 8x8 Bayer ordered dithering  */
    48, 16, 56, 24, 50, 18, 58, 26,  /* pattern.  Each input pixel   */
    12, 44,  4, 36, 14, 46,  6, 38,  /* is scaled to the 0..63 range */
    60, 28, 52, 20, 62, 30, 54, 22,  /* before looking in this table */
    3, 35, 11, 43,  1, 33,  9, 41,   /* to determine the action.     */
    51, 19, 59, 27, 49, 17, 57, 25,
    15, 47,  7, 39, 13, 45,  5, 37,
    63, 31, 55, 23, 61, 29, 53, 21]

// this array is passed to the frag shader via a MTLBuffer

fragment float4 window_gradient_fragment(WindowGradientVertexOut interpolated [[stage_in]],
   const device unsigned char* pattern [[ buffer(0) ]]) {

    int x = (int)interpolated.position.x % 8;
    int y = (int)interpolated.position.y % 8;
    int val = pattern[x+y*8];

    float bayer = 255.0 * (float)val / 64.0;
    const float rgbByteMax = 255.0;
    float4 rgba = rgbByteMax*interpolated.color;
    float4 head = floor(rgba);
    float4 tail = rgba-head;
    float4 color = head+step(bayer,tail);

    return color/255.0;
}

我通过将矩阵更改为一系列交替的0.63对来进行测试,近距离地它确实每隔一个像素就会产生暗淡的垂直条纹。但据我所知,总体范围保持不变。这使我想到,在到达片段着色器时,带已经“内置”了。因此,对其应用抖动将不会有任何帮助,因为损坏已经造成。我希望这不是真的……我天真地假设,因为颜色是浮点的,所以它们将具有完整的浮点精度,并且在碎片着色器之后将转换为8位。

1 个答案:

答案 0 :(得分:1)

您的逻辑似乎不对。 tail在结构中位于[0.0,1.0)中。 bayer在[0.0,255.0)中或多或少。 step()正在比较两者。对于val> = 1的所有值,bayer> = 3.98,因此大于tail。因此,它不是很“ dithery”。只有val为0时,颜色会向下舍入,所有其他值均会舍入。

我认为您只想在计算bayer时不乘以255.0。