Подтвердить что ты не робот

GlLineStipple устарел в OpenGL 3.1

glLineStipple устарел в последних API OpenGL. Что он заменяет? Если не заменить, как я могу получить аналогичный эффект? (Конечно, я не хочу использовать профиль совместимости...)

4b9b3361

Ответ 1

Извините, он ничего не заменил. Первой идеей, которая пришла мне в голову, чтобы подражать ей, был геометрический шейдер. Вы загружаете геометрический шейдер строкой, вычисляете ее длину экрана и основываете на том, что вы генерируете переменное количество подстрок между его начальной и конечной вершинами.


РЕДАКТИРОВАТЬ: Возможно, вы также можете использовать 1D текстуру с альфа (или красным) каналом, кодирующим шаблон как 0.0 (нет строки) или 1.0 (строка), а затем иметь координаты текстуры линий от 0 до 1 и в фрагменте chader вы делаете простой альфа-тест, отбрасывая фрагменты с альфами ниже некоторого порога. Вы можете облегчить создание геометрического шейдера для создания вашей линии texCoords, так как иначе вам нужны разные вершины для каждой строки. Таким образом, вы также можете сделать texCoord зависимым от длины экрана на линии.

Все становится сложнее, если вы рисуете треугольники (используя режим многоугольника GL_LINE). Затем вам нужно преобразовать треугольную линию самостоятельно в геометрический шейдер, вставляя треугольники и проводя строки (это также может послужить поводом для обесценивания режима многоугольника в будущем, если оно еще не было).


РЕДАКТИРОВАТЬ: Хотя я считаю этот вопрос случайным, я сделал простой шейдерный тройной для второго подхода. Это просто минимальное решение, не стесняйтесь добавлять пользовательские функции самостоятельно. Я не тестировал его, потому что мне не хватает необходимого оборудования, но вы должны понять:

uniform mat4 modelViewProj;

layout(location=0) in vec4 vertex;

void main()
{
    gl_Position = modelViewProj * vertex;
}

Вершинный шейдер - это простой проход.

layout(lines) in;
layout(line_strip, max_vertices=2) out;

uniform vec2 screenSize;
uniform float patternSize;

noperspective out float texCoord;

void main()
{
    vec2 winPos0 = screenSize.xy * gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
    vec2 winPos1 = screenSize.xy * gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
    gl_Position = gl_in[0].gl_Position;
    texCoord = 0.0;
    EmitVertex();
    gl_Position = gl_in[1].gl_Position;
    texCoord = 0.5 * length(winPos1-winPos0) / patternSize;
    EmitVertex();
}

В геометрическом шейдере мы берем строку и вычисляем ее длину пространства экрана в пикселях. Затем мы разделим его на размер текстуры шаблона, который был бы factor*16 при эмуляции вызова glLineStipple(factor, pattern). Это воспринимается как 1D-координата текстуры второй конечной точки линии.

Обратите внимание, что эта координата текстуры должна быть интерполирована линейно (noperspective спецификатор интерполяции). Обычная правильная интерполяция может привести к тому, что шаблон шаблона "сжимается" на более отдаленных участках линии, тогда как мы явно работаем со значениями экранного пространства.

uniform sampler1D pattern;
uniform vec4 lineColor;

noperspective in float texCoord;

layout(location=0) out vec4 color;

void main()
{
    if(texture(pattern, texCoord).r < 0.5)
        discard;
    color = lineColor;
}

Теперь шейдер фрагмента просто выполняет простой альфа-тест, используя значение из текстуры шаблона, которое содержит строку 1 для строки и 0 без строки. Таким образом, чтобы эмулировать фиксированную функцию, вы должны иметь 16-пиксельную 1-компонентную 1D текстуру вместо 16-битного шаблона. Не забудьте установить режим обертывания рисунка на GL_REPEAT, о режиме фильтрации я не уверен, но я полагаю, что GL_NEAREST будет хорошей идеей.

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


EDIT: Фактически прямая поддержка OpenGL 3 для целых операций в шейдерах позволяет полностью отказаться от всего этого подхода 1D-текстуры и работать прямо с фактическим битовым шаблоном. Таким образом, геометрический шейдер слегка изменен, чтобы выставить фактическую координату шаблона размера экрана без нормализации:

texCoord = 0.5 * length(winPos1-winPos0);

В шейдере фрагмента мы просто принимаем битовый шаблон как целое без знака (хотя 32-бит в отличие от glLineStipple 16-битного значения) и коэффициент растяжения рисунка и просто берем координату текстуры (ну, нет текстура больше на самом деле, но nevermind) modulo 32, чтобы получить ее позицию по шаблону (те явные uint раздражают, но мой компилятор GLSL говорит, что неявные преобразования между int и uint являются злыми):

uniform uint pattern;
uniform float factor;

...
uint bit = uint(round(linePos/factor)) & 31U;
if((pattern & (1U<<bit)) == 0U)
    discard;