- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF133:pov-ray
Материал из Linuxformat.
- POV-Ray Занимательная механика – создаем фигуры правильной геометрической формы
Содержание |
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.