# Создание частиц в Pro Editor

В данной статье я покажу как создать подобную сцену в продвинутом редакторе.

{% embed url="<https://codepen.io/shikitos/pen/bGrzJoJ>" %}

Для создания анимации — нужно зайти в сам **редактор** и создать новый проект (чтобы редактор был пустой).

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2FwaDyARcA6FwSVZ0MqdBW%2FParticles_1.jpg?alt=media\&token=a8e3b2f1-42d3-4c5a-9812-1bd97362e805)

Далее, нужно создать скрипт, привязанный к сцене.

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2FnKDqWDnynD36FU1YG4P5%2FParticles_2.jpg?alt=media\&token=452e1332-c283-4aa8-8fa7-79fea1a542dc)

Для перехода в режим редактирования, нужно нажать на кнопку **Edit**.

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2FBTtNC3oIIOElr0mtrx2f%2FParticles_3.jpg?alt=media\&token=e86aa0a1-2c57-4c4e-95b2-f3e6b1d57236)

В открывшемся текстовом редакторе будет писаться весь код сцены.

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2FFMpH8siZBcWexYZjwTBE%2FParticles_4.jpg?alt=media\&token=9a82d8b6-bbcd-42f7-aec9-285e8b502d6c)

Первым делом нужно создать функцию `init()`, эта функция выполняется при запуске сцены.

{% code lineNumbers="true" %}

```javascript
function init() {

}
```

{% endcode %}

Внутрь этой функции мы поместим освещение сцены. Я добавлю пять источников света: заполняющий, направленный и три точечных *(строки 3-16)*.

{% code lineNumbers="true" %}

```javascript
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);
	
}
```

{% endcode %}

Следующим шагом нужно добавить непосредственно сам кусочек тумана. Для этого я буду использовать следующее изображение, загруженное на Dropbox.

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2FiGbQVh9yGWaAldmZOsGh%2Fimage.png?alt=media\&token=72115270-2356-44cd-8f29-c7feb859ffd1)

Теперь, нужно создать плоскость и использовать данное изображение в качестве текстуры.&#x20;

Для этого  нужно воспользоваться специальным THREE.js классом, называемым загрузчик (**loader**).

{% hint style="warning" %}
Загрузка различных объектов с помощью загрузчика содержит в себе некоторые ограничения.&#x20;

О том, как правильно загружать объекты, читайте в [zagruzka-obektov-s-pomoshyu-klassa-loader](https://mywebar.gitbook.io/mywebar-knowledge-base/yazyk-ru-1/pro-editor/tekushie-ogranicheniya/zagruzka-obektov-s-pomoshyu-klassa-loader "mention")
{% endhint %}

Добавим загрузчик до функции `init()` *(строка 1)*.

{% code lineNumbers="true" %}

```javascript
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);
	
}
```

{% endcode %}

Теперь нужно создать геометрию и материал для будущей частицы тумана *(строки 20-26)*. Геометрией является плоскость `PlaneBufferGeometry` размером 500\*500. Материал, это `MeshLamberMaterial`, куда, в качестве параметров переданы: **map** — текстура тумана, **transparent** — прозрачность (работает только для **.png**), **depthWrite** — проверка глубины (убрано для предотвращения артефактов перекрытия), **side** — материал с двух сторон у плоскости.

{% code lineNumbers="true" %}

```javascript
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
	});
	
}
```

{% endcode %}

Так как мы создаем огромную туманность, нам нужно большое количество подобных плоскостей с кусочками тумана. Поэтому, далее, нужно добавить цикл, который будет создавать массив частиц *(строки 28- 44)*. Так же, до объявления функции, нужно создать массив, куда будут добавляться все частицы тумана *(строка 2)*.

{% code lineNumbers="true" %}

```javascript
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);
		
	}
	
}
```

{% endcode %}

Что мы сделали? Мы создаем мэш *(строка 30)*, потом мы задаем рандомную позицию для каждой частицы, чтобы туман был не в одной маленькой точке *(строки 31-35)*, после, немного поворачиваем плоскости *(строки 36-38)* и добавляем непрозрачность *(строка 39)*. После всего, мы добавляем созданную частицу как в массив, так и на сцену.&#x20;

Данный цикл повторяется 50 раз, благодаря чему создается 50 частиц.

Сделанный скрипт создает туман над сценой, поэтому нужно повернуть камеру в его сторону *(строки 6-9)*.&#x20;

{% code lineNumbers="true" %}

```javascript
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);
		
	}
	
}
```

{% endcode %}

{% hint style="info" %}
Поворот камеры (`camera.rotation.x` и тому подобное) не будет работать в дополненной реальности, это нужно лишь для просмотра получившегося тумана.&#x20;

Так же, вы можете изменять само расположение частиц, изменяя параметры в строках 32 - 36.
{% endhint %}

Теперь, если нажать на кнопку **Play** находящуюся на верхней панели, мы увидим туман.

![](https://16483826-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQlfxB1bBQeYgEsEfSMqq%2Fuploads%2Fj3cLmT86g2oCWJWayvjl%2Fimage.png?alt=media\&token=bce0662d-6f5f-419f-b2a9-f1f0ac71490d)

Туман будет статичным. Для того, чтобы он начал двигаться как на примере сверху, нужно создать функцию `update()` и добавить туда вращение каждой частицы *(строки 53-59)*.

{% code lineNumbers="true" %}

```javascript
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; 
	}); 
	
}
```

{% endcode %}
