Журнал LinuxFormat - перейти на главную

LXF132:pov-ray

Материал из Linuxformat
Перейти к: навигация, поиск
POV-Ray Создавайте новые миры всего несколькими строчками кода

Содержание

POV-Ray: Строим новый мир

Трехмерное моделирование – это не только Blender. Вячеслав Ястребцев представляет другие рендереры, дающие новые возможности.


Принято считать, что Linux обделён мультимедийными приложениями. До последнего времени это было обоснованным мнением, однако сегодня сообщество активно разрабатывает многочисленные программы для создания и просмотра мультимедиа. Трехмерные приложения – бесспорный лидер этого процесса. Стремительно развивающийся редактор трёхмерных сцен Blender (http://www.blender3d.org), используемый для создания трёхмерной графики и анимации профессионального качества; продвинутый рендерер YafAray (http://www.yafaray.org); наконец, вершина современных технологий визуализации – LuxRender (http://www.luxrender.net), обеспечивающий отрисовку изображений, практически неотличимых от фотографий – все они обещают скорый бум свободного ПО в медиа-индустрии. Но в тени стремительно растущих современных проектов тихо, без громких обещаний, развивается, пожалуй, самая почтенная система 3D-моделирования и визуализации, уходящая своими корнями в далёкие 80‑е, но достойная пристального внимания даже сегодня. Имя этому аксакалу – POV-Ray.

Приготовимся к старту

Как и всякий старец, POV-Ray отличается консерватизмом и непростым характером. Двоичная версия релиза 3.6, доступная на http://www.povray.org, вышла аж в 2004 году, и её нормальная работа в современных дистрибутивах не гарантируется. Лучше сразу скачать исходный код POV-Ray 3.7 Beta и собрать его самостоятельно. Тут нас поджидают дополнительные хлопоты: при запуске конфигурационного скрипта требуется указать своё имя с помощью опции COMPILED_BY=«имя» (подойдёт любая комбинация букв и цифр). Кроме того, бета-версия требует постоянного ввода некого кода. Для его получения необходимо ввести в консоли команду povray --betacode; программа напечатает набор символов, который необходимо присвоить переменной POVRAY_BETA и далее экспортировать, выполнив export POVRAY_BETA=код.

Установив программу, настройте параметры рендеринга. Откройте файл ~/.povray/3.7/povray.ini и добавьте в его конец две строки: Pause_When_Done=On, чтобы окно с готовым изображением не пропадало по завершении отрисовки, и Output_File_Name=«pov_render.png» – она указывает, в какой файл записывать созданное изображение.

Лицензии, лицензии

Неприятный сюрприз: POV-Ray не является свободным ПО. Да, исходные тексты доступны, и вы можете найти программу в репозиториях своего дистрибутива; но в 1986 году, когда была начата работа над проектом, GPL еще не была столь популярна. За прошедшие 24 года над POV-Ray успело потрудиться множество людей, поэтому изменить лицензию на более приемлемую в современном Linux-мире, увы, не представляется возможным. (Примечание: однако, по состоянию на 2017 год, версии POV-Ray с 3.7 и выше - имеют свободную лицензию GNU Affero General Public License; для устаревших версий программы действуют отдельные лицензии).

Азбука SDL

Итак, всё готово для знакомства. POV-Ray не имеет встроенных средств интерактивного моделирования: есть множество программ, экспортирующих в его формат (в том числе альфа-версия Blender 2.5). Однако всю мощь POV-Ray можно раскрыть, только описывая сцену на SDL (Scene Description Language) – интерпретируемом языке программирования с С-подобным синтаксисом.

Сцены POV-Ray состоят из объектов, описываемых единым образом. Сам объект задаётся конструкцией вида:

тип_объекта {параметры}

Параметры бывают двух видов: обязательные и дополнительные. Обязательные необходимо указывать при создании объекта, сразу после открывающей фигурной скобки. Если забыть это сделать, POV-Ray сообщит об ошибке и аварийно завершит работу. Обязательные параметры могут быть числами или векторами, имеют фиксированный порядок и разделяются запятыми. Дополнительные параметры, напротив, требуют указания имени параметра, за которым следует его значение (число, вектор или объект). Разделять дополнительные параметры запятой не нужно.

Вектора в нотации POV-Ray записываются так:

<несколько чисел через запятую>

Примером вектора может служить <1, 3, -2> или <0.2, 0.4, 0.9, 0.1>. Вектора используются для обозначения координат и цветов.

Для ускорения работы POV-Ray позволяет использовать ряд сокращений: x, y, z – единичные вектора, совпадающие с соответствующими осями координат (x заменяет вектор <1, 0, 0>, y – <0, 1, 0>, z – <0, 0, 1>); при вводе дробей с нулевой целой частью можно не писать ноль перед точкой (.1 вместо 0.1).

Следует отметить различия координатной системы POV-Ray и Blender: в последнем ось z направлена в зенит, а вращение объектов происходит по часовой стрелке (если смотреть по направлению оси вращения). В POV-Ray ось z направлена к горизонту виртуального мира, а вращение происходит против часовой.

Вооружившись этими простыми правилами, приступим к написанию нашей первой сцены. Создайте текстовый файл с именем sphere.pov, откройте его в любом текстовом редакторе (Vi, Emacs, Kate «понимают» синтаксис SDL) и введите следующий текст:

 camera {
 	 location <0, 0, -4>
 	 look_at <0,0,0>
 	 angle 50
 }
 light_source {
 	 <4,4,-3>, rgb 1
 }
 sphere {
 	 <0, 0, 0>, 1
 	 pigment {
 		 color rgb x
 	 }
 }

В первой строке создаётся камера и определяются её основные характеристики: положение, отслеживаемая точка и угол поля зрения, соответственно. Положение камеры и точки обзора задаётся векторами. Как видите, ничего сверхъестественного нет – точно те же параметры (если не больше) мы бы указали, размещая камеру в Blender. В шестой строке создаётся источник света, которому требуются два обязательных параметра: вектор, задающий положение лампы, и цветовой вектор, задающий окраску и интенсивность света. На последнем стоит остановиться подробнее. Строго говоря, цвет в POV-Ray описывается пятью числами: привычной RGB-триадой основных цветов, пропусканием [transmit] и фильтрацией [filter]. Ключевое слово rgb подсказывает POV-Ray, что мы определяем только RGB-компоненты цвета, а пропускание и фильтрация будут нулевыми. Внимательный читатель может воскликнуть: «Цвет задаётся вектором, а в коде после rgb стоит число!» Ничего страшного в этом нет: POV-Ray догадается, что вы имели в виду, и заменит его на вектор требуемой размерности, все компоненты которого будут равны указанному числу. В нашем случае, получится вектор <1, 1, 1> обозначающий чистый белый свет.

Наконец, в девятой строке создаётся сфера. Указываются два обязательных параметра: положение (вектор) и радиус (число), а далее идёт объявление нового объекта «пигмент» (pigment), вложенного в сферу. Пигменты задают цвет поверхности объекта-родителя: без них POV-Ray успешно отрисует сцену, но сфера будет выглядеть чёрным кругом. Внутри пигмента содержится параметр color. Здесь есть ещё одна причина для удивления: нам нужно задать цвет, а переменная x вроде бы описывает координаты? Все в порядке: x – это просто псевдоним для вектора <1, 0, 0>, что бы ни значили его компоненты; в данном случае они определяют красный цвет.


Созданную сцену необходимо скомпилировать (отрисовать). Откройте консоль, перейдите в каталог, содержащий файл sphere.pov, введите команду povray sphere.pov, и на экране появится изображение сферы. Вдоволь налюбовавшись на свое первое творение, щелкните по окну, чтобы закрыть его.

Мир без полигонов

Многие читатели, уже хорошо знакомые с трёхмерной графикой, могут заинтересоваться количеством полигонов в отрисованной сфере: уж больно гладкая у неё поверхность. Сообщаем: ни одного! Для описания сцены POV-Ray применяет математиче­ские функции, на ходу рассчитывая точки пересечения лучей света с идеально гладкими поверхностями их графиков, и хотя полигональные объекты можно использовать в сценах, они служат только для импорта моделей из сторонних приложений. С одной стороны, такой подход к моделированию непривычен, с другой – мы избавлены от многих «узких мест»: выбора между высоким качеством и объёмом занимаемой памяти, видимых изломов на поверхностях при достаточно малом расстоянии от камеры до объекта; наконец, сложные поверхности (например, горные хребты), требуют для корректного отображения просто чудовищного числа полигонов.

В POV-Ray существует два основных способа моделирования: с помощью объединения базовых форм (сфер, цилиндров, кубов и т. д.) в более сложные объекты, либо путем создания собственных функций, описывающих сложную поверхность. Первый подход удобно применять для разнообразных технических изделий – деталей механизмов, зданий; второй же идеален для создания ландшафтов. Сегодня мы подробнее остановимся на моделировании с помощью функций, а механикой позанимаемся в следующей части.

Небо и земля

Поставим себе задачу изобразить планету радиусом около 6 000 условных километров, поднять на ней горы повыше Джомолунгмы, налить океан, прикрыть её атмосферой толщиной в десяток километров, а в довершение – вывести виртуальную камеру на орбиту и сфотографировать пейзаж. Не нужно бежать искать терабайтный винчестер – всё уместится в несколько килобайт!

Для лучшего контроля за визуализацией нашей сцены, создадим новый файл с настройками рендерера. Просто скопируйте planet.ini с LXFDVD в директорию с вашим проектом – основные настройки POV-Ray в нем снабжены подробными комментариями; советую прочитать и их.

Некоторые величины, описывающие геологию планеты (радиус, высота гор и т. д.), нам понадобятся не раз, и лучше сразу дать им понятные имена, чтобы не запутаться. Для определения имён разнообразных объектов в POV-Ray используется оператор #declare. Допишите в файл planet.pov следующие строчки:

#declare atmoradius = 6020;
#declare planetradius = 6000;
#declare reliefheigth = 30;
#declare oceandeep = 11;

Как всегда, хорошим тоном будет сразу разнести основные компоненты нашей сцены (материалы, функции и сами объекты) по отдельным файлам. Скажем, создайте файлы planet_texture.inc и planet_functions.inc, а в planet.pov добавьте строки

#include «planet_functions.inc» 
#include «planet_texture.inc» 

Первую из них придется продублировать и в начале файла planet_texture.inc. Ключевое слово #include велит POV-Ray перед дальнейшей обработкой сцены открыть и прочитать указанный файл.

Приступим к созданию объектов. Добавьте в planet.pov следующие строчки, создающие камеру и источник света:

 camera {
 	 location z*-12000
 	 look_at 0
 	 angle 90
 }
 light_source {
 	 x*15000, rgb 1
 	 rotate y*40
 }

Выражение z*-12000 обозначает умножение вектора z на число -12 000, т.е. перемещение камеры на 12 000 единиц назад от центра мира (z – это вектор <0, 0, 1>, значит, z*-12000 – <0, 0, -12000>).

По умолчанию, в сцене POV-Ray присутствует рассеянное освещение для смягчения тени, но в космосе рассеянного света нет, поэтому нам следует отключить его:

 global_settings {
 	 ambient_light 0
 }

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

Время кодировать

Начнём с создания сферы. Добавьте в planet_functions.inc строку:

#declare planetoid = function { sqrt( pow(x,2) + pow(y,2) + pow(z,2) ) }

Она начинается с уже знакомого нам ключевого слова #declare, после которого идёт имя определяемого объекта. Слово function за знаком равенства создаёт новый объект-функцию, математическое выражение для которой приведено в фигурных скобках. Если у вас есть вопросы – обратитесь к полному листингу на LXFDVD; он снабжен подробными комментариями. Необходимо отметить, что переменные x, y и z внутри функций меняют своё поведение: теперь это не вектора единичной длины, а координаты точки в пространстве, для которой вычисляется значение функции. В нашем случае, значением функции будет расстояние от точки в пространстве до центра сцены, а множество равноудалённых от центра точек образуют сферу.

Чтобы сделать сферу видимой, нужно превратить абстрактную формулу в поверхность. Для этого применяется специальный объект – изоповерхность (isosurface), делающий видимыми области, в которых функция принимает определённое значение. Вернитесь в файл planet.pov и припишите к нему:

 isosurface {
 	 function { planetoid(x,y,z) }
 	 threshold planetradius
 	 accuracy .000000001
 	 max_gradient 1.6
 	 contained_by { sphere { 0, planetradius+150 } }
 	 pigment { biosphere }
 }

При создании объекта isosurface необходимо указать функцию, на основе которой будет строиться поверхность. У нас это planetoid(), определённая ранее в файле planet_functions.inc. Следующий параметр – threshold (порог), сообщающий, через область с каким значением функции пройдёт будущая поверхность. Мы используем здесь ранее заданную переменную planetradius, значение которой равно 6000 – это радиус сферы. Далее идут два важнейших для создания нормального изображения параметра: accuracy (точность) и max_gradient (максимальный градиент). Если их значения будут не оптимальны, мы получим чрезмерно долгую отрисовку с артефактами (тёмные полосы, дыры в поверхностях и т. д.). Легче всего настроить максимальный градиент: если он слишком мал или велик, POV-Ray напечатает в консоли предупреждение, предложив оптимальное значение. С accuracy сложнее: точность не должна быть ни слишком высокой, ни слишком низкой. Обычно требуются небольшие значения (порядка нескольких тысячных), а если очень малая accuracy не помогает избавится от артефактов, а, наоборот, усиливает их – это повод начать её увеличение.

Параметр contained_by задаёт объект, ограничивающий пространство, в котором может располагаться изоповерхность. В нашей сцене ограничителем служит сфера с радиусом на 150 единиц большим, чем у планеты. Последний параметр назначает для нашей изоповерхности текстуру – это пигмент biosphere, который пока что определен в planet_texture.inc следующим образом:

#declare biosphere = pigment { color rgb .6 }


Посмотрите, что получилось: запустите в консоли povray planet.ini (или взгляните на рисунок). Да, это простой серый шар, но теперь мы можем деформировать поверхность, чтобы создать рельеф.

Поднимем горы

Вернитесь в файл planet_functions.inc и определите функцию, описывающую горы:

 #declare highland = function {
 	 pattern {
 		 crackle
 		 warp {
 			 turbulence .4
 			 octaves 4
 			 lambda 2
 			 omega .7
 		 }
 		 scale planetradius*.025
 	 }
 }

