Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Квадратичное сложение амплитуд свестимости

Квадратичное сложение амплитуд свестимости

Страницы: 1 2 Следующая »
SuslikМодераторwww14 июня 201814:10#0
Уже создавал подобную тему, но старую не нашёл. Тогда к ответу мы так и не пришли, поэтому по новой.

Имеется srgb-текстура, в которой хранится светимость некоторой поверхности. То есть насколько ярко излучает каждая точка этой поверхности. Для простоты можно предположить, что текстура — просто белый круг на чёрном фоне. Есть алгоритм, который что-то там сэмплит из этой текстуры, интегрирует и получает в результате srgb-значение результирующего цвета на экране. При интегрировании испольузется шаг дискретизации и метод вполне нормально сходится к точному решению, если шаг устремить к нулю. Псевдокод алгоритма:

void main()
{
  float sum_weight = 0.0f;
  for(int x = 0; x < steps_count; x++)
  {
    for(int y = 0; y < steps_count; y++)
    {
      float weight = 1.0f / (steps_count * steps_count);
      sum_weight += weight;
      sum_light += textureLod(light_texture, GenerateSample(x, y, steps_count), 0/*нулевой мип*/) * GenerateWeight(x, y, steps_count) / weight;
    }
  }
  gl_FragColor = sum_light / sum_weight;
}

Странность начинается, если для исходной текстуры светимости построить мип-уровни и сэмплить не только из нулевого мипа, а и из более низких. Мип-уровни строятся srgb-корректно, то есть перед усреднением делается srgb-текстурная выборка через гамма-коррекцию, усредняются линейные значения и далее результат записывается в srgb-ренертаргет, следующий уровень. Вот при всей этой операции алгоритм сходится к решению, которое визуально выглядит более тёмным, чем точное решение. То есть если сделать так:

void main()
{
  float sum_weight = 0.0f;
  for(int x = 0; x < steps_count; x++)
  {
    for(int y = 0; y < steps_count; y++)
    {
      float weight = 1.0f / (steps_count * steps_count);
      sum_weight += weight;
      sum_light += textureLod(light_texture, GenerateSample(x, y, steps_count), 5/*ненулевой мип*/) * GenerateWeight(x, y, steps_count) / weight;
    }
  }
  gl_FragColor = sum_light / sum_weight;
}

то результирующее изображение получается темнее. Я уже пытался выдавить из себя минимальный пример, как это воспроизвести, но у меня никак не получается, потому что на простых примерах вроде gaussian blur'а, кажется, проблема не возникает и случается именно в моём алгоритме, где логика зашита в генерирование сэмплов и весов к ним.

Методом научного тыка было обнаружено, что если усреднять пиксели мипов не в линейном пространстве, а по примерно квадратичному закону, то результат выглядит гораздо ближе к истине. Под "примерно квадратичным" я понимаю степень около двойки — это то ли просто квадрат, то ли 2.2 степень гаммы. Короче, вот такое стандартное генерирование мипов(сэмплер srgb) даёт тёмный результат:

  gl_FragColor = (
    texelFetch(src, pos + ivec2(0, 0)) + 
    texelFetch(src, pos + ivec2(1, 0)) + 
    texelFetch(src, pos + ivec2(1, 1)) + 
    texelFetch(src, pos + ivec2(0, 1))) * 0.25;
а если генерить так, то всё ок:
  float gamma = 2.2;
  gl_FragColor = pow((
    pow(texelFetch(src, pos + ivec2(0, 0)), gamma) + 
    pow(texelFetch(src, pos + ivec2(1, 0)), gamma) + 
    pow(texelFetch(src, pos + ivec2(1, 1)), gamma) + 
    pow(texelFetch(src, pos + ivec2(0, 1)), gamma)) * 0.25, 1.0 / gamma);

Проще всего сказать, что я где-то ошибся в коде или мне что-то показалось. Но может ли быть какое-то физическое объяснение, если принять, что мне не показалось? Если гамма на самом деле не 2.2, а 2, то может ли быть такое, что почему-то складываются квадраты интенсивностей?

Правка: 14 июня 2018 14:17

Андрей5000Постоялецwww14 июня 201815:19#1
Suslik
А сами мипы проверял? Они корректно создались?
}:+()___ [Smile]Постоялецwww14 июня 201815:27#2
У тебя в формулах с весами явно творится какой-то бред. Как минимум, на weight ты делишь дважды.
Но, помимо этого, брать другой мип для текстуры без соответствующей коррекции GenerateSample и GenerateWeight математически неправильно.
SuslikМодераторwww14 июня 201815:27#3
Андрей5000
мипы создались корректно. точнее, так как ожидалось — переводятся в линейное пространство, усредняются, записываются, при записи обратно переводятся в srgb. но это даёт визуально неправильный результат. визуально правильный результат получается при фактически возведении исходного значения в 4 степень(2.2 в квадрте), усреднении и потом извлечении корня 4-й степени ещё раз.

}:+()___ [Smile]
> У тебя в формулах с весами явно творится какой-то бред. Как минимум, на weight ты делишь дважды.
это псевдокод. повторюсь — при чтении из нулевого мипа интеграл сходится при уменьшении шага интегрирования. алгоритм image-based lighting'а.

}:+()___ [Smile]
> Но, помимо этого, брать другой мип для текстуры без соответствующей коррекции
> GenerateSample и GenerateWeight математически неправильно.
вот тут подробнее. методы вроде gaussian blur работают, вроде, вполне корректно, если просто читать из более высоких мипов, по крайней мере сходятся к тому же самому.

Правка: 14 июня 2018 15:31

