Еще одна проблема состоит в том, что язык шейдеров OpenGL хотя и поддерживает циклы, даже вложенные, но не поддерживает двухмерные массивы. В принципе можно «раскрутить» ядро свёртки и хранить его в одномерном массиве, в каждой ячейке которого будут храниться х- и г/-координаты (сдвиг) от центра ядра и значение в этой точке. Во фрагментном шейдере можно обработать весь массив в одном цикле, прибавляя указанный сдвиг к текущим текстурным координатам, обращаясь к основному изображению и умножая полученное значение пиксела на значение из ядра. Если ядро свёртки будет храниться в таком виде, значения можно записывать в массив как угодно: по строкам, по столбцам, в обратном порядке или вообще в произвольном порядке. В массив даже не нужно включать нулевые значения ядра, так как они никак не влияют на результат.

Вершинный шейдер здесь должен выполнять тождественное отображение входных геометрических фигур (а именно прямоугольника, размер которого по горизонтали соответствует размеру основного изображения) и передавать текстурные координаты. Текстурная координата (0, 0) должна ассоциироваться с нижним левым углом прямоугольника, а текстурная координата (1, 1) - с верхним правым углом прямоугольника.

В случае если ядро свёртки выходит за край основного изображения, требуется особое решение. Можно использовать один из побочных эффектов текстурных операций OpenGL: если приложение хочет нарисовать край так, чтобы получился результат в режиме GL_CONSTANT_BORDER, текстура с основным изображением должна содержать в GL_TEXTURE_WRAP_S и GL_TEXTURE_WRAP_T параметр GL_CLAMP_TO_BORDER. Если же нужен край вида GL_REPLICATE_BORDER (при выходе ядра за край берется крайний пиксел изображения), то параметры текстуры GL_TEXTURE_WRAP_S и GL_TEXTURE_WRAP_T должны быть установлены в GL_CLAMP_TO_EDGE. А если нужен режим GL REDUCE, приложение должно рисовать прямоугольник, немного меньший свертываемого изображения. Для размера ядра 3x3 прямоугольник должен быть меньше на 2 пиксела в ширину и на 2 пиксела в высоту. В этом случае текстурная координата нижнего левого угла будет (1/width, 1/height), а текстурная координата верхнего правого угла - (1 - 1/width, 1 - 1/height). Режим текстуры нужно установить в GL_NEAREST, чтобы избежать ненужной интерполяции.

Сложность заключается также в том, что OpenGL требует, чтобы текстуры имели размеры, кратные степени двойки и по ширине, и по высоте (такие изображения в наше время - редкость). Чтобы обойти это ограничение, можно увеличить изображение до следующей ближайшей степени двойки, а затем соответственно сдвинуть текстурные координаты на прямоугольнике. Это может привести (а может и не привести) к излишнему расходованию текстурной памяти, что зависит от того, поддерживает ли графический ускоритель виртуальное текстури-рование (загрузка части текстур в графическое оборудование по запросу). Существуют расширения от разных производителей, с помощью которых эту проблему пытаются решить. OpenGL ARB работает над тем, чтобы создать общее решение и включить его в стандарт OpenGL.


⇐ вернуться назад | | далее ⇒