Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Igors от Октябрь 09, 2010, 17:04



Название: Wind order (OpenGL)
Отправлено: Igors от Октябрь 09, 2010, 17:04
Добрый день

На приаттаченной картинке некоторые части черные. Причина в том что нормали к полигонам и/или вертексам отвернуты от источника света (incorrect  wind order). Поэтому OpenGL не вычисляет свет для них - вот и темно. Обычно совсем необязательно делать поверхности двусторонними чтобы решить эту проблему: берем нормаль и проверяем ее угол с направлением камера-точка. Если этот угол > 90, инвертируем нормаль, а потом уж смотрим направлена ли она на источник света или от него.

А как сделать это в OpenGL?

Спасибо


Название: Re: Wind order (OpenGL)
Отправлено: xop от Октябрь 09, 2010, 19:20
Вы уверены что там включен односторонний вывод полигонов? Включается glEnable( GL_CULL_FACE ) и glCullFace( GL_BACK ). Ну и можно еще поэкспериментировать - поставить либо glFrontFace( GL_CW ) ли glFrontFace( GL_CCW) - переключает трактовку wind order для поликов. Если вывод односторонний, но наблюдаются такие артефакты, то проблема в модельке - как правило исправляется либо настройками программы экспорта из 3D-пакета, либо правкой самого экспортера.


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 09, 2010, 19:56
Вы уверены что там включен односторонний вывод полигонов? Включается glEnable( GL_CULL_FACE ) и glCullFace( GL_BACK ). Ну и можно еще поэкспериментировать - поставить либо glFrontFace( GL_CW ) ли glFrontFace( GL_CCW) - переключает трактовку wind order для поликов. Если вывод односторонний, но наблюдаются такие артефакты, то проблема в модельке - как правило исправляется либо настройками программы экспорта из 3D-пакета, либо правкой самого экспортера.
Наоборот, я уверен что включен ДВУсторонний вывод  :) Если CULL, то все работает как положено. Есть также возможность для пользователя инвертировать нормали для preview. Но все это не очень удобно. Про экспорт понятно, но тоже - неудобно. Напр эта машинка состоит из 177 моделей, поди разберись кого там инверсить. Сами по себе инверсные нормали не мешают рендеру и вообще не есть ошибка: напр смотрим на дом снаружи - нужны одни нормали, а зашли внутрь - инверсные. Вот как бы OpenGL уговорить?


Название: Re: Wind order (OpenGL)
Отправлено: xop от Октябрь 10, 2010, 01:33
Двусторонний вывод - это на самом деле очень плохая идея. Даже если забыть об удвоении нагрузки на растеризатор, пиксельный шейдер и память - это еще может приводить к артефактам. Простейший пример - есть стена с небольшой толщиной. Если включен двусторонний вывод, то растеризуются обе стороны, и поскольку они находятся на очень небольшом расстоянии, то легко поймать z-fighting. Лучше все-таки делать корректные модели, и кстати вообще непонятно что за проблема с экспортом - можно немного подробнее, откуда экспортится, чем и как? Просто есть подозрение, что либо проблема в экспортере и решается в две строчки, либо тупо моделлеры косячат.

Да, если сроки вообще прижали, и надо "вчера" - если верить спецификации в пиксельном шейдере доступна для чтения переменная gl_FrontFacing типа bool. Название думаю само за себя говорит :) Может поможет, но лучше все-таки пересмотреть подход к самому контенту.


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 10, 2010, 10:38
Ладно, давайте по контенту, т.е. постановке. Пользователь имеет модель, рендерится она без проблем (attachment). Однако в OGL превью половина черная. Это вызывает массу ненужных вопросов. Конечно я могу рассказать - включите cull (прямой или обратный), в конце-концов переключитесь на software preview где этой проблемы нет и.т.п. Я знаю что мне ответят: что cull - дело хорошее, но с ним части модели исчезают, поэтому нужно с cull и без. Что software preview действительно работает хорошо, но OGL (как ни крути) намного быстрее. В общем получаются бесконечные разговоры, и мне приходится "оправдываться" (хотя баги не мои  :)).

Импортер: писал я, исходная модель в текстовом alias .obj файле. Никакой ошибки входных данных не вижу. Говорить о "корректности" направления нормалей можно для "solid" а для "surface" оба направления одинаково корректны. Напр. если планируется сцена внутри автомобиля - то никуда не деться - др. нормали будут отвернуты от света.