Андрей5000Постоялецwww14 июня 201815:44#4
Suslik
очевидно что то с семплерами и фреймбуферами а не шейдерами. 4 степень это уже перебор
}:+()___ [Smile]Постоялецwww14 июня 201815:57#5
Suslik
> вот тут подробнее. методы вроде gaussian blur работают, вроде, вполне корректно, если просто читать из более высоких мипов, по крайней мере сходятся к тому же самому.
Твои GenerateSample/GenerateWeight косвенно задают эффективный вес пикселей текстуры TextureWeight(i, j).
Когда ты берешь другой мип, то ты фактически размываешь этот TextureWeight (причем достаточно хитрым алгоритмом).
Т. е. если этот эффективный вес достаточно гладкий, то результаты будут похожими, однако в общем случае это не так.
SuslikМодераторwww14 июня 201816:36#6
}:+()___ [Smile]
я, разумеется, согласен, что просто взять мипы и надеяться на правильный результат нельзя. понятно, что результат "размажет". но я ожидаю, что хотя бы средняя интенсивность результата останется той же самой, а она падает. и почему-то если усреднять мипы по квадратичной зависимости, то интенсивность на моих тестах сохраняется даже для очень высоких мипов, на которых размер текселя составляет примерно 1/4 области интегрирования. не исключаю, что я творю какую-то неведомую ерунду, которая на моих тестах по счастливому стечению обстоятельств даёт правдоподобный результат, но проблема ещё и в том, что когда-то давно я приходил к точно такому же выводу, хоть и с другой стороны, и тогда тоже не смог объяснить это явление.

ещё небольшая зацепка, которая может как-то помочь. я тестирую на данных приблизитель дельта-функции. то есть я беру исходную текстуру с очень локализованным очень ярким пятном и прогоняю по ней алгоритм с кучей семплов, использую его как референс. потом размываю мипами, прогоняю тот же самый алгоритм, сравниваю среднюю интенсивность на глазок.

Правка: 14 июня 2018 16:37

}:+()___ [Smile]Постоялецwww14 июня 201817:23#7
Suslik
> но я ожидаю, что хотя бы средняя интенсивность результата останется той же самой, а она падает
Проверь на чисто случайных черно-белых текстурах (0 или 255 с заданной вероятностью) в сравнении с однотонной.
Т. е. среднее по ансамблю черно-белых должно быть равно значению для соответствующей однотонной.
На однотонных то хоть алгоритмы одинаково работают?

Ну и да, раз есть подозрение, что возможны проблемы с sRGB, то проверь линейность.
Т. е. что сумма результатов для двух текстур совпадает с результатом для текстуры суммы.

> я тестирую на данных приблизитель дельта-функции
Доведи до абсурда: тестируй на черных текстурах с одним белым пикселем и сгенерируй TextureWeight(i, j) для обоих случаев.
Дальше можно генерировать случайные текстуры и проверять что алгоритм выдает свертку с найденным TextureWeight.

Правка: 14 июня 2018 17:24

SuslikМодераторwww14 июня 201817:41#8
}:+()___ [Smile]
> На однотонных то хоть алгоритмы одинаково работают?
да, это первым делом проверял

}:+()___ [Smile]
> Доведи до абсурда: тестируй на черных текстурах с одним белым пикселем и
> сгенерируй TextureWeight(i, j) для обоих случаев.
примерно так и есть. просто на совсем одном пикселе результат настолько шумный, что трудно на глаз даже яркость оценить.

завтра буду гонять абсурдные тесты. очень хочется понять, откуда ноги растут у этого эффекта.

DelfigamerПостоялецwww14 июня 201818:01#9
Я в смущении.
Ты скалярно умножаешь текстуру на кернел, и при подстановке разных мипов у тебя получается разная яркость? Или у тебя полноценная свёртка, и ты оцениваешь яркость текстуры-результата?
Можно хотя бы на одномерном аналоге показать, какого вида у тебя кернел?

Правка: 14 июня 2018 18:02

SuslikМодераторwww15 июня 20187:10#10
}:+()___ [Smile]
тестил я, тестил. тестил, тестил, потом ещё потестил немного. пришёл к выводу, что, судя по всему, с мипами я всё равно творю как бы ерунду нефизичную, но вот такое квадратичное усреднение просто неким образом компенсирует визуальные артефакты в наиболее типичных случаях. судя по всему, не всегда, то есть оно на самом деле оно как сходилось не к тому при использовании мипов, так и продолжает сходиться не к тому же, но визуально артефакты меньше. это значит, что физического обоснавания у подхода, скорее всего, нет, просто визуальный эффект, когда при большем показателе гаммы, средняя интенсивность мипмап повышается при усреднении деталей.

Правка: 15 июня 2018 7:11

DelfigamerПостоялецwww15 июня 20188:23#11
Suslik
Я так ничего и не понял. ._.
Но, наверно, где-то не сохраняется энергия.
g-contПостоялецwww15 июня 201810:30#12
Я-то думал у Суслика каждое действие строго математически обосновано. А он оказывается тоже экспериментирует и прикидывает "на глазок".
innuendoПостоялецwww15 июня 201810:37#13
Suslik
> sum_weight;

мне всегда казалось что сумма весов она как бы 1.0

и да, зачем тебе glsl? :)

Правка: 15 июня 2018 10:38

FordPerfectПостоялецwww15 июня 201811:14#14
> просто визуальный эффект, когда при большем показателе гаммы, средняя интенсивность мипмап повышается при усреднении деталей.
Конкретно это вроде следует тупо из неравенства о средних.
Страницы: 1 2 Следующая »

/ Форум / Программирование игр / Графика

2001—2018 © GameDev.ru — Разработка игр