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

LXF133:pov-ray

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

Содержание

POV-Ray: Зубчатое колесо

Колесо, как известно, является одним из величайших изобретений человечества. Вячеслав Ястребцев увековечит его в растре.


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

Подготовка

Как и в прошлый раз, мы опишем основные элементы нашей сцены по отдельности, а потом соединим их в законченную композицию. Для удобства работы разведём объекты по собственным файлам, согласно их типу: формы поверхностей (файл mech_shapes.inс на диске), текстуры (mech_textures.inс) и непосредственно сцена (mech.pov). Для краткости, я буду придерживаться этого порядка именования и далее.

Первым делом разместим камеру и светильники: откройте файл mech.pov и подключите к сцене пока пустые файлы mech_shapes.inс и mech_textures.inс (обязательно создайте эти пустые файлы!) с помощью инструкции #include <имя файла>. Разместим камеру в позиции <0, 20, 0> и направим в точку <0,0,0>, затем повесим в точке <20, 20, 20> источник белого света. В результате должно получится следующее:

 camera {
 	 location <0, 20, 0>
 	 look_at 0
 	 angle 47
 }
 light_source {
 	 <20, 20, 20>,
 	 color rgb 1
 }

Конструктор

Приступаем к самому интересному – созданию зубчатой передачи. Вначале создадим один зубец, присвоив ему имя tooth. Итак, открываем mech_shapes.inс и набираем:

 #declare tooth = prism {
 	 -.5, .5,
 	 6,
 	 <-.12, -.02>, <-.12, .2>, <-.07, .4>,
 	 <.07, .4>, <.12, .2>, <.12, -.02>
 }

Нами использован новый объект – prism (призма), имеющий следующие обязательные параметры: положение нижнего и верхнего торца по оси Y, число боковых граней призмы, X- и Z-координаты боковых граней призмы (чтобы лучше представлять координаты, удобно набросать чертёж детали заранее). Созданный объект пока не виден в сцене (можете запустить рендер и проверить), ведь мы просто сказали POV-Ray: «Слово tooth обозначает призму с параметрами...». Рендерер запоминает призму, но не помещает её в сцену без специального оператора object. Воспользуемся им:

 object {
 	 tooth
 	 pigment { color rgb x }
 }

Ура, теперь зубец виден! Но этого мало: нужно создать десятки зубцов, расположив их на окружности. Попробуем сдвинуть зубец с места...

Трансформации