Здесь используется метод определения функции через встроенные в POV-Ray генераторы-паттерны [pattern], другими словами – процедурные текстуры. Функции, задаваемые с помощью паттернов, возвращают значения от 0 (чёрный цвет на текстуре) до 1 (белый цвет). В нашем случае используется паттерн crackle (аналог текстуры voronoi в Blender); слово warp определяет искажение базовой формы, turbulence – тип и силу искажения; octaves, lambda и omega — дополнительные параметры; scale – модификатор, изменяющий размер рисунка (паттерны, их модификаторы и процедурные текстуры будут детально рассмотрены в следующей статье, а самые нетерпеливые могут обратиться к комментариям в файле на диске).

Создадим еще одну функцию, описывающую контуры континентов и характер рельефа (bozo – близкий родственник Blender-текстуры по имени clouds):


 #declare lowlands = function {
 	 pattern {
 		 bozo
 		 warp {
 			 turbulence 1
 			 octaves 4
 			 lambda 2
 			 omega .4
 		 }
 		 scale planetradius*.3
 	 }
 }

Наконец, объединим две предыдущие функции в одну, описывающую весь рельеф планеты:

#declare landscape = function {(lowlands(x,y,z)+highland(x,y,z)*pow(lowlands(x,y,z),4))*.7}

