О чем этот пример
Эффект "прогрева" (warp) шума — мощный инструмент для генерации сложных текстур и ландшафтов. Встроенный в Phaser объект `NoiseSimplex3D` позволяет управлять количеством итераций этого эффекта. В статье на примере кода разберем, как параметр `noiseWarpIterations` превращает простой шум в детализированные, органичные паттерны, которые можно использовать для воды, облаков или каменных поверхностей.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create()
{
const { width, height } = this.scale;
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5
}, width * 1 / 8, height / 2, width / 4, height);
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 2
}, width * 3 / 8, height / 2, width / 4, height);
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 3
}, width * 5 / 8, height / 2, width / 4, height);
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 4
}, width * 7 / 8, height / 2, width / 4, height);
this.add.text(10, 10, '1 warp iteration', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 4 + 10, 10, '2 warp iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width / 2 + 10, 10, '3 warp iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
this.add.text(width * 3 / 4 + 10, 10, '4 warp iterations', { fontSize: 24 }).setStroke('#ff8844', 2).setShadow(2, 2, '#333333', 2, true, false);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1280,
height: 720,
scene: Example
};
const game = new Phaser.Game(config);
Создание базового объекта 3D-шума
В Phaser 3 существует фабричный метод this.add.noisesimplex3d(), который создает и добавляет на сцену объект 3D-шума Перлина (симплекс-шума). Этот метод принимает конфигурационный объект и параметры позиционирования.
this.add.noisesimplex3d(config, x, y, width, height);
В нашем примере для всех объектов задана одинаковая базовая конфигурация: noiseCells определяет «зернистость» шума по осям (X, Y, Z), а noiseWarpAmount — силу искажения.
{
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5
}
Что такое warp-итерации?
Параметр noiseWarpIterations управляет тем, сколько раз базовый шум будет использоваться для искажения самого себя. Это процесс, похожий на наложение фильтра.
- При значении 1 (или его отсутствии) применяется однократное искажение.
- При значении 2 шум искажается, а затем результат снова искажается на основе собственных значений.
- С каждой новой итерацией паттерн становится сложнее, теряет регулярность и приобретает более естественный, «природный» вид.
Ключевой момент: последующие итерации используют уже искаженные координаты, создавая эффект фрактальной сложности.
Сравнение результатов на практике
В примере создается четыре объекта шума с увеличением noiseWarpIterations от 1 до 4. Они размещаются рядом для наглядного сравнения.
// 1 итерация (значение по умолчанию)
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5
}, width * 1 / 8, height / 2, width / 4, height);
// 4 итерации
this.add.noisesimplex3d({
noiseCells: [ 4, 9, 4 ],
noiseWarpAmount: 0.5,
noiseWarpIterations: 4 // Явное указание параметра
}, width * 7 / 8, height / 2, width / 4, height);
Вы увидите, как плавный градиент первого блока превращается в насыщенный, детализированный и хаотичный паттерн в последнем. Добавление текстовых меток помогает визуально закрепить разницу между итерациями.
Настройка и позиционирование
Помимо конфигурации шума, важно правильно задать позицию и размер. Метод this.add.noisesimplex3d() после config объекта принимает стандартные для игровых объектов параметры.
// x, y — координаты центра объекта.
// width, height — его размеры.
this.add.noisesimplex3d(config, x, y, width, height);
В примере координата X для каждого объекта рассчитывается динамически, чтобы равномерно распределить их по ширине экрана:
width * 1 / 8, // Первый объект
width * 3 / 8, // Второй объект
width * 5 / 8, // Третий объект
width * 7 / 8 // Четвертый объект
Все объекты имеют одинаковую высоту (height) и ширину, равную четверти экрана (width / 4).
Что попробовать дальше
Параметр noiseWarpIterations — это ключ к превращению простого шума в сложную, готовую к использованию текстуру. Больше итераций означает больше деталей и менее предсказуемый результат.
**Идеи для экспериментов:**
1. Поиграйте с балансом noiseWarpAmount и noiseWarpIterations. Сильное искажение с малым числом итераций даст резкий эффект, а слабое с большим числом — тонкую структуру.
2. Используйте такие текстуры в качестве карт высот для процедурного ландшафта (noiseWarpIterations: 3-4 отлично подойдет для гор).
3. Анимируйте параметр noiseOffset.z во времени, чтобы создать эффект движущихся облаков или волн, и посмотрите, как итерации warp влияют на анимацию.
