GLSL: Как получить доступ к цветам близлежащих вершин? (билинейная интерполяция без униформы) - PullRequest
3 голосов
/ 22 марта 2011

Я пытаюсь выполнить билинейную цветовую интерполяцию на четырехугольнике, мне удалось с помощью моего предыдущего вопроса здесь, но у него плохая производительность, потому что он требует, чтобы я повторил glBegin () и glEnd () и 4 раза glUniform() перед glBegin ().

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

glBegin(GL_QUADS);
    glColor4f(...); glVertexAttrib2f(uv, 0, 0); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 1, 0); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 1, 1); glTexCoord2f(...); glVertex3f(...);
    glColor4f(...); glVertexAttrib2f(uv, 0, 1); glTexCoord2f(...); glVertex3f(...);
... // here can be any amount of quads without repeating glBegin()/glEnd()
glEnd();

Чтобы сделать это, я думаю, что я должен как-тополучить доступ к цветам близлежащих вершин, но как?Или есть другие решения для этого?

Мне нужно, чтобы это работало таким образом, чтобы я мог легко переключаться между различными интерполяционными шейдерами.

Любое другое решение, которое работает с одной командой glBegin ()тоже хорошо, но отправка всех угловых цветов для каждой вершины неприемлема, разве это единственное решение здесь?

Редактировать: В примере кода используется непосредственный режим только для ясности.Даже с массивами / буферами вершин проблема будет такой же: мне придется разделить вызовы рендеринга на 4 фрагмента вершин, что приведет к полному падению скорости здесь!

Ответы [ 4 ]

3 голосов
/ 23 марта 2011

Короче говоря: вы не можете сделать это с помощью вершинного шейдера.

Интерполятор (или растеризатор) является одним из компонентов графического конвейера, который не программируется.Учитывая, как работает графический канал, ни вершинному шейдеру, ни фрагментному шейдеру не разрешен доступ ко всему, кроме их вершины (или фрагмента, соответственно), из соображений скорости, простоты и параллелизма.

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

В более новых версиях OpenGL (3.0 и выше, я полагаю?) теперь существует концепция геометрического шейдера.Геометрические шейдеры сложнее реализовать, чем относительно простые вершинные и фрагментные шейдеры, но геометрические шейдеры получают топологическую информацию.То есть они выполняются в примитиве (треугольник, линия, квад и т. Д.), А не в одной точке.С этой информацией они могут создать дополнительную геометрию для разрешения вашего альтернативного метода интерполяции цвета.

Однако это гораздо сложнее, чем необходимо.Я придерживаюсь карты текстур с 4 текселями и реализую вашу логику в поиске фрагментов.

2 голосов
/ 23 марта 2011

Под капотом OpenGL (и все аппаратное обеспечение, на котором он работает) будет делать все как треугольники, поэтому, если вы решите смешивать цвета с помощью вершинной интерполяции, это будет треугольная интерполяция, потому что аппаратное обеспечение не работает по-другому.

Если вы хотите интерполировать "квад", вы должны поместить свои цвета в текстуру, потому что в аппаратном обеспечении текстура всегда имеет форму "квад".

0 голосов
/ 23 марта 2011

Если вы действительно думаете, что именно количество отрисовок приводит к снижению производительности, вы можете попробовать использовать Instancing (используя glDrawArrayInstanced + glVertexAttribDivisor), доступный в ядре GL 3.1.

Альтернативой могут быть точечные спрайты,в зависимости от используемой модели (в основном, от максимального размера четырехугольников и всегда ли они перпендикулярны виду).Это доступно с версии GL 2.0.

0 голосов
/ 23 марта 2011

Линейная интерполяция с цветами, указанными для каждой вершины, может быть эффективно настроена с помощью glColorPointer.Точно так же вы должны использовать glTexCoordPointer / glVertexAttribPointer / glVertexPointer, чтобы заменить все эти отдельные вызовы для каждой вершины одним вызовом, ссылающимся на данные в массиве.Затем выполните рендеринг всех ваших квадов с помощью одного (или не более чем нескольких) вызовов glDrawArrays или glDrawElements.Вы увидите огромное улучшение по сравнению с этим даже без VBO (которые просто меняют место хранения массивов).

Вы упоминаете, что хотите менять шейдеры (между ShaderA и ShaderB, скажем) по принципу «четыре за квадратом».Вы должны либо:

  • Организовать вещи так, чтобы вы могли объединить все четырехугольники ShaderA вместе и все четырехугольники ShaderB вместе и отобразить все вместе с помощью одного вызова.Изменение шейдера, как правило, довольно дорого, поэтому вы хотите минимизировать количество изменений.

или

  • Реализуйте всю необходимую логику шейдера в одном «унифицированном» шейдере, но выбирается другим атрибутом вершины, который выбирает между различными путями кода.То, насколько это эффективно, как подход пакетирования (что является предпочтительным), зависит от того, имеет ли каждая «плитка» шейдеров SIMD тенденцию к запуску смеси путей или только одного.
...