Может это решается шейдером? (для превью gourand хватает). Никогда ими не занимался,  но все когда-то случается впервые. Вопрос начинающего: можно ли сделать так чтобы шейдер вызывался только для видимых точек (не перекрытых др. полигонами)?  Спасибо


Название: Re: Wind order (OpenGL)
Отправлено: xop от Октябрь 10, 2010, 16:58
Во-первых, если модель рендерится без проблем софтовым рендером, то это еще не значит, что она корректна для железки :) При НЕ real-time рендере на самом деле можно себе позволить очень много разных проверок, которые по хорошему можно провести на стадии подготовки геометрии. При использовании шейдеров - в принципе можно все эти проверки тоже сделать, просто это будет сильно неэффективно.

Кстати, только что обратил внимание, что вы связываете направление нормали и wind order. Вообще-то для железки - это две никак не связанные вещи. Нормаль - это просто атрибут вершины, и wind order на него никак не влияет, как и на любой другой атрибут. Wind order - порядок в пространстве экрана, в котором указаны вершины для треугольника. По умолчанию насколько я помню если против часовой, то это front face, если по - то back face. На основании этого растеризатор в зависимости от настроек решает обрабатывать ли треугольник.

Дальше, если части модели исчезают при включенном cull, но черных кусков вылазящих посреди освещенных нет - то это почти наверняка неправильный контент. Если есть - то это почти наверняка неправильный экспорт. Во втором случае можно сделать примерно такую обработку при импорте - для каждого треугольника посчитать его нормаль (n=cross(p1-p0,p2-p0), если считать корректным wind order против часовой), и если она смотрит в другую сторону с заданными нормалями для его вершин (dot(n,n0)<0 и dot(n,n1)<0 и dot(n,n2)<0) то поменять местами две рядом стоящие вершины (например 1 и 2) в этом треугольнике. Опять же, еще раз вопрос - в какой конкретно программе готовились модели? И если можно - было бы неплохо посмотреть на сам obj-файл, может что прояснится.

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

Теперь по поводу шейдеров. Главный вопрос - какое целевое железо? Если требуется поддержка встроенных интеловских видеокарт - то возникает проблема. Интел до сих пор не сделали поддержку в драйверах GLSL (высокоуровневый язык шейдеров OpenGL), там только ARB-ассемблер, причем его возможности весьма ограничены. И либо вручную на нем писать, либо использовать Cg, для которого есть компилятор в этот ассемблер. Либо использовать DirectX вместо OpenGL - там таких проблем с интелом нет. Если поддержки интела не надо, то все намного проще, хотя все равно крайне желательно иметь компы с ATI и NV для проверки.

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

UPD. Вот тут довольно внятно и приближенно к реальности :) описываются основные стадии графического конвейера, как с фиксированным функционалом, так и с вершинными и пиксельными шейдерами:
http://gameengines.ru/index.php?name=Pages&op=view&id=40
http://gameengines.ru/index.php?name=Pages&op=view&id=41
http://gameengines.ru/index.php?name=Pages&op=view&id=42

И насчет "можно ли сделать так чтобы шейдер вызывался только для видимых точек" - вот если посмотреть на конвеер, нарисованный в статье, то очевидно нельзя - z-test идет после пиксельного шейдера. В реальной жизни в определенных случаях видеокарта может выполнить z-test до запуска пиксельного шейдера, но только при строго определенных условиях, и опять же - если в был сначала выведен дальний полигон, а потом ближний, то эта оптимизация по понятным причинам все равно не сработает. В общем, ответ на этот вопрос весьма неоднозначный, и лезть в него пока не советую, а то может каша в голове получиться :(


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 10, 2010, 18:19
Добрый день, xop

Спасибо за предложение помощи, я хочу им воспользоваться, но сначала надо разобраться что лечить  :) Я визуализировал нормали для одного из боковых стекол машины (это маленькая отдельная модель). Attachment:

- слева: OGL шейдинг (1 camera light)
- посередине: полигонные нормали
- справа: вертексные нормали

Вопрос: что плохого в таких нормалях и wind order? Почему мы решили что "корректное" направление - то которое понимает OGL?  :) Разумеется пользователь может выбрать все модели  в которых его нормали не устраивают и включить галочку "Reverse Normals" и/или пере-импортить их с этой опцией - но это трудоемко и неудобно. Вот и хочется чтобы OGL рисовал без выкрутасов. Для software это проблема смешная, слабо верится что у акул NVidia этого нет  :)

