LINUX.ORG.RU

[openGL] Быстрый способ вычисления нормалей

 


0

0

Решил я понемногу начать 3D в своей fits-смотрелке реализовывать. Для начала - без выпендрежа, тупыми страшными треугольниками. Посмотрел примеры (terrain, например), крутить 3D получается довольно быстро (60fps для изображения 3000x3000, 1500fps для 500x500), а вот нормали вычисляются медленно (~5с для 3000x3000).

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

/* вычисление нормалей для точки (x,y) изображения
 * сначала заполняются массивы нормалей для правого нижнего и левого верхнего
 * треугольников, с одной из вершин в данной точке,
 * затем для каждой точки вычисляется общая нормаль
 *
 * 				ПРИНЦИП
 *  *---B---*---*		(rd - прав.ниж. треугольник, ul - лев. верхний)
 *  | / | / | / |	Нормаль в точке А при отображении треугольников, как на рис.,
 *  E---A---C---*	складывается из нормалей Aul+Bdr+Cul+Adr+Dul+Edr
 *  | / | / | / | 	Нормали для отдельных треугольников: (X - интенсивность в точке)
 *  *---D---*---*		(нормаль = верт. вектор x гор. вектор)
 * 			не нормализованная	Aul = (E-A, A-B, 1)
 * 								Adr = (A-C, D-A, 1)
 */

Но вот с распараллеливанием (для CUDA'ы) пока не могу придумать, что делать (т.к. на границах областей придется влезать в соседние области => использовать разделяемую память для ускорения вычислений вряд ли получится).

☆☆☆☆☆

Есть ещё вариант вычислять нормали по углам поворота относительно одной соседней. Идти так по длине и для первых элементов по высоте. Но простота такого решения, конечно, от рода поверхности зависит.

unnamed
()

Решил я понемногу начать 3D в своей fits-смотрелке [..]

эм, а Ваша смотрелка имеет какое-нибудь отношение к FITS, или то просто так совпало?

shty ★★★★★
()

по поводу методов и примеров рекомендую посмотреть сорцы CGAL, правда там может быть сложновато

shty ★★★★★
()
Ответ на: комментарий от shty

Ваша смотрелка имеет какое-нибудь отношение к FITS, или то просто так совпало?

Оно и есть :)

Изначально разработку начал, чтобы гартманограммы считать, а потом постепенно решил всякими доп. функциями доработать.

Eddy_Em ☆☆☆☆☆
() автор топика

А можно что-нибудь ещё рассказать про задачу. Мне стало интересно, но меня не покидает чувство, что в суть проблемы я не въехал. :(

А если рассчитать нормаль в точке А, как нормаль к поверхности, образованной отрезками EC,BD? Так не катит?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

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

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

ну не знаю, у нас научные товарищи на неё фапают :)

shty ★★★★★
()
Ответ на: комментарий от Eddy_Em

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

Ну дык, как насчет моей идеи?

pathfinder ★★★★
()
Ответ на: комментарий от shty

может этот материал поможет

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

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

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

эм, а что такое нормали к узлам? имхо, это всё равно что искать значение функции в точке разрыва

shty ★★★★★
()
Ответ на: комментарий от shty

эм, а что такое нормали к узлам? имхо, это всё равно что искать значение функции в точке разрыва

Ага, верно. :)

Но если я правильно понял, то нужен некий быстрый алгоритм, который считает «непонятно что», но так, чтобы это «непонятно что» было похоже на нормали к поверхности в узлах к сетки (где первые производные к поверхности имеют разрыв).

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Но если я правильно понял, то нужен некий быстрый алгоритм, который считает «непонятно что», но так, чтобы это «непонятно что» было похоже на нормали к поверхности в узлах к сетки (где первые производные к поверхности имеют разрыв).

мне кажется в таком разе проще ничего не делать - много времени сэкономить можно :)

shty ★★★★★
()
Ответ на: комментарий от shty

мне кажется в таком разе проще ничего не делать

А с освещением что делать? (Хотя я не специалист по 3D, может оно и не надо)

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