Для изменения положения и размеров объектов в сцене POV-Ray использует модификаторы translate, rotate и scale (перемещение, поворот и масштаб, соответственно). После модификатора указывается трёхмерный вектор, задающий величину изменения объекта по осям (для translate – смещения по каждой из осей, для scale – коэффициенты масштабирования, а для rotate, к счастью, определять вращения через кватернионы в особо извращённой форме POV-Ray не требует: каждый компонент вектора задаёт поворот вокруг соответствующей оси (против часовой стрелки, при взгляде по оси вращения, или по часовой, если взгляд направлен против оси вращения). Сместим зубец на 5 единиц по оси Z, добавив внутрь оператора object строку translate 5*z, после слова tooth. Теперь повернём на 45° вокруг оси Y, добавив rotate 45*y после модификатора смещения. Порядок модификаторов очень важен: во многих 3D-редакторах можно указывать центр трансформации, но POV-Ray всегда трансформирует объекты относительно начала координат! Поэтому вращение и масштабирование объектов, отодвинутых от начала координат, приведёт к их смещению. Попробуйте поменять местами сдвиг и поворот зубца, чтобы увидеть различия.

Разобравшись со сдвигом, перейдём к «размножению» зубцов. Нужно просто несколько раз добавить оператор object с правильными трансформациями... тут возникает масса проблем: число зубцов измеряется многими десятками – вбивать всё это очень долго; в каждом случае необходимо рассчитать правильные трансформации – это слишком сложно; наконец, километровая «простыня» везде, где нужна шестерня – это недопустимо! На помощь приходят директивы препроцессора и встроенные функции SDL: мы напишем макрос, создающий шестерёнки.

Макросы

Вначале узнаем точные размеры (габариты) зубца. Для вычисления положения углов габаритного контейнера объектов используются функции max_extent() и min_extent(), принимающие идентификатор объекта и возвращающие координаты дальнего и ближнего углов габаритного контейнера соответственно. Используем их по назначению, добавив перед object строчки:

 #declare max_dim = max_extent(tooth); // Дальний угол габаритного контейнера
 #declare min_dim = min_extent(tooth); // Ближний угол габаритного контейнера
 #declare tooth_dist = (max_dim.x - min_dim.x)*2; // Дистанция между зубцами

При расчёте дистанции использована новая конструкция: идентификатор вектора и через точку x – извлечение x-компоненты вектора (указав y или z, можно извлечь и другие компоненты соответственно). В результате, tooth_step содержит расстояние между вершинами зубцов.

Зная эту величину и число зубцов, легко рассчитать длину окружности и радиус шестерни; последняя величина равна требуемому сдвигу зубца от центра. Поделив 360 на число зубцов, легко найти угловой шаг зубцов. Определим макрос, принимающий число зубцов в переменную ToothNum, добавив перед object, но после объявления tooth_dist:

 #macro gear(ToothNum)
 	 #declare Radius = (tooth_dist*ToothNum)/(2*pi); // Радиус шестерни
 	 #declare Angle = (360/ToothNum)*y; // Угловой шаг зубцов шестерни
 	 union {

Оператор union объединит все детали шестерёнки в единый объект, что облегчит дальнейшую работу. С дублированием зубцов превосходно справится директива #while … #end, организующая многократное выполнение команд, пока выполняется заданное условие. Добавим перед object:

 	 #declare Count = 0;
 	 #while (Count < ToothNum)

А после закрывающей object фигурной скобки –

 	 #declare Count=Count+1;
 	 #end

Изменим трансформации внутри object на следующие:

 translate Radius*z
 rotate Angle*Count

Конструкция выше создаст кольцо из зубцов: заполним пустоту в центре цилиндром, указав координаты его торцов и радиус (равный переменной Radius), и закроем оператор union (обратитесь к файлу на диске, если что-то не работает).

 		 cylinder {
 			 max_dim.y*y, min_dim.y*y,
 			 Radius
 			 pigment { color rgb z }
 		 }
 	 }

Объявим переменную Gear_radius, облегчающую расположение шестерёнок, и закроем макрос директивой #end:

 	 #declare Gear_radius = (Radius+max_dim.z*.5)*x;
 #end

Зубец снова пропал, превратившись в генератор шестерёнок. Перейдём в mech.pov, откроем оператор union { и добавим объект:

 union{
 	 object {
 		 gear(50)
 		 rotate clock * Angle*y
 		 #declare masterRadius = Gear_radius;
 	 }

В объекте мы обратились к нашему макросу, заказав шестерню с 50 зубцами, после чего задали поворот, использовав переменную clock, предопределённую самим POV-Ray и хранящую время с начала анимации; сейчас она содержит 0.

Добавим вторую шестерню после первой, закрыв объединение:

 	 object {
 		 gear(30)
 		 rotate -clock * Angle + Angle*.5
 		 translate Gear_radius + masterRadius
 	 }
 	 translate -2*x
 	 rotation 60*z
 }

Чтобы обе шестерни уместились в кадре, сдвинем объединение на 2 единицы влево, а поворот сделает композицию сцены динамичнее. Запустите рендер.

Ясная, твёрдая, верная сталь

Яркие сине-красные цвета нехарактерны для изделий чёрной металлургии. Чтобы добавить сцене реализма, опишем в файле mech_texture.inc текстуру стали:

 #declare steel = texture {
 	 pigment { color rgb <.9,.95,1>*.2 }
 	 finish {
 		 specular .7
 		 roughness .01
 		 metallic
 	 }
 }

Для имитации бликов на металле был использован новый оператор finish (отделка), содержащий следующие параметры: specular – интенсивность блика, roughness – резкость краёв и размер блика (чем ниже значение, тем резче края и меньше блик), metallic – ключевое слово, делающее блик более «металлическим», окрашивая его в цвет пигмента.

В mech.pov добавьте по оператору texture { steel } сразу после каждого вызова макроса gear. В начало файла добавьте ещё один светильник:

 light_source {
 	 <-20, 20, 20>,
 	 color rgb 1
 }

Удалите из mech_shapes.inс все пигменты – они нам больше не понадобятся. Теперь запускайте рендер и любуйтесь результатом.

Ровная, без единого изъяна, поверхность шестерни смотрится мёртво и искусственно. Сымитируем лёгкий налёт ржавчины, переписав пигмент текстуры steel:


 pigment {
 	 bozo
 	 color_map {
 		 [.37 color rgb <.85,.9,1>*.03]
 		 [.4 color rgb <1,.6,.5>*.03]
 	 }
 }

Bozo (как вы, надеюсь, помните из предыдущего урока) – тип генератора процедурной текстуры, создающий плавные переходы от 0 до 1, напоминающие облака. Директива color_map позволяет определить изменения цвета в зависимости от значения генератора. В квадратных скобках описываются ключевые точки в формате [<значение генератора> <цвет>]; между соседними точками цвет линейно интерполируется.

Теперь поверхность шестерёнок покрыта бурым налётом, но границы ржавчины и металла слишком ровные – необходимо сильнее перемешать значения генератора bozo, используя оператор warp. Добавьте сразу после bozo следующее:

 warp {
 	 turbulence 1
 	 octaves 4
 	 lambda 3
 	 omega .7
 }

Turbulence – ключевое слово, задающее тип искажения; турбулентность несколько раз смещает текстуру в каждой точке. Число смещений задаётся параметром octaves; lambda определяет вариативность направления смещения (чем ближе к единице, тем равномерней смещение); omega – отношение дистанций текущего и предыдущего смещений; число после turbulence указывает дистанцию первого смещения.

Теперь края ржавых пятен стали рваными, что прибавило сцене реализма. Анимируем сцену, просто запустив POV-Ray командой povray +KFF15 +KF3 <имя файла>, где +KFF<число> – количество кадров, +KF<число> – значение переменной clock в последнем кадре; далее следует имя файла сцены (расширение *.pov) или файла с настройками (*.ini). Выполнив povray +KFF15 +KF3 mech.ini, получим 15 кадров анимации поворота шестерёнок на 3 зубца. На выходе будет набор из 15 файлов с карами: воспользуйтесь сторонней графической программой (GIMP, ImageMagick, Blender и т. д.) и соберите их в анимированный GIF, PNG или видеофайл.

И кое-что еще

Маленький бонус: замените свой файл mech_shapes.inc файлом mech_shapes_extend.inc с диска. В нем находится переписанный макрос gear. Теперь шестерёнки содержат больше деталей! Разберитесь, что было сделано, на досуге.

Загляните на...

Несколько полезных сайтов о POV-Ray:

  • http://www.povray.org/ Основной сайт программы: исходные тексты, списки рассылки и самое главное...
  • http://hof.povray.org/ Зал славы, галерея лучших работ: многие неотличимы от фотографий.
  • http://www.f-lohmueller.de/index.htm Сайт, почти целиком оформленный изображениями, созданными в POV-Ray;
  • обязательно посетите галерею http://www.f-lohmueller.de/pov/g_000.htm#Trucks с детальнейшими моделями транспорта, целиком описанными на SDL.
Персональные инструменты
купить
подписаться
Яндекс.Метрика