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

LXF132:pov-ray

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

Содержание

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

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


POV-Ray

Принято считать, что 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>, что бы ни значили его компоненты; в данном случае они определяют красный цвет.

LXF132 65 1.jpg Проба пера: красная сфера на черном фоне в десяти с небольшим строках кода.

Созданную сцену необходимо скомпилировать (отрисовать). Откройте консоль, перейдите в каталог, содержащий файл 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 }

LXF132 66 1.jpg Заготовка для нашей будущей планеты готова!

Посмотрите, что получилось: запустите в консоли 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):

LXF132 67 3.jpg Лучше гор могут быть только горы, на которых еще не бывал...

 #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. Теперь она будет идти довольно долго, но вместо голого шара появится нечто, испещрённое горами и ущельями. Рельеф планеты готов!

Иногда POV-Ray 3.7 Beta выдает сообщение об ошибке: «Parse Error: Redeclaring functions is not allowed - #undef the function first!». Создаваемая функция считается уже объявленной, что вызывает аварийное завершение работы. Проблема решается путём добавления команды #undef <имя функции> перед объявлением последней.

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

Как мёртвый каменный мир, наша планета неплохо смотрится уже сейчас, но куда интересней она будет выглядеть с атмосферой, водоёмами и лесами. Давайте нальем океаны – для этого нужно просто создать в 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 с параметрами:

LXF132 67 1.jpg Нальем моря и пустим воздух. А заодно высадим лес.

 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
 		 }
 	 }
 }

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

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

LXF132 67 2.jpg Земля в иллюми­наторе! Ну, не совсем Земля...

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

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

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

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