В данной статье я покажу как создать подобную сцену в продвинутом редакторе.
Для создания анимации — нужно зайти в сам редактор и создать новый проект (чтобы редактор был пустой).
Далее, нужно создать скрипт, привязанный к сцене.
Для перехода в режим редактирования, нужно нажать на кнопку Edit.
В открывшемся текстовом редакторе будет писаться весь код сцены.
Первым делом нужно создать функцию init(), эта функция выполняется при запуске сцены.
function init() {
}
Внутрь этой функции мы поместим освещение сцены. Я добавлю пять источников света: заполняющий, направленный и три точечных (строки 3-16).
function init() {
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
}
Следующим шагом нужно добавить непосредственно сам кусочек тумана. Для этого я буду использовать следующее изображение, загруженное на Dropbox.
Теперь, нужно создать плоскость и использовать данное изображение в качестве текстуры.
Для этого нужно воспользоваться специальным THREE.js классом, называемым загрузчик (loader).
Загрузка различных объектов с помощью загрузчика содержит в себе некоторые ограничения.
let loader = new THREE.TextureLoader();
function init() {
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
}
Теперь нужно создать геометрию и материал для будущей частицы тумана (строки 20-26). Геометрией является плоскость PlaneBufferGeometryразмером 500*500. Материал, это MeshLamberMaterial, куда, в качестве параметров переданы: map — текстура тумана, transparent — прозрачность (работает только для .png), depthWrite — проверка глубины (убрано для предотвращения артефактов перекрытия), side — материал с двух сторон у плоскости.
let loader = new THREE.TextureLoader();
function init() {
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
let cloudMaterial = new THREE.MeshLambertMaterial({
map: loader.load("https://dl.dropboxusercontent.com/s/4wvy8q8eyws4kpf/smoke-1.png?dl=1"),
transparent: true,
depthWrite: false,
side: THREE.DoubleSide
});
}
Так как мы создаем огромную туманность, нам нужно большое количество подобных плоскостей с кусочками тумана. Поэтому, далее, нужно добавить цикл, который будет создавать массив частиц (строки 28- 44). Так же, до объявления функции, нужно создать массив, куда будут добавляться все частицы тумана (строка 2).
let loader = new THREE.TextureLoader();
let cloudParticles = [];
function init() {
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
let cloudMaterial = new THREE.MeshLambertMaterial({
map: loader.load("https://dl.dropboxusercontent.com/s/4wvy8q8eyws4kpf/smoke-1.png?dl=1"),
transparent: true,
depthWrite: false,
side: THREE.DoubleSide
});
for(let i=0; i < 50; i++) {
let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
cloud.position.set(
Math.random() * 800 - 400,
500,
Math.random() * 500 - 500
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random() * 2 * Math.PI;
cloud.material.opacity = 0.55;
cloudParticles.push(cloud);
this.add(cloud);
}
}
Что мы сделали? Мы создаем мэш (строка 30), потом мы задаем рандомную позицию для каждой частицы, чтобы туман был не в одной маленькой точке (строки 31-35), после, немного поворачиваем плоскости (строки 36-38) и добавляем непрозрачность (строка 39). После всего, мы добавляем созданную частицу как в массив, так и на сцену.
Данный цикл повторяется 50 раз, благодаря чему создается 50 частиц.
Сделанный скрипт создает туман над сценой, поэтому нужно повернуть камеру в его сторону (строки 6-9).
let loader = new THREE.TextureLoader();
let cloudParticles = [];
function init() {
camera.position.z = 1;
camera.rotation.x = 1.16;
camera.rotation.y = -0.12;
camera.rotation.z = 0.27;
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
let cloudMaterial = new THREE.MeshLambertMaterial({
map: loader.load("https://dl.dropboxusercontent.com/s/4wvy8q8eyws4kpf/smoke-1.png?dl=1"),
transparent: true,
depthWrite: false,
side: THREE.DoubleSide
});
for(let i=0; i < 50; i++) {
let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
cloud.position.set(
Math.random() * 800 - 400,
500,
Math.random() * 500 - 500
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random() * 2 * Math.PI;
cloud.material.opacity = 0.55;
cloudParticles.push(cloud);
this.add(cloud);
}
}
Поворот камеры (camera.rotation.x и тому подобное) не будет работать в дополненной реальности, это нужно лишь для просмотра получившегося тумана.
Так же, вы можете изменять само расположение частиц, изменяя параметры в строках 32 - 36.
Теперь, если нажать на кнопку Play находящуюся на верхней панели, мы увидим туман.
Туман будет статичным. Для того, чтобы он начал двигаться как на примере сверху, нужно создать функцию update() и добавить туда вращение каждой частицы (строки 53-59).
let loader = new THREE.TextureLoader();
let cloudParticles = [];
function init() {
camera.position.z = 1;
camera.rotation.x = 1.16;
camera.rotation.y = -0.12;
camera.rotation.z = 0.27;
let ambientLight = new THREE.AmbientLight(0x555555);
this.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
this.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
this.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
this.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
this.add(blueLight);
let cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
let cloudMaterial = new THREE.MeshLambertMaterial({
map: loader.load("https://dl.dropboxusercontent.com/s/4wvy8q8eyws4kpf/smoke-1.png?dl=1"),
transparent: true,
depthWrite: false,
side: THREE.DoubleSide
});
for(let i=0; i < 50; i++) {
let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
cloud.position.set(
Math.random() * 800 - 400,
500,
Math.random() * 500 - 500
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random() * 2 * Math.PI;
cloud.material.opacity = 0.55;
cloudParticles.push(cloud);
this.add(cloud);
}
}
function update() {
cloudParticles.forEach(p => {
p.rotation.z -= 0.001;
});
}