Есть и более продвинутые варианты - считать на сферических гармониках, использовать разные ambient occlusion, и т.д.
Эти разные моя основная работа, но для целей preview - occlusion никак не подходит, а PRT тем более.

Если нет возражений против вышеизложенного - перейдем к обсуждению шейдера? Спасибо

Edit: пардон, забыл ответить насчет целевого железа: самое простое, ничего пользователь специально докупать не будет.


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 10, 2010, 19:51
Просто "промежуточное итого" - если надо учить шейдеры, ну надо так надо, никуда не деться. Но надо ли? Неужели нет такой "штатной" возможности? Ведь потребность весьма жизненная, а значит - популярная


Название: Re: Wind order (OpenGL)
Отправлено: xop от Октябрь 10, 2010, 20:57
OpenGL понимает любое направление - и по часовой, и против часовой стрелки. И даже может выводить оба одновременно. Проблема не в этом. Самый быстрый треугольник - это треугольник, который не рисуется. Самый простой способ отсечь половину треугольников - это проверить в каком порядке идут их вершины. Что и реализовано в железе, и это является штатным режимом. Поэтому надо просто решить, какой порядок вершин является front-face, и поддерживать его во всех моделях. В realtime-графике это считается нормой.

Вторая проблема - отсечение поверхностей перекрытых другими поверхностями в железе реализовано через z-буфер. Т.е. для каждого пиксела есть его глубина, и если при попытке вывести очередной пиксел оказывается, что его глубина больше, чем уже записана в z-буфер, то он не выводится. А собственно проблема заключается в том, что в подавляющем большинстве случаев этот буфер имеет точность 24-бит fixed point. И в случае копланарных (или близких к этому) полигонов из-за ограничений точности может происходить так называемый z-файтинг. И в случае с двусторонним выводом вы его уже поймали, просто из-за того, что цвет back полигона совпадает с front этого сейчас не видно. Как только в модельке этой машины сделают салон - глюк будет очевиден, и весьма мерзок.  Если интересно, могу специально в своем движке врубить двусторонний режим и кинуть скриншотов, как это выглядит.

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

Если эти аргументы все равно не подействовали, и хочется двустороннего вывода, то пожалуйста, вариант даже без шейдера - делаете в памяти по две копии моделей, у второй копии меняете порядок вершин (просто перестановка двух индексов для каждого треугольника) и направление нормали (домножаете на -1), включаете односторонний режим, и все это скопом выводите. И сразу кстати наблюдаете этот самый z-файтинг, т.к. у back-полигонов из-за противоположного направления нормали цвет как раз перестанет совпадать с цветом front-полигонов. Если делать с использованием шейдера - да, можно не делать две копии, рисовать с двусторонним режимом и "разворачивать" нормаль на камеру, как это было описано в вашем первом посте - тогда проблема з-файтинга отложится до момента, когда в модели машины появится салон :).

Да, когда я спрашивал про целевое железо, то имел в виду - какое конкретно. Я отлично понимаю, что заказчик докупать специально ничего не будет, но понятие "простое" слишком растяжимое. Если например писать с использованием GLSL-шейдеров, то это будет работать на любой видеокарте geforce начиная с 6000 серии, даже на простых 6400, 7400, 8400 (они баксов по 30 стоили в момент выпуска), будет работать на любой ATI HD2xxx и выше, может даже на X300/X1300 и т.п., но гарантированно не будет практически на всех интелах. Не потому что они медленные (хотя да, они медленные:)), а потому что тупо поленились в драйвере сделать поддержку GLSL. Поэтому еще раз - какое конкретно железо у заказчика?

P.S. Когда я говорил про сферические гармоники, то совсем не имел в виду PRT :) И под ambient occlusion подразумевал SSAO, которое работает без всяких предрассчетов в реальном времени.

UPD. С z-файтингом конкретно в вашем случае ошибся - его там быть не должно. Но появится, как только у модельки появится салон.


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 11, 2010, 11:08
Поэтому надо просто решить, какой порядок вершин является front-face, и поддерживать его во всех моделях. В realtime-графике это считается нормой.
Помимо realtime есть другие задачи. Пример: пользователь поставил 2 (или более) камер и постоянно переключается между ними. Одна камера в салоне, другая снаружи. Пользователь желает иметь нормальное OGL preview для обеих. Чем он неправ, что плохого он хочет, и что я могу ему "настоятельно рекомендовать"?  :)

