Pull to refresh

Четырехмерный рендеринг: особенности, проблемы, варианты решения

Reading time 4 min
Views 5.3K


В комментариях к статье «Рейтрейсер на JavaScript» ее автор ankh1989 рассказал о планах написать рейтрейсер для четырехмерного пространства. Кое-какие свои мысли на эту тему я попробую изложить здесь.



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

Как можно поступить? Варианты могут быть такими:

1) строим трехмерное сечение сцены. Рассматриваем его как обычную 3D сцену, и выполняем рендеринг по законам трехмерного пространства.

2) Проецируем 4D на 3D (например, параллельной проекцией). Считаем, что видимые точки проекции наследуют свойства своих оригиналов, и, опять же, выполняем 3D рендеринг.

3) Выполняем центральную проекцию 4D на 3D, используя алгоритм четырехмерного рейтрейсинга. Получаем трехмерный массив пикселей. Теперь каким-то образом проецируем его на 2D. Есть такие варианты:

3a) выбираем любое направление, и на каждой линии, идущей в этом направлении, находим первый заполненный пиксель (параллельная ортогональная проекция). Цвет этого пикселя и даст цвет точки итоговой картинки.

3b) то же самое, но используем центральную проекцию.

3c,d) берем проекцию из (3a,b), но вместо того, чтобы взять цвет первого пикселя линии, усредняем все цвета, попавшие на линию.

Первые два подхода отбрасываем, как неинтересные (хотя в некоторых случаях они могут оказаться полезными). И рассмотрим, например, вариант 3b.



Итак, у нас есть камера, находящаяся в начале координат, и направленная в сторону Ow=(0,0,0,1). Точку с координатами (x,y,z,w) она проектирует в (p,q,r) = (x/w,y/w,z/w). Видны только точки, у которых w>0.

Вторая камера находится в трехмерном пространстве где-то на оси Or (точка (0,0,-a)) и проектирует точку (p,q,r) на двумерный экран, в точку (u,v)=(p/(a+r),q/(a+r)). Подставив значения p,q,r из первой формулы, получаем, что (u,v)=(x/(z+a*w),y/(z+a*w)). Это значит, что вместо двух центральных проекций нам достаточно обойтись одной — нужно только повернуть камеру. Вторая проекция будет ортогональной — вдоль оси, перпендикулярной как экрану, так и оси камеры.Таким образом, варианты (3a) и (3b) эквивалентны.

Теперь посмотрим внимательнее, что же эти проекции собой представляют. Легко понять, что в каждый пиксель экрана попадает информация о лучах, приходящих из некоторого плоского угла. Таких лучей одномерное множество, и либо мы берем их все (и, например, усредняем — это будут варианты (3c,d), либо выбираем один из лучей, пришедших не из пустоты, например, самый левый — это будут варианты (3a,b).



Вариант «самой левой точки» мне не понравился: линия OL касается объекта, и то, что мы увидим, четырехмерный зритель назвал бы силуэтом сцены. Поэтому я решил попробовать менее обычный вариант — рассмотреть точки сцены, попавшие в плоский угол, и взять цвет ближайшей к камере точки. Такую ближайшую точку (когда границы угла вычислены) можно быстро найти для любого базового объекта, после чего трассировку можно выполнять только для нее — получается одна трассировка на пиксель, что довольно быстро.

Что же получилось?

Сначала я разместил все объекты сцены (включая камеру) в одной плоскости w=0. Естественно, результат рендеринга не отличается от трехмерного (только качество похуже, я не очень старался):



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



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

Кроме того, изменилась форма подставки. Теперь видно, что она не плоская, а трехмерная, на самом деле она состоит из 5*5*3=75 3D-кубиков.



После следущего поворота картина изменилась еще сильнее: два шарика утонули в подставке, остался только один — и тот наполовину погрузился.



И, наконец, поворот на 90 градусов от исходной позиции: теперь мы смотрим с направления w. И снова видим одну сторону подставки, размером 3*5.

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



После поворота отражения исчезли совсем:



Для следующей сцены я использовал новый объект — «трубки со сферическим сечением». Если положить 4 таких трубки в разных ориентациях на плоскость, получится вот что:



Что за странный объект находится на переднем плане, я не понял. По-моему, это дырка. Или ошибка в программе.

После первого поворота исчезли отражения:



А после второго трубки утонули, зато отражения вернулись!



Четвертая сцена — реберная модель тессеракта, составленная из шариков и сферических трубок. На первом кадре шариков только 8: мы смотрим с такой стороны, что они закрывают друг друга:



Обратите внимание на отражение в плоскости. Оно состоит из 8 зеленых сфер — это сечения трубок, попавшие на плоскость w=0.

После поворота камеры стали видны все 16 вершин, а отражение в сфере стало непредсказуемым:



После следующего поворота кубик наполовину утонул:



А потом вынырнул с другой стороны, но пересекся с зеркальной сферой:



А это попытка поместить кубик в пространство со сферами и посмотреть на его тень.



По большому счету, смотреть не на что.

Итак, видно, что при выбранной проекции результат малопредсказуем, и мы видим только часть поверхности объектов — и если на ней есть интересные детали, то они от нас скрываются. Вероятно, для более полных картин придется воспользоваться усреднением по многим лучам. Надеюсь, что 100 лучей на угол будет достаточно.
Tags:
Hubs:
+62
Comments 74
Comments Comments 74

Articles