[quote]
нужен некий быстрый алгоритм, который считает «непонятно что», но так, чтобы это «непонятно что» было похоже на нормали к поверхности в узлах к сетки
[/quote]
Как раз не «непонятно что», а именно усредненные нормали в каждом узле сетки и надо посчитать. Стандартный алгоритм (как terrain, например) для каждого узла 6-8 (смотря сколько треугольников сходится в узле) вычисляют нормали для соседних треугольников, а затем складывают их и нормируют. Без учета операций индексирования и разыменования указателей сложность этого метода - около 80 операций умножения, 150 суммирования и 9 извлечения корня на каждый узел.

Моя идея - в первый проход вычислить нормали для верхнего левого и правого нижнего треугольников с вершинами в данном узле, во второй проход - на основе нормалей для соседних узлов вычислить нормаль в данном. Здесь требуется выделение доп. памяти (6*sizeof(float)*W*H), но кол-во операций без учета индексирования и разыменования - 30 умножений, 42 суммы и 3 корня на каждый узел. Да и разыменований меньше будет...

А вопрос я задал с тем, что, может быть, существует еще более быстрый и простой способ вычисления нормалей в узлах поверхности?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от pathfinder

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

Eddy_Em ☆☆☆☆☆
() автор топика

Реализовал свой способ. Получилось раза в 2 быстрее, чем в алгоритме terrain, но все-таки, как-то недостаточно быстро. Возможно, когда перенесу на CUDA, будет быстрее, но здесь уже, возможно, получится «затык» в виде переноса больших объемов памяти host->device->host.

Внешне выглядит так. Теперь нужно разобраться с освещением (почему-то подложка не видна совсем), вращением/масштабированием, распараллеливанием алгоритма.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Реализовал свой способ. Получилось раза в 2 быстрее, чем в алгоритме terrain

Ты так и не ответил, чем плохо мое предложение? Там вроде только 9 умножений, 8 сложений/вычитаний и один корень на узел. По идее, быстрее всего.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Какое твое предложение? Считать нормаль только по одному треугольнику? Выглядеть будет жутко...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

С вершиной в данном угле, как ты предлагал здесь

Я не предлагал брать один из треугольников с вершиной в точке A. EC и BD не являются сторонами ни одного из треугольников меша.

pathfinder ★★★★
()
Ответ на: комментарий от vertexua

А оно и так один раз вычисляется, потом создается GL list, а для отрисовки только вызывается список.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от vertexua

А уже сейчас плохо, потому что нет контроля над ресурсами, оно может больше чем надо туда в список напихать и жрать ОЗУ

vertexua ★★★★★
()
Ответ на: комментарий от Eddy_Em

И совершенно не имеют ни какого отношения к реальной нормали в точке A.

Ты всерьез думаешь, что существует какая-то «реальная» нормаль в точке A. Твое «в среднем по соседним плоскостям» я бы то же не назвал «реальной» нормалью.

Хотя, делай что хочешь.

pathfinder ★★★★
()

Вообще я не совсем понимаю суть твоего приложения. Модели известны заранее? Если да, то напиши утилиту, которая прощитает все нормали и бахнет их в бинарном виде в файл. Как вариант это можно проделать при инсталляции или первом запуске. Потом будешь просто одним махом это грузить в Vertex (вот оно как) Buffer Object и байндить к указателю нормалей. В другой буфер грузить вершины тоже одним махом если можно. Потом парочку вызовов - и получишь чрезвычайно оптимальную отрисовку, ребята на Direct3D будут плохо спать

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

У меня с такими подходами ландшафт с елками и тенями гоняет больше 100 FPS. И это на ноуте и это на твоей любимой жабе

vertexua ★★★★★
()
Ответ на: комментарий от pathfinder

Считать из файла. Это не напряжно. А вот с тенями то вообще на порядки быстрее работать со статическим лайтмепом, чем вычислять. Я в своей программе просто написал простой рейтрейсер, который на протяжении 10 минут пускал лучи от солнца в каждую точку ландшафта и считал углы и проходимость. Потом это сохранил в текстурку и естественно эффект был и быстрее и в разы красивее

vertexua ★★★★★
()
Ответ на: комментарий от pathfinder

И да, я забыл сказать, главный фокус в том, что загружая данные из файла процессор отдыхает, он может считать что-то еще

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

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