Осталось лишь применить созданную функцию к изоповерхности. Вернитесь в файл planet.pov и замените соответствующую строку на

function { planetoid(x,y,z) - landscape(x,y,z)*reliefheigth }

Снова запустите отрисовку командой povray planet.ini. Теперь она будет идти довольно долго, но вместо голого шара появится нечто, испещрённое горами и ущельями. Рельеф планеты готов!


Вдохнем жизнь

Как мёртвый каменный мир, наша планета неплохо смотрится уже сейчас, но куда интересней она будет выглядеть с атмосферой, водоёмами и лесами. Давайте нальем океаны – для этого нужно просто создать в planet.pov сферу со следующими настройками:

 sphere {
 	 0, planetradius+oceandeep
 	 pigment { color rgb <0,.05,.5> }
 }

Теперь перейдём в файл planet_texture.inc и как следует разукрасим нашу планету. На Земле вершины гор скрыты льдом, сами скалы лишены растительности и окрашены в красно-коричневые оттенки, равнины покрыты густой зеленью, а прибрежные зоны – песком или галькой; нам нужно воспроизвести это чередование цветов. Вначале зададим основные цвета, вписав перед определением пигмента biosphere строки:

#declare silt = color rgb .7;
#declare beach = color rgb <.5, .45, .05>;
#declare forests = color rgb <0, .2, .02>;
#declare rock = color rgb <.2, .08, .02>;
#declare ice = color rgb .8;

