Використання LUT для прискорення тригерного важкого шейдера для мобільних пристроїв


10

Я намагаюся змусити цей шейдер запустити справді старий iDevice, а також з часом Андроїди.

Навіть коли я знижую код до 2-х синусових функцій на фрагмент, шейдер працює приблизно в 20 кадрів в секунду.

Я розглядав можливість вивести аркуш із книги старих методів затінення та створити масив, який містить купу заздалегідь заданих значень триггеру і якось використовує їх для наближення шейдера.

У шейдері, який я зв'язав вище, я вже імітую, що шляхом округлення значень, відправлених до функції триггера, далі миша ліворуч (вниз) переходить на меншу якість шейдера. Насправді це дуже круто, бо дійсно близько до лівої сторони це схоже на зовсім інший і досить крутий шейдер.

У всякому разі, у мене є дві дилеми:

  1. Я не знаю, який найефективніший спосіб мати масив приблизно 360 значень у ньому в шейдері GLSL, постійному чи рівномірному?
  2. Я не можу зрозуміти, як поставити число в діапазон, як зазвичай, якби я хотів кут між 0 і 360 (так, я знаю, що графічні процесори використовують радіани), я би зробив це так.

    func range(float angle)
    {
       float temp = angle
       while (temp > 360) {temp -= 360;}
       while (temp < 0)   {temp += 360;}
       return temp;
    }
    

    Однак GLSL не дозволяє виконувати функції циклів або рекурсивних функцій.


Я не знаю, чи було б практично це здійснити, але чи допоможе це попередньо обчислені синусоїдичні значення розташовані нерівномірно, з більш тісними кластеризованими значеннями, де нахил синусоїди є найбільш крутим, а менше значень там, де він вирівнюється і не змінюється так сильно? Чи дозволить це зробити більш високу точність там, де це потрібно, без необхідності зберігати велику кількість значень?
трихоплакс

5
Щодо №2, то вбудована modфункція - це те, що ви хочете. Ви б написали mod(angle, 360.0).
Натан Рід

1
@trichoplax геніальна ідея, але я не знаю, як тоді ви могли б шукати значення на столі. Скажімо, ми помістили їх у масив, де деякі з них сконцентрованіші. Як ми могли знайти правильний індекс?
J.Doe

6
Як щодо введення ваших значень у 3-канальну 1D текстуру? Таким чином, ви можете отримати гріх, cos і загар за ціну єдиного пошуку текстури. Якщо зіставити кут 0 - 2 пікселів на 0 - 1 ультрафіолетового випромінювання та використовувати режим повторної текстури, вам навіть не потрібен дзвінок мода, він автоматично загортається, і ви також можете отримати лінійно-відфільтровані наближення між збереженими значеннями, а не хапаючись до найближчого.
russ

3
Багато часу ви можете усунути функції триггера, використовуючи для геометрії, не використовуючи кут, а починаючи та закінчуючи парою sin / cos, і використовуєте тотожні ідентичності для півкутів тощо.
щурячий вирод

Відповіді:


8

[0,360)[0,2π)

  • [0,360][0,1]
  • Ви отримуєте додаткову вигоду від того, що вам не доведеться проводити регулювання інтервалу, подібного до циклу (хоча, петлі вам так і не знадобляться, і ви можете просто використовувати модульну операцію). Просто використовуйте GL_REPEATяк режим обгортки для текстури, і вона автоматично запускається на початку при доступі з аргументами> 1 (і аналогічно для негативних аргументів).
  • А ви також отримуєте перевагу лінійної інтерполяції між двома значеннями в масиві в основному безкоштовно (або скажімо майже безкоштовно), використовуючи GL_LINEARяк фільтр текстури, таким чином отримуючи значення, які ви навіть не зберігали. Звичайно, лінійна інтерполяція не на 100% точна для тригонометричних функцій, але це, звичайно, краще, ніж ніяка інтерполяція.
  • Ви можете зберігати в текстурі більше одного значення , використовуючи текстуру RGBA (або скільки необхідних компонентів). Таким чином, ви можете отримати, наприклад, greh і cos, використовуючи єдиний пошук текстури.
  • [-1,1][0,1]float sin = 2.0 * (texValue.r + texValue.g / 256.0) - 1.0;(або навіть більше компонентів для більш дрібного зерна). Це дає змогу знову отримати прибуток від багатокомпонентних текстур.

Звичайно, це все ще має бути оцінено, чи це краще рішення, оскільки доступ до текстури не зовсім вільний, а також те, яке найкраще поєднання розміру та формату текстури.

Що стосується заповнення текстури даними та звернення до одного з ваших коментарів, ви повинні врахувати, що фільтрування текстури повертає точне значення в центрі текселя , тобто координату текстури відключає на половину розміру текселя. Отже, так, ви повинні генерувати значення в .5текселі , тобто щось подібне в коді програми:

float texels[256];
for(unsigned int i = 0; i < 256; ++i)
    texels[i] = sin((i + .5f) / 256.f) * TWO_PI);
glTexImage1D(GL_TEXTURE_1D, 0, ..., 256, 0, GL_RED, GL_FLOAT, texels);

uniform float sinTable[361]glUniform1fv[0,360)mod

angle = mod(angle, 360.0);
float value = sinTable[int(((angle < 0.0) ? (angle + 360.0) : angle) + 0.5)];

1
Ось цікаве розширення для зберігання пошукових таблиць у текстурах. Він (ab) використовує N-лінійну інтерполяцію текстури для отримання інтерполяції вищого порядку (він же кращий, ніж лінійний) точок даних, поверхонь, обсягів та гіпероб'ємів. blog.demofox.org/2016/02/22/…
Алан Вулф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.