2. Множество правил
Правило — это некая формальная запись, в которой определяется, как из одной структуры получается другая структура. Правила могут состоять из других правил.
Весьма условный пример правил для русского языка:
СЛОВО = “один или несколько слогов” СЛОГ = “согласная”+”гласный” СОГЛАСНАЯ = {б,в,г,д,ж, …, щ} ГЛАСНЫЙ = {a, е, о, .., я}
Для трехмерной структуры:
КУБ = “Полигон с координатами (0,0,0), (0,1,0), (0, 0, 1)”, “Полигон с координатами (0, 0, 0), (1, 0, 0), (1,1,0) и т.д.
Понятно, что в формальной теории или реальных приложениях правила записываются более строго и могут быть очень сложными (например Perl-синтаксис регулярных выражений). Для них существует множество теорем, которыми мучают студентов старших курсов.
3. Стартовое правило
порождение структуры не может начаться просто так, мы должны объявить базовый объект или базовое правило, с которого начнется построение, исходный шаг рекурсии.
Трехмерные фигуры как грамматики описываются в текстовых файлов специального формата .es (EisenScript).
Файл состоит как из собственно правил грамматики, так и вспомогательных инструкций, переменных и макросов, предназначенных для работы в трехмерном пространстве, а также параметризации с целью дальнейшей обработки, например, конвертации в видеофайл.
Правила и трансформации оперируют с базовыми геометрическими фигурами (примитивами) в трехмерном пространстве. У фигур, помимо 3d-координат, есть только цвет (но, к сожалению, не текстура, не материал и т.п.).
Очень хочется, но нельзя в качестве базовой фигуры взять уже готовую 3d-фигуру или сцену (хотя при желании и умении это можно добавить в код, например в документации заявлены, но не реализованы несколько примитивов типа цилиндра и конуса).
Результат выполнения — трехмерная полигональная сцена с базовой моделью освещения, которая может быть экспортирована в другие форматы или сохранена как растровое изображение. Её также можно просто покрутить, увеличить или уменьшить в редакторе в окне предпросмотра, программа достаточно быстра на современных PC и начинает притормаживать на сценах от ста тысяч объектов.
Итак, посмотрим, как в Eisenscript реализованы формальные грамматики.
1. Базовые примитивы
Алфавит среды — исходные строительные блоки, из которых создается фигура. Это шар, куб, вектор, прямоугольник, точка, поверхность.
Для описания примитива достаточно написать зарезервированное кодовое слово.
Пример примитивов:
box
sphere
grid
line
dot
2. Трансформации
Трансформации описывают всевозможные действия, применяемые к текущему состоянию (примитиву): сдвиг по осям x, y, z, повороты по трем осям, изменение цвета (абсолютное значение в RGB, смешивание текущего цвета с другим, изменение параметров тона-яркости-насыщенности (HSV), изменение альфа канала), масштабирование объекта в трех осях, зеркальное отражение, применение матрицы поворота.
Трансформации записываются в фигурных скобках и выглядят как буква (сокращение названия трансформации) и числовое значение-аргумент. Аргумент идет обязательно после пробела.
Аргументом является или число с плавающей запятой или целочисленное значение, зависит от типа.
Изменение в 3d-координатах это float, модификация цвета — integer.
Внутри одной трансформации может быть произвольное количество действий, если происходит несколько однотипных действий, то они автоматически складываются.
Также трансформации могут быть заданы рандомным числом.
Примеры:
{ x 1} // сдвигает текущее состояние по оси x на единицу
{x 2 y 2 z 2} // равномерно сдвигает состояние на 2 единицы по трем осям
{rx 30} // поворачивает относительно оси x на 30 градусов
{sat 10 hue -30} //изменяет атрибуты цвета
{x 1 x 1 x 1} // равно {x 3 }
Трансформации записываются сразу перед примитивами (или правилами). Либо это одна трансформация, либо их список, но со знаком умножения, который означает повторение трансформации N раз (итерация).
Пример:
1 * { hue 30 x 1 } // равно { hue 30 x 1}
10 * { x 1 hue 36 } 10 * { y 1 sat 0.9 } 10 * { z 1 b 0.9 } box
Итерация из примера выше является важным элементом языка.
Запись N * { transform t }, где N и t — некоторые числа, а transform — некоторая трансформация, эквивалентна N записям вида:
{ transform t} …
{ transform t*2} …
{ transform t*3} …