vertexua

У меня с такими подходами ландшафт с елками и тенями гоняет больше 100 FPS. И это на ноуте и это на твоей любимой жабе

Твой ландшафт вряд ли больше миллиона треугольников использует :)

pathfinder

Интересно, что быстрее? Считать нормали из файла, или вычислить их один раз в памяти?

Почти одинаково: для 9 миллионов треугольников расчет занимает ~1.5с, заполнение списка - ~2с, соответствующий файл с нормалями (32МБ) будет загружаться ~1..1.5с, список будет заполняться так же долго.

vertexua

И да, я забыл сказать, главный фокус в том, что загружая данные из файла процессор отдыхает, он может считать что-то еще

А теперь представь, сколько потребуется дополнительного места и времени, чтобы для, скажем, пары сотен мегабайт (~10 файлов) рассчитать нормали (до того, как эти файлы откроют) и сохранить их в файлы :)

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Почему? VBO такая хитрая штука, что указывая смещения можно создавать в программе вообще один VBO. Откуда 3000?

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Ааа... ты имеешь ввиду что у тебя треугольники полосами. Тут решений кучи.

1) Фиктивный бесконечно тонкий треугольник, который тянется через весь ландшафт и соединяет разные стрипы превращая их в один

2) Фиктивный треугольник, но покороче, так как полоски идут то в одну сторону, то назад.

3) Несколько вызовов функции рисования с разными смещениями.

4) Лучшее решение. Разбить ландшафт на квадраты, каждый заключить в куб, к нему применить ARB_occlusion_query, потом отрисовать каждый такой кластер любым из методов выше. Я делаю так. Ну у меня там не только в геометрии вопрос, а еще и в fillrate bound (основная текстура, detail map, shadow/light map)

vertexua ★★★★★
()
Ответ на: комментарий от Eddy_Em

И еще забыл сказать, VBO подойдет всегда, он так спроектирован, остальное нужно жечь огнеметом

vertexua ★★★★★
()
Ответ на: комментарий от Eddy_Em

Твой ландшафт вряд ли больше миллиона треугольников использует :)

Ты сначала достигни чтобы почти бесконечный ландшафт работал, у меня для этого Occlusion Query. Потому количество треугольников в зависимости от вида бывает очень РАЗНЫМ

vertexua ★★★★★
()
Ответ на: комментарий от Eddy_Em

Ну в ZIP положи. В любом случае это стандартный подход считать такие штуки в разных редакторах, а не в програме. В програме только для динамических поверхностей, иначе стандартный подход - в файл. И вообще можешь открыть для себя NormalMap если на то пошло. Он может быть и в JPEG )

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

И правда. Но что-то грызут меня сомнения по поводу производительности этого VBO: пример из CUDA-SDK работал очень быстро, а какой-то примерчик на SDL с всего лишь 2млн. треугольников тормозил у меня нещадно... Но, конечно, можно попробовать и с VBO.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Не все определяется количеством треугольников, ты туда текстур 5 засунь с CubeMap, или лучше шейдер жирный напиши и посмотри как у тебя 50000 тысяч будут работать

vertexua ★★★★★
()
Ответ на: комментарий от Eddy_Em

Ну а что, больше ты ничего особо не придумаешь, разве что если представить что ландшафт - черно-белая картинка, то уменьшить его размеры на сколько надо и для него посчитать карту нормалей в рантайме. Тогда просто будет менее детализированная карта нормалей, иначе мало что можно придумать. Как оптимизировать геометрию? Тебе сказали - VBO. Как оптимизировать нормали? Никак без уменьшения количества этих нормалей. Разве что перенести на видеокарту. Но вообще если ты сделаешь на OpenCL (ибо CUDA в пролете, не кроссвидеокартно), то прирост скорости будет даже без оптимизации по shared памяти. Тем более если уже припечет, то можно немного схитрить, кластеризовав картинку ландшафта на квадраты и каждый из них засовывать в shared. Ничего что по краям это будет не совсем честный нормаль ) Ну если что можешь засовывать чуть больший кусок в shared, чтобы и края захватить, тогда будет честный.

vertexua ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.