Russian Qt Forum
Сентябрь 30, 2024, 12:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Wind order (OpenGL)  (Прочитано 6911 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Октябрь 09, 2010, 17:04 »

Добрый день

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

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

Спасибо
Записан
xop
Гость
« Ответ #1 : Октябрь 09, 2010, 19:20 »

Вы уверены что там включен односторонний вывод полигонов? Включается glEnable( GL_CULL_FACE ) и glCullFace( GL_BACK ). Ну и можно еще поэкспериментировать - поставить либо glFrontFace( GL_CW ) ли glFrontFace( GL_CCW) - переключает трактовку wind order для поликов. Если вывод односторонний, но наблюдаются такие артефакты, то проблема в модельке - как правило исправляется либо настройками программы экспорта из 3D-пакета, либо правкой самого экспортера.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Октябрь 09, 2010, 19:56 »

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

Двусторонний вывод - это на самом деле очень плохая идея. Даже если забыть об удвоении нагрузки на растеризатор, пиксельный шейдер и память - это еще может приводить к артефактам. Простейший пример - есть стена с небольшой толщиной. Если включен двусторонний вывод, то растеризуются обе стороны, и поскольку они находятся на очень небольшом расстоянии, то легко поймать z-fighting. Лучше все-таки делать корректные модели, и кстати вообще непонятно что за проблема с экспортом - можно немного подробнее, откуда экспортится, чем и как? Просто есть подозрение, что либо проблема в экспортере и решается в две строчки, либо тупо моделлеры косячат.

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

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Октябрь 10, 2010, 10:38 »

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

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

Может это решается шейдером? (для превью gourand хватает). Никогда ими не занимался,  но все когда-то случается впервые. Вопрос начинающего: можно ли сделать так чтобы шейдер вызывался только для видимых точек (не перекрытых др. полигонами)?  Спасибо
Записан
xop
Гость
« Ответ #5 : Октябрь 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 до запуска пиксельного шейдера, но только при строго определенных условиях, и опять же - если в был сначала выведен дальний полигон, а потом ближний, то эта оптимизация по понятным причинам все равно не сработает. В общем, ответ на этот вопрос весьма неоднозначный, и лезть в него пока не советую, а то может каша в голове получиться Грустный
« Последнее редактирование: Октябрь 10, 2010, 18:13 от xop » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Октябрь 10, 2010, 18:19 »

Добрый день, xop

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

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

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

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

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

Edit: пардон, забыл ответить насчет целевого железа: самое простое, ничего пользователь специально докупать не будет.
« Последнее редактирование: Октябрь 10, 2010, 18:22 от Igors » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Октябрь 10, 2010, 19:51 »

Просто "промежуточное итого" - если надо учить шейдеры, ну надо так надо, никуда не деться. Но надо ли? Неужели нет такой "штатной" возможности? Ведь потребность весьма жизненная, а значит - популярная
Записан
xop
Гость
« Ответ #8 : Октябрь 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-файтингом конкретно в вашем случае ошибся - его там быть не должно. Но появится, как только у модельки появится салон.
« Последнее редактирование: Октябрь 10, 2010, 22:15 от xop » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Октябрь 11, 2010, 11:08 »

Поэтому надо просто решить, какой порядок вершин является front-face, и поддерживать его во всех моделях. В realtime-графике это считается нормой.
Помимо realtime есть другие задачи. Пример: пользователь поставил 2 (или более) камер и постоянно переключается между ними. Одна камера в салоне, другая снаружи. Пользователь желает иметь нормальное OGL preview для обеих. Чем он неправ, что плохого он хочет, и что я могу ему "настоятельно рекомендовать"?  Улыбающийся

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

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

По поводу z-fighting я так понимаю (поправьте если надо): если есть double-sided (или близкие к ним полигоны) то да, артефакты я получу, но в данном случае это может и желательно - конкретный рендер также не поддерживает double-sided если cull выключен для объекта
Записан
xop
Гость
« Ответ #10 : Октябрь 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-файтинг.
« Последнее редактирование: Октябрь 11, 2010, 14:37 от xop » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Октябрь 14, 2010, 17:26 »

Добрый день

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

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


Страница сгенерирована за 0.066 секунд. Запросов: 23.