какое конкретно железо у заказчика?
Меньше 6000 - можно не рассматривать

.. вариант даже без шейдера - делаете в памяти по две копии моделей, у второй копии меняете порядок вершин (просто перестановка двух индексов для каждого треугольника) и направление нормали (домножаете на -1), включаете односторонний режим, и все это скопом выводите.
Две копии моделей - накладно. Почему не так: когда отдаем полигон в OGL, проверяем нормаль к полигону (смотрят ли она на камеру) и, если нужно, инвертируем данные. То есть "на лету". Что Вы об этом думаете? Нет ли такой готовой ф-ции в OGL?

По поводу z-fighting я так понимаю (поправьте если надо): если есть double-sided (или близкие к ним полигоны) то да, артефакты я получу, но в данном случае это может и желательно - конкретный рендер также не поддерживает double-sided если cull выключен для объекта


Название: Re: Wind order (OpenGL)
Отправлено: xop от Октябрь 11, 2010, 14:32
Помимо realtime есть другие задачи. Пример: пользователь поставил 2 (или более) камер и постоянно переключается между ними. Одна камера в салоне, другая снаружи. Пользователь желает иметь нормальное OGL preview для обеих. Чем он неправ, что плохого он хочет, и что я могу ему "настоятельно рекомендовать"?
Если пользователь хочет камеру в салоне, то по идее этот салон должен быть промоделен, нет? :) А если он промоделен, то проблема с отсечением задних граней автоматически отпадает.

Меньше 6000 - можно не рассматривать
Хорошо, если видео NV и ATI, и поддержка интела не нужна - можно переходить к GLSL-шейдерам :)

Две копии моделей - накладно. Почему не так: когда отдаем полигон в OGL, проверяем нормаль к полигону (смотрят ли она на камеру) и, если нужно, инвертируем данные. То есть "на лету". Что Вы об этом думаете? Нет ли такой готовой ф-ции в OGL?

Стоп-стоп-стоп. А как вы собственно отдаете данные? Если не через VBO, то очень зря. Насчет накладности двух копий - когда геометрия в видеопамяти это вообще ни разу не накладно - по крайней мере пока поликов меньше 100000. Куда накладнее на лету на CPU обрабатывать каждый полик и потом еще и по шине это гнать каждый кадр.

Если делать "на лету" - то скорее так: ставите двусторонний режим, и вершинный шейдер, в котором делается что-то вроде
normal = mix( vertex_normal, -vertex_normal, dot(camera_pos-vertex_pos,vertex_normal)>0 );

По поводу z-fighting я так понимаю (поправьте если надо): если есть double-sided (или близкие к ним полигоны) то да, артефакты я получу, но в данном случае это может и желательно - конкретный рендер также не поддерживает double-sided если cull выключен для объекта

Проблема такая:
внешняя стенка <-| |-> стенка салона
При одностороннем выводе все замечательно выводится - и снаружи, и изнутри. При двустороннем - выводятся обе стенки с любой стороны, и поскольку они стоят близко, то большая вероятность поймать z-файтинг.


Название: Re: Wind order (OpenGL)
Отправлено: Igors от Октябрь 14, 2010, 17:26
Добрый день

Прошу прощения что "притих" - как часто бывает, откуда ни возьмись появилась куча др. дел  :)
Если пользователь хочет камеру в салоне, то по идее этот салон должен быть промоделен, нет? :) А если он промоделен, то проблема с отсечением задних граней автоматически отпадает.
Салон и промоделен (всего машинка 700К полигонов) но проблема никак не отпадает  :)

Стоп-стоп-стоп. А как вы собственно отдаете данные? Если не через VBO, то очень зря. Насчет накладности двух копий - когда геометрия в видеопамяти это вообще ни разу не накладно - по крайней мере пока поликов меньше 100000. Куда накладнее на лету на CPU обрабатывать каждый полик и потом еще и по шине это гнать каждый кадр.
Да вот все еще разбираюсь как же отдается. Коду больше 10 лет и писан не мной. Один "хороший человек" придумал хранить данные неоднообразно: для небольших данных просто массив, а для др - кусками. Ну и как там только в OpenGL не отдается - и совсем по-простому glNormal и glNormalPointer и еще как-то. Вот и обдумываю как бы мне все это привести в порядок - или может вообще перейти на что-то поновее и оставить старье как есть. Пока почитаю VBO, там видно будет.