О чем этот пример

При работе с текстурами высокого разрешения, особенно когда они масштабируются в игровом мире, могут возникать неприятные визуальные артефакты: мерцание (aliasing) или размытие. Фильтрация mipmap — это техника, которая помогает сгладить переходы между уровнями детализации текстуры при её сильном уменьшении на экране. В Phaser 3 вы можете глобально управлять типом фильтра mipmap для всех текстур в игре, что напрямую влияет на производительность и качество рендеринга. В этой статье мы разберем, как и зачем это делать, на конкретном примере.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('uv', 'assets/pics/uv-grid-4096-ian-maclachlan.png');
    }

    create ()
    {
        //  4096 x 4096 texture

        this.add.image(0, 0, 'uv').setOrigin(0, 0).setDisplaySize(512, 512);

        this.add.image(512, 0, 'uv').setOrigin(0, 0).setDisplaySize(256, 256);

        this.add.image(768, 0, 'uv').setOrigin(0, 0).setDisplaySize(128, 128);

        this.add.image(896, 0, 'uv').setOrigin(0, 0).setDisplaySize(64, 64);
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    mipmapFilter: 'LINEAR_MIPMAP_LINEAR',
    scene: Example
};

const game = new Phaser.Game(config);

Что такое mipmap и зачем он нужен?

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

Без mipmap рендерер будет пытаться усреднить огромное количество текселей в один пиксель экрана «на лету», что приводит к шуму и мерцанию при движении объекта. С mipmap этот процесс оптимизирован, но возникает вопрос: как именно интерполировать цвета при переходе между уровнями mipmap? Для этого и существуют фильтры mipmap.

Phaser поддерживает несколько режимов, задаваемых через свойство mipmapFilter в конфигурации игры.

Разбор примера: демонстрация текстур разных размеров

В предоставленном примере загружается одна большая текстура (4096x4096) и отображается четыре раза, каждый раз с уменьшенным displaySize. Это наглядно показывает, как текстура сжимается до разных размеров на экране.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('uv', 'assets/pics/uv-grid-4096-ian-maclachlan.png');
}

В методе create мы создаем четыре изображения, выстроенные в ряд. Каждое использует одну и ту же текстуру 'uv', но отображается с разными размерами (512, 256, 128, 64 пикселей).

create ()
{
    this.add.image(0, 0, 'uv').setOrigin(0, 0).setDisplaySize(512, 512);
    this.add.image(512, 0, 'uv').setOrigin(0, 0).setDisplaySize(256, 256);
    this.add.image(768, 0, 'uv').setOrigin(0, 0).setDisplaySize(128, 128);
    this.add.image(896, 0, 'uv').setOrigin(0, 0).setDisplaySize(64, 64);
}

Самое маленькое изображение (64x64) — это яркий пример случая, когда mipmap критически важен. Без него сетка на текстуре выглядела бы как хаотичный шум.

Настройка фильтра в конфигурации игры

Ключевой параметр настройки находится не в коде сцены, а в главном конфиге игры. Он называется mipmapFilter и передается в конструктор Phaser.Game.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    mipmapFilter: 'LINEAR_MIPMAP_LINEAR',
    scene: Example
};

const game = new Phaser.Game(config);

Установка значения 'LINEAR_MIPMAP_LINEAR' говорит WebGL использовать трилинейную фильтрацию. Это самый качественный (и чуть более затратный) режим, который плавно интерполирует пиксели как внутри одного уровня mipmap, так и между соседними уровнями. Другие возможные значения — 'LINEAR_MIPMAP_NEAREST' или null для отключения фильтрации mipmap (но не самих mipmap).

Важно: этот параметр применяется глобально ко всем текстурам, загруженным в игре. Изменить его для отдельной текстуры после запуска игры стандартными средствами Phaser нельзя.

Практические рекомендации: когда и что использовать

Выбор фильтра — это всегда баланс между качеством и производительностью.

* **LINEAR_MIPMAP_LINEAR (трилинейная фильтрация)**: Дает максимально плавный и качественный результат без резких переходов. Рекомендуется для большинства проектов, особенно если в игре есть плавное движение камеры или вращение объектов. Это значение по умолчанию в Phaser. * **LINEAR_MIPMAP_NEAREST (билинейная фильтрация)**: Более производительный вариант. Он дает сглаживание внутри уровня mipmap, но переход между уровнями может быть более заметным (резким). Может подойти для пиксель-арт игр, где резкость предпочтительнее плавности, или для статичных UI-элементов. * **null или отсутствие свойства**: Mipmap-цепочка будет генерироваться, но фильтрация между уровнями отключена. Это может привести к «скачкам» качества при изменении расстояния до объекта. Используйте только если столкнулись с серьезными проблемами производительности и готовы пожертвовать качеством.

Совет: всегда включайте mipmap для текстур, которые могут значительно уменьшаться на экране. Это дешевле, чем позволять GPU каждый раз вычислять фильтрацию в реальном времени.

Что попробовать дальше

Глобальная настройка mipmapFilter — это мощный и простой инструмент для контроля качества рендеринга в Phaser 3. Используя трилинейную фильтрацию, вы обеспечиваете плавное отображение текстур на любом расстоянии. **Идеи для экспериментов:** 1. Создайте сцену с движущейся камерой, которая приближается и удаляется от объекта с большой текстурой. Попробуйте разные значения mipmapFilter и понаблюдайте за краями объекта в движении. 2. Загрузите текстуру с четким контрастным паттерном (например, шахматную доску) и сравните визуальный результат при LINEAR_MIPMAP_LINEAR и LINEAR_MIPMAP_NEAREST на сильно уменьшенном изображении. 3. Проверьте, влияет ли выбор фильтра на FPS в вашем проекте на целевом устройстве (например, на мобильном телефоне).