Специальные Объекты
В Boxshot есть и другие объекты помимо узлов сцены. Нажмите ссылки ниже, чтобы быстро перейти к нужной теме:
Сцена
Boxshot поддерживает один объект сцены на каждый открытый документ. Вы не можете создать или открыть другую сцену из скрипта — просто работайте с той, которая сейчас загружена. Примеры использования сцены приведены здесь. Ниже — более структурированный список свойств и методов.
Узлы сцены
У каждой сцены есть один и только один корневой узел. Вы можете получить его дочерние узлы, но не можете редактировать сам корень, так как он доступен только для чтения. При этом можно добавлять, клонировать или удалять его дочерние узлы. Используйте следующий код, чтобы получить корневой узел:
var root = scene.root;
Однако при попытке выполнить любой из следующих вызовов вы получите сообщение об ошибке:
scene.root.name = "my name";
scene.root.visible = false;
scene.root.translation = vec3(1, 1, 1);
Дочерние узлы можно получить точно так же, как и у любого другого узла сцены:
var children = scene.root.children;
print("у корневого узла %1 дочерних узлов", children.length);
Сохранение и экспорт
Boxshot сохраняет сцены во внутреннем формате, а также позволяет экспортировать в некоторые популярные 3D-форматы, такие как Collada или 3D PDF. С точки зрения скриптинга нет большой разницы, какой формат использовать. Сохранение выполняется так:
scene.save(filename); // версия по умолчанию
scene.save(filename, params); // версия с параметрами
Переменная params — это словарь с настройками плагина сохранения и самого Boxshot. Boxshot пытается определить формат сохранения по расширению файла, которое вы передаете. Все плагины сохранения сообщают Boxshot, какие расширения они поддерживают, поэтому Boxshot легко подбирает подходящий плагин. Если вам нужно сохранить файл с нестандартным расширением, вы можете передать MIME-тип параметром:
var params = {"mime": "model/dae"};
scene.save("collada-file.txt", params);
Чтобы сохранить текущую сцену как проект Boxshot, используйте такой код:
scene.save("file.boxshot5");
Импорт
Вы можете импортировать другой проект Boxshot в сцену так:
const target = scene.root;
scene.importProject(target, "/full/path/to/other/project.boxshot5");
Рендеринг
Вы также можете рендерить сцену из скрипта — так же, как и из интерфейса. Boxshot позволяет настроить движок рендеринга так, как вам нужно, поэтому рендеринг можно автоматизировать. Пример рендеринга из скрипта:
var params = {"width": 400, "height": 300, "passes": 200};
scene.render("renderer.raytracer3", "/path/to/file.png", params);
Обратите внимание: рендеринг может занять некоторое время и не может быть отменен, если запущен из скрипта, поэтому убедитесь, что вы сначала сохранили свою задачу. Этот метод рассчитан на пакетный режим, поэтому, если возможно, лучше используйте рендеринг через интерфейс.
Параметр passes задает число проходов. Вместо него можно использовать minutes и указать время рендеринга.
Метод render() принимает 3 параметра. Первый задает движок рендеринга, варианты описаны в учебнике по рендерингу из скриптов. Второй параметр задает имя файла, в который будет сохранено изображение. Убедитесь, что вы указали полный путь к файлу. Последний параметр — словарь свойств, которые передаются движку рендеринга; здесь можно задать разрешение. Если вы укажете только width или только height, Boxshot вычислит второе измерение по соотношению сторон камеры.
Изменение свойств сцены
Вы можете получать доступ ко всем свойствам сцены из скриптов. Например:
// загрузить фоновое изображение и задать пурпурный оттенок
scene.backgroundMode = 0; // 0 - однотонный фон, 1 - прозрачный фон, 2 - фон окружения
scene.backgroundTint = color("#FF00FF");
scene.backgroundImage = "filename.jpg";
// настроить окружение сцены
scene.environmentImage = "environment.exr"; //
scene.environmentIntensity = 1.0; // означает 100%
scene.environmentOffsetH = 0; //
scene.environmentOffsetV = 0; //
scene.environmentTint = color("#FFFFFF"); // белый оттенок
// настроить солнечный свет
scene.sunEnabled = true; // включить солнечный свет
scene.sunHeight = 45; //
scene.sunRotation = 30; //
scene.sunIntensity = 0.5; // 50%
scene.sunAngularSize = 2.0; // сделать тень мягче
scene.sunTint = color("#FFFFF0"); // сделать солнечный свет слегка желтоватым
// настроить пол
scene.showFloor = true; // показывать пол
scene.floorReflectionEnabled = true; // включить отражение пола
scene.floorReflectionLevel = 0.75; // уровень отражения 75%
scene.floorReflectionDecay = 0; // без затухания
scene.floorRoughnessLevel = 0; // зеркальное отражение пола
// расширенные настройки сцены
scene.realisticLighting = true; // включить более медленное, но более реалистичное освещение
scene.diffuseIntensity = 1.0;
scene.floorDiffuseLevel = 1.0;
scene.floorTotalShadowLevel = 1.0;
scene.floorEnvShadowLevel = 1.0;
scene.innerReflectionsReflectEnvironment = true;
Камера
Вы можете получать доступ ко всем параметрам камеры из скриптов. Используйте следующий код, чтобы получить объект камеры:
var c = scene.camera;
print(c);
Объект камеры позволяет менять углы, FOV, дистанцию, соотношение сторон и центральную точку вращения. Вот как получать и задавать углы:
var c = scene.camera;
// прочитать углы поворота
print("углы поворота камеры: %1, %2", c.hangle, c.vangle);
// изменить углы поворота
c.setAngles(10, 20);
print("новые углы поворота камеры: %1, %2", c.hangle, c.vangle);
Остальные свойства еще проще:
var c = scene.camera;
c.distance = 30;
c.aspect = 4.0/3.0;
c.fov = 45;
c.znear = 1.0;
c.zfar = 3000.0;
// задать центр вращения
c.center = vec3(0, 0, 1);
// настроить глубину резкости
c.depthOfField = true;
c.focalDistance = 123.3;
c.apertureSize = 1.0;
Источники света
Вы можете создавать источники света из скрипта точно так же, как группы или объекты (подробнее см. в учебнике по управлению объектами). Затем вы можете получать доступ ко всем параметрам источника света из скрипта:
// создать источник света
var l = scene.root.addLight("test light");
l.radius = 1.0;
l.intensity = 2.0;
l.color = color("#ff00ff");
l.lightVisible = true;
// переместить его
l.translation = vec3(10, 20, 30);
Вы по-прежнему можете переименовывать и скрывать источник света точно так же, как любой другой узел сцены:
l.visible = false;
l.name = "hidden light";
Материалы
Материалы в Boxshot достаточно сложные, поэтому сначала полезно прочитать учебник по материалам.
Получение материалов
Материалы можно получить только у реальных геометрических объектов. Давайте создадим цилиндр и получим его материалы:
var m = scene.root.addMesh("cylinder", "generator.simple.cylinder");
var mtls = m.materials;
print("У цилиндра %1 материалов", mtls.length);
for (var i = 0; i < mtls.length; i++)
print("%1. %2", i + 1, mtls[i].name);
Если вы знаете название материала, есть более простой способ получить его:
var m = scene.root.addMesh("sphere", "generator.simple.sphere");
var mtl = m.material("Surface");
Базовые свойства
Вот как изменить наиболее часто используемые свойства материала:
// создать сферу и получить ее материал
var m = scene.root.addMesh("sphere", "generator.simple.sphere");
var mtl = m.material("Surface");
mtl.metallicReflection = false;
mtl.saturatedReflection = true;
mtl.alphaIsReflectionMask = false;
mtl.reflection180Level = 0.2;
mtl.reflection180Tint = color(1, 0.5, 0);
mtl.refractionIndexN = 1.5;
mtl.refractionIndexK = 0;
mtl.opacity = 1.0;
mtl.refract = true;
mtl.refractionTransmittance = color(0.2, 0.1, 0.8);
mtl.refractionAttenuation = 100;
mtl.bumpMode = "Normal"; // используйте "None", "Normal", "ReliefIn" или "ReliefOut"
mtl.normalMapLevel = 0.75;
mtl.heightMapLevel = 0;
mtl.thinFilmEnabled = true;
mtl.thinFilmMinimalThickness = 60;
mtl.thinFilmRefractionN = 2.5;
mtl.thinFilmRefractionK = 0;
Доступ к слотам текстур выполняется так:
var tsDiffuse = mtl.diffuseSlot;
var tsReflectance = mtl.reflectanceSlot;
var tsRoughness = mtl.roughnessSlot;
var tsAnisotropyLevel = mtl.anisotropyLevelSlot;
var tsAnisotropyAngle = mtl.anisotropyAngleSlot;
var tsHeightmap = mtl.heightmapSlot;
var tsThinFilm = mtl.thinFilmSlot;
Каждый слот можно настраивать по примеру ниже:
var tsDiffuse = mtl.diffuseSlot;
var tsRoughness = mtl.roughnessSlot;
tsDiffuse.tint = color(1, 0.5, 0, 1); // если слот поддерживает оттенок (tint)
tsRoughness.value = 0.2; // если слот поддерживает числовое значение уровня
tsDiffuse.filename = "texture.jpg";
tsDiffuse.repeatU = 2;
tsDiffuse.repeatV = 3;
tsDiffuse.offsetU = 0.2;
tsDiffuse.offsetV = -0.5;
tsDiffuse.wrapU = true;
tsDiffuse.wrapV = true;
tsDiffuse.linearFiltering = false;
tsDiffuse.rotation = 10; // здесь используются градусы
tsDiffuse.crop = [0, 0.5, 1, 0.5]; // left, top, width, height; все в диапазоне 0..1 (если слот поддерживает обрезку)
Клонирование материалов
Каждый материал может вернуть словарь своих параметров:
var s = scene.root.addMesh("sphere", "generator.simple.sphere");
var m = s.material("Surface");
var p = m.parameters;
for (var k in p)
print("%1 -> %2", k, p[k]);
Вы можете собрать свой словарь и передать его обратно материалу. Просто используйте идентификаторы из реального словаря параметров:
var d = {"opacity": 0.5, "diffuse-tint": "#FF8000"};
m.parameters = d;
Boxshot молча пропускает неизвестные элементы, поэтому если вы не видите нужных изменений после применения параметров, проверьте синтаксис ключей словаря.
Теперь можно скопировать один материал в другой так же, как вы делаете это перетаскиванием на другую сетку. Вот код:
var s1 = scene.root.addMesh("sphere 1", "generator.simple.sphere");
var m1 = s1.material("Surface");
m1.diffuseColor = color(1, 0, 0);
m1.opacity = 0.8;
var s2 = scene.root.addMesh("sphere 2", "generator.simple.sphere");
s2.translation = vec3(0, 0, 20);
var m2 = s2.material("Surface");
m2.parameters = m1.parameters;
Самая последняя строка копирует все параметры материала с первой сферы на вторую.
Наклейки
Подробнее о наклейках или декалях можно прочитать в учебнике по наклейкам. Ниже показано, как создавать наклейки из скриптов, получать к ним доступ и менять их параметры.
Создание наклеек
Чтобы создать наклейку, вам нужен геометрический объект, на который вы ее разместите. Затем просто вызовите метод addDecal(from, to, image) у этого объекта, чтобы разместить image как наклейку:
var m = scene.root.addMesh("sphere", "generator.simple.sphere");
var d = m.addDecal(vec3(0, -100, 10), vec3(0, 0, 10), ":/textures/decals/Zombies 1.png");
Параметры from и to задаются в мировых координатах и определяют луч, который пересекается с объектом, чтобы найти точку размещения наклейки. Луч используется вместо конкретной точки на сетке потому, что объекты в Boxshot могут меняться, и программе нужно отображать наклейки как можно ближе к их исходному положению. Имея луч, Boxshot может пересечь его с новой геометрией и найти новую позицию наклейку.
Доступ к наклейкам объекта
Чтобы получить доступ к существующим наклейкам, вам снова нужен геометрический объект, на котором они расположены. Затем вы можете получить наклейки через его свойство decals:
var s = scene.selection[0];
var decals = s.decals;
print(decals.length);
Вот как вывести имена наклеек:
var s = scene.selection[0];
var decals = s.decals;
for (var i = 0; i < decals.length; i++)
print(decals[i].name);
Свойство decals – это массив Javascript из объектов наклеек, поэтому вы можете получить его длину через length и перебирать, как любой другой массив.
Удаление наклеек
Чтобы удалить наклейку, просто передайте ее объект в метод deleteDecal(decal) ее геометрического объекта:
var m = scene.root.addMesh("sphere", "generator.simple.sphere");
var d = m.addDecal(vec3(0, -100, 10), vec3(0, 0, 10), ":/textures/decals/Zombies 1.png");
m.deleteDecal(d);
Код выше создает и сразу удаляет наклейку.
Доступ к свойствам наклейки
Код ниже показывает, как получать доступ к свойствам наклейки и изменять их:
var m = scene.root.addMesh("sphere", "generator.simple.sphere");
var d = m.addDecal(vec3(0, -100, 10), vec3(0, 0, 10), ":/textures/decals/Zombies 1.png");
d.name = "My Decal";
d.width = 5; // см
d.height = 4; // см
d.scale = 1.2;
d.rotation = 45; // градусы
d.fitToImage(); // обновляет ширину и высоту
d.offset = 0.1;
d.opacity = 1.0;
d.customBack = true;
var mtls = d.materials;
У наклейки может быть один или два (если включена обратная сторона) материала в виде массива в свойстве materials. Вы можете редактировать их так же, как и стандартные материалы сцены. Не все свойства доступны для редактирования, поэтому используйте элементы управления интерфейса как ориентир того, что именно можно менять у декалей.
Снапшоты
Вот как вывести список снапшотов с помощью скриптинга:
var s = scene.snapshots;
for(i = 0; i < s.all.length; i++)
print(s.all[i]);
Чтобы сделать новый снапшот, используйте этот код ( "ui" – глобальная
переменная, которую нужно передать параметром, чтобы сделать снапшот):
scene.snapshots.take("new snapshot", ui);
Наконец, чтобы активировать снапшот по индексу или по имени, используйте такой код:
scene.snapshots.activate(0);
scene.snapshots.activateByName("new snapshot");
Математические типы
Скриптовый движок Boxshot поддерживает некоторые распространенные математические функции, а также несколько встроенных типов, чтобы упростить скриптинг сцены.
Цвета
Boxshot активно использует цвета для тонирования изображений, поэтому скриптовый движок хорошо их поддерживает. Вот несколько примеров того, как создать объект цвета:
var orange = color("#FF8000");
var red = color(1, 0, 0);
var magenta = color(255, 0, 255, 255);
Обратите внимание: если все компоненты цвета меньше или равны 1, Boxshot интерпретирует их как числа с плавающей точкой. Поэтому если вам нужен (1, 1,
- в диапазоне 0..255, используйте строковую форму:
var almostBlack = color("#010101");
Доступ к компонентам цвета:
var c = color(10, 20, 30, 40);
print("r = %1, g = %2, b = %3, a = %4", c.r, c.g, c.b, c.a);
Даже если вы создаете цвет из строки или байтов, внутри значения цвета хранятся как float в диапазоне 0..1, поэтому вся математика с компонентами должна выполняться во float. Код выше не выводит 10, 20, 30 и 40 — он выводит float-значения. Вот как присваивать значения:
var c = color(0, 0, 0, 0);
c.r = 1;
c.g = 0.5;
c.b = 0;
c.a = 1;
print(c);
В Javascript присваивание означает копирование ссылки, а не значения, поэтому следующий код может вас удивить:
var c1 = color(1, 1, 1, 1);
var c2 = c1; // c2 теперь ссылается на c1
c2.r = 0; // изменение c2 меняет и c1
print("c1 = %1, c2 = %2", c1, c2);
Код выше выводит два одинаковых цвета. Чтобы сделать c2 копией c1, а не ссылкой, используйте метод clone():
var c1 = color(1, 1, 1, 1);
var c2 = c1.clone(); // c2 теперь копия c1, а не ссылка
c2.r = 0; // изменение c2 больше не меняет c1
print("c1 = %1, c2 = %2", c1, c2);
При необходимости с цветами можно выполнять математические операции. В Javascript нельзя перегружать операторы для пользовательских классов, поэтому используются методы:
var c1 = color(0.5, 0.5, 0.5);
var c2 = c1.mul(2); // умножить все компоненты на 2
print("c1 = %1, c2 = %2", c1, c2);
var c3 = c2.div(2); // разделить на 2
print("c3 = %1", c3);
Можно складывать и вычитать два цвета:
var c1 = color(0.1, 0.1, 0.1, 0.1);
var c2 = color(0.3, 0.3, 0.3, 0.3);
var cAdd = c1.add(c2);
var cSub = c2.sub(c1);
print("add = %1, sub = %2", cAdd, cSub);
Обратите внимание: методы mul(), div(), add() и sub() ограничивают (clamp) результат диапазоном 0..1, чтобы избежать переполнений. То же происходит при создании, поэтому color(300, 300, 300, 300) эквивалентен color(255, 255, 255, 255). Наконец, сравнение цветов:
var c1 = color(255, 255, 255, 255);
var c2 = color(1, 1, 1, 1);
print(c1.equals(c2));
Векторы
Векторы работают практически так же, как цвета выше. Вот как создать объект-вектор:
var a = vec3(1, 2, 3);
var b = vec3(1); // означает vec3(1, 1, 1)
Как и у цветов, можно обращаться к компонентам напрямую:
var a = vec3(1, 2, 3);
print("x = %1, y = %2, z = %3", a.x, a.y, a.z);
Можно менять значение вектора, изменяя его компоненты:
var a = vec3(0);
a.x = 1;
a.y = 2;
a.z = 3;
print(a);
Аналогично цветам, присваивание векторов означает присваивание ссылок; используйте clone(), чтобы копировать значения:
var a = vec3(1, 2, 3);
var b = a;
var c = a.clone();
a.x = 10;
print("a = %1, b = %2, c = %3", a, b, c);
Вы можете складывать, вычитать, умножать векторы и выполнять другие математические операции:
var a = vec3(1, 1, 1);
var b = vec3(3, 3, 3);
var c = a.add(b);
var d = b.sub(a);
print("add = %1, sub = %2", c, d);
Умножение и деление на число:
var a = vec3(1, 1, 1);
var b = a.mul(2);
var c = a.div(2);
print("mul = %1, div = %2", b, c);
Умножение на вектор:
var a = vec3(1, 2, 3);
var b = vec3(4, 5, 6);
var c = a.dot(b);
var d = a.cross(b);
print("dot = %1, cross = %2", c, d);
Также можно получить длину вектора или нормализовать его:
var a = vec3(1, 2, 3);
var len1 = a.length;
var b = a.normalized();
var c = a.clone();
var len2 = c.normalize();
Обратите внимание на разницу между normalize() и normalized(): первая функция изменяет вектор, а вторая — нет. Первая также возвращает старую длину вектора.
Математические функции
Вот список встроенных математических функций, которые вы можете использовать в скриптах:
- abs(x)
- acos(x)
- asin(x)
- atan(x)
- atan2(y, x)
- ceil(x)
- cos(x)
- exp(x)
- floor(x)
- log(x)
- max([value1 [, value2 [, …]]])
- min([value1 [, value2 [, …]]])
- pow(x, y)
- random()
- round(x)
- sin(x)
- sqrt(x)
- tan(x)
Все функции нужно вызывать с префиксом Math, например так:
var s = Math.sin(1);
var r = Math.random();
Также есть полезные константы:
- PI
- E
- LN10
- LN2
- LOG2E
- LOG10E
- SQRT1_2
- SQRT2
Обратите внимание: тригонометрические функции, такие как sin() и cos(), работают в радианах, а не в градусах, поэтому вам может понадобиться предварительно конвертировать значения:
var deg = 90;
var rad = 90 * Math.PI / 180;
var cos90 = Math.cos(rad);
print(cos90);
Пользовательские функции
Вы можете создавать свои пользовательские функции. Например, код преобразования градусов в радианы выше можно упростить так:
function deg2rad(d)
{
return d * Math.PI / 180;
}
print(Math.cos(deg2rad(90)));
Пользовательские функции могут обрабатывать встроенные объекты. Функция ниже переводит цвет в градации серого по самому простому алгоритму:
function grayscale(c)
{
var gray = (c.r + c.g + c.b) / 3;
return color(gray, gray, gray, c.a);
}
print(grayscale(color(1, 0, 0)));
Больше Информации о Скриптах
- Обзор — общая информация об использовании скриптов в Boxshot.
- Управление объектами — обход сцены и работа с ее элементами;
- Специальные объекты — камера, материалы, освещение итп;
- Объекты сцены — настройка встроенных объектов;
- Инструменты — использование инструментов из скриптов;
- Командная строка — запуск скриптов Boxshot из командной строки.