OpenGL выборочный закадровый рендеринг на одну из 2 текстур в одном фрагментном шейдере

Я пишу GLSL шейдер для вращения манипулятора. Я нацеливаюсь на стиль Autodesk Maya, 3 оси для каждого из поворотов x y и z и одна ось над ними для вращения вдоль передней оси камеры равна 4;

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

Чтобы включить выбор объектов, я использую кадровый буфер custrom с 2 прикрепленными текстурами в качестве целей рендеринга — один для цвета, один для идентификаторов выделения.

Проблема заключается в том, что наличие четырех осей, нарисованных в режиме GL_LINES, создает проблему для пользователя. Если линии нарисованы тонкими и красивыми, пользователь должен очень точно щелкнуть по ним, чтобы активировать конкретную ось, потому что он должен точно выбрать пиксель с соответствующим object_id оси.
Я хочу облегчить свою жизнь, создав 2 отдельных рисунка. Тонкие линии для цветного вывода и в 3 раза более широкие линии для объективного вывода текстуры.

Я новичок в openGL. Теперь моя наивная логика передает булеву форму, которая указывает фрагменту шейдера, нужно ли рисовать в цветном или объективном буфере.

Вот команды рисования с переданным селектором render_target

    GLfloat lw;
glGetFloatv(GL_LINE_WIDTH,&lw);
glUniform1ui(7,0);//render to RGB
glDrawArrays(GL_POINTS,0,1);
glUniform1ui(7,1);//render to OBJECTID
glLineWidth(10);
glDrawArrays(GL_POINTS,0,1);
glLineWidth(lw);

А вот фрагмент шейдера:

#version 450
//inputs
layout(location=6) uniform uint manipulator_selected_axis;
layout(location=7) uniform uint render_to_selection_buffer;

//outputs
layout(location=0) out vec4  out_color;
layout(location=1) out float out_objectid;

void main(void)
{
if (render_to_selection_buffer==1)
{
switch (gl_PrimitiveID)
{
case 0: //CAMERA FORWARD
out_objectid=float(253)/256;
break;
case 1: //X
out_objectid=float(250)/256;
break;
case 2: //Y
out_objectid=float(251)/256;
break;
case 3: //Z
out_objectid=float(252)/256;
break;
}
out_color=vec4(0,0,0,0);
}
else
{
vec4 active_axis_color=vec4(1.0,1.0,0.0,1.0);
switch(gl_PrimitiveID)
{
case 0: //CAMERA FORWARD
if(manipulator_selected_axis==0)
out_color=active_axis_color;
else
out_color =vec4(1.0,0.5,1.0,1.0);
break;
case 1: //X
if(manipulator_selected_axis==1)
out_color=active_axis_color;
else
out_color =vec4(1.0,0.0,0.0,1.0);
break;
case 2: //Y
if(manipulator_selected_axis==2)
out_color=active_axis_color;
else
out_color =vec4(0.0,1.0,0.0,1.0);
break;
case 3: //Z
if(manipulator_selected_axis==3)
out_color=active_axis_color;
else
out_color =vec4(0.0,0.0,1.0,1.0);
break;
case 4:
out_color =vec4(0.6,0.6,0.6,1.0);
break;
}
out_objectid=0;

}
}

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

Итак, ВОПРОС 1, каков альтернативный правильный способ написать такой шейдер, который делает то же самое?
ВОПРОС 2 более технический.

введите описание изображения здесь

Здесь я предоставляю скриншот того, что я получаю при вызове 2 glDrawArrays.
Как вы можете видеть, у меня есть черные контуры в моем цветном буфере.
Проблема заключается в том, что когда шейдер framgent выполняет код рендеринга для цели out_objectid, он все равно записывает некоторую грязную случайную информацию в out_color, как показано на рисунке ниже, поэтому мне пришлось перезаписать его с помощью out_color = vec4 (0,0,0,0 ). По крайней мере, это дает чистый черный цвет.

введите описание изображения здесь
Итак, ВОПРОС 2. Где моя ошибка? Как я могу предотвратить блок objectid для записи в out_color?
Спасибо
ОБНОВИТЬ:
После того, что мне предложили, я пришел к такому эффекту. Я не могу описать, что происходит внутри openGL. Похоже, что он все еще пишет в GL_DEPTH_COMPONENT и делает несколько неопределенных тестов глубины, которые приводят к такому результату. Я не хочу никаких записей глубины во время этого вызова отрисовки, потому что манипулятор всегда находится сверху.
Может быть, вы могли бы дать мне дополнительный совет.

введите описание изображения здесь
Чертежный код

glBindBuffer(GL_ARRAY_BUFFER,0);
glUseProgram(program_id_ctl_manip_color);

glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glUniform4f(0,0,0,0,1);
glUniform1f(5,0.67);
glUniform1ui(6,manipulator_axis_highlight);
glUniformMatrix4fv(10,1,GL_TRUE,cam.matrix_view.m);
glUniformMatrix4fv(14,1,GL_TRUE,cam.matrix_projection_ortho.m);
glUniformMatrix4fv(18,1,GL_TRUE,cam.matrix_camera.m);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glDrawArrays(GL_POINTS,0,1);GLfloat lw;
glGetFloatv(GL_LINE_WIDTH,&lw);
glLineWidth(6);
glUseProgram(program_id_ctl_manip_objectid);
glUniform4f(0,0,0,0,1);
glUniform1f(5,0.67);
glUniform1ui(6,manipulator_axis_highlight);
glUniformMatrix4fv(10,1,GL_TRUE,cam.matrix_view.m);
glUniformMatrix4fv(14,1,GL_TRUE,cam.matrix_projection_ortho.m);
glUniformMatrix4fv(18,1,GL_TRUE,cam.matrix_camera.m);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glDrawArrays(GL_POINTS,0,1);
GLenum buffers[2]={GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1};
glDrawBuffers(2,buffers);

glLineWidth(lw);

0

Решение

Давайте сначала перейдем к вопросу 2:

Где моя ошибка? Как предотвратить блокировку объекта для записи в
out_color

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

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

  • включить альфа-смешивание и записать полностью прозрачные пиксели на ваш out_color,
  • просто установите буфер рисования для вашего out_color вывод на GL_NONE

Вероятно, есть много других стратегий, которые могут достичь того же результата, но все они не очень эффективны, что приводит нас к вопросу 1: каков альтернативный правильный способ написать такой шейдер, который делает то же самое?

Каков альтернативный правильный способ написать такой шейдер, который делает
тот же самый?

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

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

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

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

Есть еще одна проблема с вашим кодом: glLineWidth() со значениями помимо 1,0 осуждается. Ваш код не будет работать на современных профилях ядра GL. Если вы хотите широкие линии, вы должны нарисовать примитивы на основе traingle.

2

Другие решения


По вопросам рекламы [email protected]