Далее надо изменить сам пигмент biosphere следующим образом:

 #declare biosphere = pigment {
 	 function { landscape(x,y,z) }
 	 color_map {
 		 [0 color silt]
 		 [.36 color silt]
 		 [.365 color beach]
 		 [.37 color beach]
 		 [.38 color forests]
 		 [.48 color forests]
 		 [.54 color rock]
 		 [.55 color rock]
 		 [.56 color ice]
 		 [1 color ice]
 	 }
 }

Здесь мы воспользовались объектом color_map чтобы из­менять цвет поверхности в зависимости от значения функции landscape().

Наконец, добавим атмосферу, определив в файле planet.pov объект sphere с параметрами:


 sphere {
 	 0, atmoradius
 	 hollow
 	 material {atmosphere}
 }

Атмосфера рассеивает и поглощает солнечный свет. В объявлении сферы использовано ключевое слово hollow, которое подготавливает объект к имитации объёмной среды, рассеивающей свет. Вместо пигмента задан материал (material) – сложнейший объект, объединяющий все оптиче­ские свойства предмета: от цвета поверхности до подповерхностного рассеивания света.

Перейдём в файл planet_texture.inc и добавим в нём еще один интересный материал, следующего вида:

 #declare atmosphere = material {
 	 texture { pigment { color rgbt 1 } }
 	 interior {
 		 media {
 			 scattering { 3, rgb <.1,.8,1>*.003 }
 			 absorption rgb <.1,.8,1>*.003
 		 }
 	 }
 }

Запустив отрисовку, мы увидим голубоватую дымку, привычно окутывающую планету.

Запустим спутник

То, что у нас получилось – это не просто шар с текстурой! Замените старое описание камеры на следующее:

 camera {
 	 #local camLoc = -6200 * z;
 	 location camLoc
 	 sky -x
 	 look_at camLoc - x + .3*z
 	 angle 90
 	 rotate <-26, -.8, 0>
 }

Камера подойдёт ближе к поверхности планеты (по земным меркам, высота над поверхностью составит около 150 километров) и повернётся к одному из хребтов. Выполните отрисовку еще раз – и вы увидите горную цепь с ущельями, напоминающими русла рек. Подобные пейзажи можно найти по всей виртуальной планете: просто изменяйте вектор после слова rotate, чтобы переезжать с места на место.

Персональные инструменты
купить
подписаться
Яндекс.Метрика