Tutorials

Световые ореолы

Узнайте больше, создав форк полного проекта.

Этот простой эффект отлично подходит для добавления атмосферы в вашу сцену. Добавьте свечение к источнику света или эмиссионной текстуре, чтобы создать эффект пыльной или туманной атмосферы или смоделировать эффект просмотра яркого света.

Он работает следующим образом: мы создаем сущность с прикрепленным примитивом плоскости, на котором находится материал светящегося ореола. К сущности мы прикрепляем скрипт, который заставляет плоскость всегда смотреть на камеру (billboarding). Для дополнительного удовольствия мы затушевываем ореол, если он направлен в сторону от камеры, чтобы имитировать направленный свет.

Assets

Текстура

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

blob

Эта текстура будет основой свечения.

Материал

Материал для светового ореола использует текстуру кляксы в слоте эмиссии. Используйте свойство tint для установки цвета вашего ореола. Мы также включили смешивание в слоте прозрачности, и он также использует текстуру кляксы с Color Channel установленным на R.

Blend Type установлен на Additive Alpha. Часть Additive означает, что цвет материала добавляется к цвету фона под ним. Это означает, что ореол светится на фоне. Часть Alpha означает, что она использует значение opacity для установки прозрачности материала.

Сущности

entities

Настройка сущностей для свечения тоже проста. У нас есть родительская сущность для скрипта ореола и дочерняя сущность, к которой прикреплен примитив плоскости. Мы делаем это для упрощения кода, чтобы мы могли использовать entity.lookAt для установки ориентации свечения. Примитив плоскости обращен вверх, поэтому мы создаем дочернюю сущность и применяем к ней вращение, чтобы плоскость была правильно размещена перед камерой.

Код

Код для этого проекта имеет две особенно интересные функции.

Во-первых, мы обновляем сущность ореола, чтобы она смотрела на камеру каждый кадр

// Установить свечение так, чтобы оно всегда было направлено на камеру
this.entity.lookAt(this.camera.getPosition());

Во-вторых, если гало помечено как unidirectional (с атрибутом скрипта, который мы предоставили), то мы изменяем прозрачность так, чтобы гало было невидимым, когда оно направлено в противоположную сторону от камеры. На самом деле мы постепенно изменяем прозрачность так, чтобы она становилась более прозрачной, чем больше она указывает в противоположную сторону от камеры.

// Если включено, однонаправленное означает, что свечение исчезает, когда оно отводится от камеры
if (this.unidirectional) {
    // Получить скалярное произведение направления родителя и направления камеры
    var dot = -1 * tmp.dot(this.camera.forward);
    // Если скалярное произведение меньше 0, свечение направлено от камеры
    if (dot < 0) {
        dot = 0;
    }

    // Переопределить значение прозрачности на экземпляре сетки плоскости, чтобы уменьшить его до нуля, когда свечение отводится от камеры
    meshes[0].setParameter("material_opacity", dot);
} else {
    // Необходимо установить значение по умолчанию из-за этой проблемы на данный момент: https://github.com/playcanvas/engine/issues/453
    meshes[0].setParameter("material_opacity", 1);
}

Мы используем метод setParameter на pc.MeshInstance для установки значения, которое будет использоваться фрагментным шейдером. В настоящее время это является недокументированной функцией в движке (вы не найдете ее по ссылке на документацию для разработчиков). Причина этого заключается в том, что она зависит от точного знания имени униформной переменной в шейдере. Эти значения могут измениться, и этот API может измениться в будущем. Но это довольно полезно, потому что позволяет переопределить одно значение в шейдере только для этого экземпляра сетки. В данном случае это важно, потому что все свечения используют один и тот же материал, но нам потребуется разное значение прозрачности для каждого экземпляра свечения.

Вот полный список:

var Halo = pc.createScript('halo');

Halo.attributes.add('camera', {type: 'entity'});
Halo.attributes.add('unidirectional', {type: 'boolean', default: false});

Halo.tmp = new pc.Vec3();

// инициализация кода, вызываемая один раз для каждой сущности
Halo.prototype.initialize = function() {
    // Получить сущность с моделью плоскости на ней
    this.plane = this.entity.children[0];

    // Получить родительскую сущность, которая используется для указания направления
    this.parent = this.entity.parent;
};

// код обновления, вызываемый каждый кадр
Halo.prototype.update = function(dt) {
    var tmp = Halo.tmp;

    // Сохранить вектор, в котором родитель смотрит (обратите внимание, что вперед - это отрицательное z)
    tmp.copy(this.parent.forward).scale(-1);

    var meshes = this.plane.render.meshInstances;

    if (this.camera) {

        // Установить свечение так, чтобы оно всегда было направлено на камеру
        this.entity.lookAt(this.camera.getPosition());

        // Если включено, однонаправленное означает, что свечение исчезает, когда оно отклоняется от камеры
        if (this.unidirectional) {
            // Получить скалярное произведение направления родителя и направления камеры
            var dot = -1 * tmp.dot(this.camera.forward);
            // Если скалярное произведение меньше 0, свечение направлено от камеры
            if (dot < 0) {
                dot = 0;
            }

            // Переопределить значение прозрачности на экземпляре сетки плоскости, чтобы оно исчезало до нуля, когда свечение отклоняется от камеры
            meshes[0].setParameter("material_opacity", dot);
        } else {
            // Необходимо установить значение по умолчанию из-за этой проблемы на данный момент: https://github.com/playcanvas/engine/issues/453
            meshes[0].setParameter("material_opacity", 1);
        }
    }
};

Вот и все. Простой, но красивый эффект для добавления в вашу сцену. Посмотрите проект для получения дополнительной информации.

This site is translated by the community. If you want to get involved visit this page