Я пытаюсь реализовать простое дизеринг в моем шейдере металлического фрагмента, чтобы избавиться от полос на градиентах. Это не работает, и мне интересно, это просто ошибка или значения цвета, переданные шейдеру, уже квантованы (если это правильное слово) до 8 бит. Другими словами, фрагментный шейдер имеет дело со значениями с плавающей запятой, но находятся ли они уже на дискретных уровнях, налагаемых 8-битным пространством RGB?
Вот мой шейдер и матрица, которую я использую для дизеринга. Я основал это на этих двух статьях / сообщениях:
Артефакты полос градиента OpenGL
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-битное произойдет после фрагментного шейдера.
color = all(rgba == head) ? float4(1, 0, 0, 1) : float4(0, 1, 0, 1)
или что-то в этом роде, чтобы напрямую определить, квантуется ли цвет до 8 бит. - person Ken Thomases   schedule 17.08.2018==
между двумя векторами дает вектор логических значений, представляющий результаты покомпонентно.all()
затем проверяет, все ли они верны. Итак, он проверяет, равны ли векторы для всех компонентов; то есть фактически равны друг другу. Если у вас есть зеленый цвет, это означает, что, по крайней мере, для некоторых фрагментов, какой-то компонентinterpolated.color
не был квантован до 8 бит. Получение всего зеленого цвета без красного - это немного удивительно. Это говорит о том, что ни один фрагмент не имел цвета, все компоненты которого были целым кратным 1 / 255.0. - person Ken Thomases   schedule 17.08.2018all(tail < 0.002)
. Однако я замечаю, что ваша логика кажется неправильной. Я не знаком с техникой дизеринга, ноtail
находится в [0.0,1.0) по конструкции.step()
сравнивает это сbayer
, которое находится в [0.0,255.0). Еслиval
равно 1,bayer
равно 3,98, что всегда будет большеtail
. Итак, толькоval
из 0 изменяет цвет. Я думаю, вы просто хотите не умножать на 255,0 при вычисленииbayer
. - person Ken Thomases   schedule 17.08.2018