2014-11-23 4 views
0

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

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

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

Проблема в том, что наличие 4 осей, нарисованных режимом 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 более технический.

enter image description here

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

enter image description here ВОПРОС 2. Где моя ошибка? Как заблокировать блок objectid для записи в out_color? Спасибо UPDATE: После того, что я предложил, я пришел к такому эффекту. Я не могу описать, что происходит во внутренности openGL. Похоже, он все еще пишет GL_DEPTH_COMPONENT и делает некоторые неопределенные глубинные тесты, которые приводят к такому результату. Я не хочу, чтобы во время этого вызова рисования была записана глубина, потому что манипулятор всегда на вершине. Возможно, вы могли бы дать мне дополнительные советы.

enter image description here рисования Код

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); 

ответ

2

Давайте перейдем к вопросу 2 первых:

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

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

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

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

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

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

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

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

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

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

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

+0

Большое спасибо. Это было полезно. Я также думал, что glLineWidth может быть устаревшим, но не успел это проверить. Пока я буду использовать его, но скоро перейду к современному. Так как я понял, что минимальный способ изменения вещей в моей ситуации - это отпирать привязанность к out_color и максимальному созданию 2 шейдеров. Я тоже рассматривал это, и у меня возник вопрос в том, что у меня есть 2 флеш-шейдера в одной программе. Возможно ли это, или я должен скомпилировать и связать две отдельные программы? Я не хочу излишней компиляции моей программы компиляции. Хотите, чтобы это было как можно проще. – Antiusninja

+0

Просто создание 2 отдельных шейдеров фрагментов не выполняет эту работу. Как именно я должен отключить свой цветовой буфер? Прямо сейчас у меня есть только один буфер с двумя цветными вложениями? Как правильно отвязать одну из текстур? – Antiusninja

+0

Как я уже сказал, измените буфер рисования. – derhass

 Смежные вопросы

  • Нет связанных вопросов^_^