Статьи

WebGL With Three.js: текстуры и частицы

С момента своего появления 3D-графика в браузере стала популярной темой. Но если бы вы создавали свои приложения с использованием простого старого WebGL, это заняло бы очень много времени. Но теперь у нас есть несколько довольно полезных библиотек, которыми мы можем воспользоваться, например Three.js . Итак, в этой серии я покажу вам, как создавать потрясающие трехмерные эффекты для браузера.

Я ожидаю, что у вас будет общее представление о трехмерном пространстве, прежде чем вы начнете читать этот учебник, так как я не буду объяснять такие вещи, как координаты, векторы и т. Д.


Мы начнем с кода из предыдущей части этой серии. Также возьмите предоставленные мною ресурсы и поместите их в ту же папку, что и ваше приложение. Теперь, поскольку здесь мы будем использовать изображения, вам придется поместить ваше приложение на некоторый статический сервер (может быть локальный), потому что, если вы не запустите браузер с включенным доступом к файлам из файлов (например, с помощью --allow-file-access-from-files флаг --allow-file-access-from-files в Chrome) CORS не позволит вам загрузить их из файла. Это все, что вам нужно сделать, прежде чем продолжить.


Если вам когда-нибудь стало так скучно, что вы пошли на создание чего-либо с использованием чистого OpenGL, вы, вероятно, помните, как тяжело загрузить текстуру. К счастью, Three.js поставляется с хорошей функцией, которая будет загружать и настраивать текстуру для нас. Добавьте эту строку перед определением материала нашего куба:

1
var cubeTexture = THREE.ImageUtils.loadTexture(‘./box.png’);

Это действительно все, что вам нужно сделать, чтобы загрузить текстуру.

В реальном приложении вам нужно будет предварительно загрузить текстуру, как любое обычное изображение, и показать пользователям какую-нибудь необычную полосу загрузки, чтобы сообщить им, что вы загружаете (Three.js будет использовать кэшированное изображение).


Теперь мы применим текстуру к нашему кубу. Это также легко, вам просто нужно заменить определение цвета в материале куба так:

1
var cubeMaterial = new THREE.MeshLambertMaterial({ map: cubeTexture });

Атрибут map устанавливает текстуру. Теперь вы можете открыть браузер и увидеть вращающийся текстурированный куб:

textured_cube

Вы также можете раскрасить текстуру, просто добавьте определение color в настройках материала, например:

1
var cubeMaterial = new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0x28c0ec });

И теперь куб становится синим:

textured_colorized_cube

Таким образом, вы можете иметь несколько разных объектов с одинаковой текстурой, если меняется только цвет.


Вы можете установить различные материалы для каждого лица куба. Чтобы достичь этого, вы должны изменить определение всего материала. Сначала определите массив materials . Каждый элемент в массиве будет соответствовать материалу одного лица. Они идут в следующем порядке: справа, слева, сверху, снизу, спереди и сзади:

1
2
3
4
5
6
7
var materials = [];
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0xff0000 }));
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0xffff00 }));
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0xffffff }));
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0x00ffff }));
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0x0000ff }));
materials.push(new THREE.MeshLambertMaterial({ map: cubeTexture, color: 0xff00ff }));

Как вы видите, у каждого лица есть свой материал, поэтому вы можете устанавливать различные текстуры, цвета и другие атрибуты для каждого. Затем измените тип материала куба на THREE.MeshFaceMaterial :

1
var cubeMaterial = new THREE.MeshFaceMaterial(materials);

Вам нужно только передать массив materials в качестве параметра. В браузере вы должны увидеть, что каждая сторона куба имеет разный цвет:

each_side_different

Допустим, вы хотите создать эффект вращающихся снежинок в своем приложении. Если вы будете рендерить каждую снежинку в виде меша, вы получите очень низкий fps. Вот где частицы вступают в игру. Они намного менее сложны, и рисование их как целой системы частиц делает их действительно эффективными.

Начнем с создания геометрии для наших частиц:

1
var particles = new THREE.Geometry;

THREE.Geometry — это объект базовой геометрии, без какой-либо формы. Теперь мы должны определить положение каждой частицы в системе. Пусть это будет совершенно случайно:

1
2
3
4
for (var p = 0; p < 2000; p++) {
    var particle = new THREE.Vector3(Math.random() * 500 — 250, Math.random() * 500 — 250, Math.random() * 500 — 250);
    particles.vertices.push(particle);
}

Этот цикл создаст 2000 случайно расположенных частиц и поместит их все в геометрию. Далее вы должны определить материал частиц:

1
var particleMaterial = new THREE.ParticleBasicMaterial({ color: 0xeeeeee, size: 2 });

Обратите внимание, что мы используем THREE.ParticleBasicMaterial , который предназначен только для частиц. В опциях мы определяем только цвет и размер каждой частицы. Наконец, вы можете создать систему частиц и добавить ее в сцену:

1
2
3
var particleSystem = new THREE.ParticleSystem(particles, particleMaterial);
 
scene.add(particleSystem);

Теперь, чтобы сделать сцену лучше, давайте повернем частицы в направлении, противоположном тому, в котором вращается куб (измените функцию render чтобы она выглядела так):

1
2
3
4
5
6
7
8
9
function render() {
    requestAnimationFrame(render);
     
    var delta = clock.getDelta();
    cube.rotation.y -= delta;
    particleSystem.rotation.y += delta;
     
    renderer.render(scene, camera);
}

Мы переместили clock.getDelta в переменную, потому что, если вы будете использовать это так:

1
2
cube.rotation.y -= clock.getDelta();
particleSystem.rotation.y += clock.getDelta();

Система частиц не будет вращаться, потому что второй вызов вернет число, близкое к нулю (помните, что он получает время от последнего вызова).

Теперь откройте браузер, и вы увидите вращающиеся куб и частицы:

cube_with_particles

Давайте объединим обе вещи, которые вы изучили в этом уроке, и превратим эти уродливые белые квадраты в настоящие снежинки. Сначала загрузите текстуру снежинки:

1
var particleTexture = THREE.ImageUtils.loadTexture(‘./snowflake.png’);

Теперь измените материал частиц, чтобы использовать текстуру. Также включите прозрачность и увеличьте размер частиц, чтобы мы могли видеть форму:

1
var particleMaterial = new THREE.ParticleBasicMaterial({ map: particleTexture, transparent: true, size: 5 });

Если вы откроете браузер, то увидите, что вокруг куба текут красивые снежинки:

particles_snowflakes

Эффект дыма довольно легко достичь, и он выглядит красиво. Начните с создания геометрии, как со снежинками:

1
2
3
4
5
var smokeParticles = new THREE.Geometry;
for (var i = 0; i < 300; i++) {
    var particle = new THREE.Vector3(Math.random() * 32 — 16, Math.random() * 230, Math.random() * 32 — 16);
    smokeParticles.vertices.push(particle);
}

Единственная разница здесь в том, что мы выбираем позицию из прямоугольной призмы с размерами 32x32x230. Теперь давайте загрузим текстуру и определим материал:

1
2
var smokeTexture = THREE.ImageUtils.loadTexture(‘./smoke.png’);
var smokeMaterial = new THREE.ParticleBasicMaterial({ map: smokeTexture, transparent: true, blending: THREE.AdditiveBlending, size: 50, color: 0x111111 });

В определении материала есть вариант blending . Он сообщает визуализатору, как он должен отображать один объект на другом. С THREE.AdditiveBlending перекрывающиеся значения цвета будут добавляться друг к другу, что приведет к более яркому дыму в областях с более высокой плотностью частиц. Мы также установили цвет почти черный, чтобы дым выглядел более естественно.

Наконец, создайте систему частиц, переместите ее немного влево и добавьте к сцене:

1
2
3
4
5
var smoke = new THREE.ParticleSystem(smokeParticles, smokeMaterial);
smoke.sortParticles = true;
smoke.position.x = -150;
 
scene.add(smoke);

Вы также должны установить smoke.sortParticles в true. Когда оно ложно, фон спрайта может быть нарисован черным. Если вы откроете браузер, вы увидите неподвижный столб дыма рядом с кубом:

smoke_still

Чтобы оживить дым, нам нужно пройти через все частицы и немного их поднять. Добавьте этот код в функцию render :

01
02
03
04
05
06
07
08
09
10
11
12
var particleCount = smokeParticles.vertices.length;
while (particleCount—) {
    var particle = smokeParticles.vertices[particleCount];
    particle.y += delta * 50;
     
    if (particle.y >= 230) {
        particle.y = Math.random() * 16;
        particle.x = Math.random() * 32 — 16;
        particle.z = Math.random() * 32 — 16;
    }
}
smokeParticles.__dirtyVertices = true;

В цикле мы добавляем delta * 50 к позиции y частицы. Затем мы проверяем, является ли частица выше 230, если это так, мы случайным образом выбираем ее новую позицию где-то в нижней части столба дыма. Наконец, самое важное: установить для флага __dirtyVertices геометрии __dirtyVertices true.

Чтобы повысить производительность, Three.js кэширует объекты, чтобы избежать повторного построения всех вызовов WebGL в каждом кадре, поэтому, если мы что-то изменим в геометрии объекта, мы должны сообщить рендереру, что он изменился. По __dirtyVertices флаг __dirtyVertices просто достигнет элемента.

Если вы откроете браузер сейчас, вы должны увидеть плавно анимированный дым рядом с кубом.


В этом уроке вы узнали, как использовать текстуры и частицы. Как и раньше, не бойтесь немного поэкспериментировать с вашим приложением. Если у вас есть проблемы, взгляните на документацию . В следующей статье я научу вас, как загружать модели и анимировать их.