О чем этот пример
Хотите добавить глубину и реализм в 2D-игру? Фильтр Image Light в Phaser позволяет симулировать динамическое освещение на основе карт нормалей и окружения. Вместо статичных спрайтов вы получаете материалы, которые реагируют на свет, создавая эффект объема и отражений. В этой статье мы разберем, как настроить источник света, привязать его к вращающемуся объекту и динамически менять параметры окружения для создания интерактивных визуальных эффектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
background;
backgroundLight;
spider;
spiderLight;
environmentImage;
environmentImageBlur;
panoramaBlurTexture;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/textures/alien-metal.jpg');
this.load.image('bg_n', 'assets/textures/alien-metal-n.jpg');
this.load.image('spider', 'assets/normal-maps/spider.png');
this.load.image('spider_n', 'assets/normal-maps/spider_n.png');
this.load.image('environment', 'assets/panorama-360/KPNO-Drone-360-2-CC2-by-NOIRLab.jpg');
}
create ()
{
this.environmentImage = this.add.image(0, 0, 'environment').setOrigin(0).setVisible(false);
this.environmentImageBlur = this.environmentImage.enableFilters().filters.internal.addPanoramaBlur({
power: 2
});
this.environmentImageBlur.active = false;
this.panoramaBlurTexture = this.textures.addDynamicTexture('environmentBlur', this.environmentImage.width, this.environmentImage.height);
this.panoramaBlurTexture.draw(this.environmentImage).render();
this.background = this.add.image(640, 360, 'bg').enableFilters().setScale(1.5);
this.backgroundLight = this.background.filters.internal.addImageLight({
environmentMap: 'environmentBlur',
normalMap: 'bg_n',
colorFactor: [ 1.5, 1.5, 1.5 ]
});
this.spider = this.add.image(320, 480, 'spider').enableFilters().setRotation(1).setScale(0.5);
this.spiderLight = this.spider.filters.internal.addImageLight({
environmentMap: 'environmentBlur',
normalMap: 'spider_n',
colorFactor: [ 2, 2, 2 ],
modelRotationSource: this.spider
});
this.add.text(640, 48, 'Click to toggle light image smoothing', { fontSize: 24 }).setOrigin(0.5);
this.input.on('pointerdown', () => {
this.environmentImageBlur.active = !this.environmentImageBlur.active;
this.panoramaBlurTexture.draw(this.environmentImage).render();
});
}
update (time, delta)
{
const angle = time / 3000;
this.spider.setPosition(128 * Math.cos(angle) + 300, 128 * Math.sin(angle) + 500)
.setRotation(angle);
}
}
const config = {
type: Phaser.WEBGL,
width: 1280,
height: 720,
backgroundColor: '#2d3440',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка ассетов: карты нормалей и окружения
Для работы фильтра ImageLight необходимы не только обычные текстуры, но и специальные ассеты. Карта нормалей (normal map) — это текстура, где цвет каждого пикселя кодирует направление поверхности (нормаль). Она позволяет рассчитать, как свет должен падать на плоский спрайт, создавая иллюзию объема. Карта окружения (environment map) — это текстура, обычно в формате 360° панорамы, которая используется для расчета отражений и общего освещения.
В методе preload() загружаются все необходимые изображения:
this.load.image('bg', 'assets/textures/alien-metal.jpg');
this.load.image('bg_n', 'assets/textures/alien-metal-n.jpg');
this.load.image('spider', 'assets/normal-maps/spider.png');
this.load.image('spider_n', 'assets/normal-maps/spider_n.png');
this.load.image('environment', 'assets/panorama-360/KPNO-Drone-360-2-CC2-by-NOIRLab.jpg');
Обратите внимание на суффикс _n в названиях файлов — это общепринятое обозначение для карт нормалей.
Создание и обработка карты окружения
Карта окружения используется как источник света для всех объектов на сцене. Чтобы иметь возможность динамически менять её свойства (например, добавлять размытие), мы создаем её динамическую копию.
Сначала изображение окружения добавляется на сцену, но делается невидимым (setVisible(false)). Затем для него активируется фильтр PanoramaBlur, который размывает панораму, симулируя более мягкий, рассеянный свет. Изначально этот фильтр отключен (active = false).
this.environmentImage = this.add.image(0, 0, 'environment').setOrigin(0).setVisible(false);
this.environmentImageBlur = this.environmentImage.enableFilters().filters.internal.addPanoramaBlur({
power: 2
});
this.environmentImageBlur.active = false;
Затем создается динамическая текстура и в неё рендерится обработанное изображение окружения. Эта текстура ('environmentBlur') будет использоваться фильтром ImageLight.
this.panoramaBlurTexture = this.textures.addDynamicTexture('environmentBlur', this.environmentImage.width, this.environmentImage.height);
this.panoramaBlurTexture.draw(this.environmentImage).render();
Настройка освещения для фона и объекта
Фильтр ImageLight добавляется к любому игровому объекту с помощью метода .enableFilters(). Ключевые параметры конфигурации:
* environmentMap: ключ текстуры, которая служит источником света (наша динамическая текстура).
* normalMap: ключ текстуры карты нормалей для объекта.
* colorFactor: массив множителей для RGB-каналов, усиливающих интенсивность света.
* modelRotationSource: опциональный объект, вращение которого (rotation) будет влиять на расчет освещения. Это создает эффект, что свет падает на объект под разными углами при его вращении.
Освещение для фона настраивается просто, так как фон не вращается:
this.backgroundLight = this.background.filters.internal.addImageLight({
environmentMap: 'environmentBlur',
normalMap: 'bg_n',
colorFactor: [ 1.5, 1.5, 1.5 ]
});
Для паука (spider) добавляется привязка к источнику вращения. Это означает, что расчет освещения для этого спрайта будет учитывать его текущий угол поворота в мире, делая отражения корректными при движении.
this.spiderLight = this.spider.filters.internal.addImageLight({
environmentMap: 'environmentBlur',
normalMap: 'spider_n',
colorFactor: [ 2, 2, 2 ],
modelRotationSource: this.spider
});
Что попробовать дальше
Фильтр ImageLight — мощный инструмент для перехода от плоской графики к материалам с объемом в Phaser. Комбинируя его с картами нормалей, динамическими текстурами и другими фильтрами (как PanoramaBlur), можно создавать сложные и производительные визуальные эффекты прямо в 2D-контексте.
**Идеи для экспериментов:**
1. Изменяйте параметр power у PanoramaBlur или попробуйте другие фильтры для обработки карты окружения.
2. Анимируйте свойство colorFactor для создания эффекта пульсирующего или меняющего цвет света.
3. Используйте разные карты окружения (день/ночь, интерьер/экстерьер) и переключайте их во время игры для драматической смены атмосферы.
4. Привяжите modelRotationSource к камере, чтобы освещение на объектах менялось при вращении вида.
