reckfellENGINE

Sky: небо, солнце и карта окружения

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

На этой странице

Sky-шейдер описывает цвет неба по направлению взгляда. Его функция sky() используется для видимого фона, карты окружения для освещения/отражений и включённых промежуточных проходов. Настройка частоты обновления карты окружения не отключает отрисовку фона.

Подключите небо к окружению

  1. Добавьте WorldEnvironment и назначьте ему Environment.
  2. Выберите BackgroundMode = Sky и создайте ресурс Sky в Environment.Sky.
  3. В SkyMaterial создайте ShaderMaterial с Shader типа sky.
  4. Убедитесь, что активная Camera3D смотрит на свободный фон. Непрозрачная геометрия закрывает небо.

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

Шейдер
shader_type sky;
uniform vec3 zenith_color : source_color = vec3(1.0, 0.0, 0.0);
uniform vec3 horizon_color : source_color = vec3(0.0, 1.0, 0.0);
uniform vec3 ground_color : source_color = vec3(0.0, 0.0, 1.0);
void sky() {
    float height = clamp(abs(EYEDIR.y) * 2.0, 0.0, 1.0);
    vec3 pole = EYEDIR.y >= 0.0 ? zenith_color : ground_color;
    COLOR = mix(horizon_color, pole, height);
}

Для создания тех же ресурсов из C# сохраните помощник SkySetup.cs:

C#
using Reckfell;

public static class SkySetup
{
    public static Reckfell.Environment Create(Shader shader)
    {
        var material = new ShaderMaterial { Shader = shader };
        var sky = new Sky
        {
            SkyMaterial = material,
            ProcessMode = Sky.ProcessModeEnum.Quality,
            RadianceSize = Sky.RadianceSizeEnum.Size256,
        };
        return new Reckfell.Environment
        {
            BackgroundMode = Reckfell.Environment.BGMode.Sky,
            Sky = sky,
            TonemapMode = Reckfell.Environment.ToneMapper.Linear,
        };
    }
}

Загрузите шейдер через ResourceLoader.Load<Shader>("asset://DirectionSky.reckfellshader"), вызовите SkySetup.Create(shader) и назначьте результат свойству Environment у WorldEnvironment. Создайте WorldEnvironment внутри того же World3D, который использует камера; в SubViewport с OwnWorld3D нужно собственное окружение. Linear здесь выбран для проверки цвета, а не как универсальная настройка художественного рендера.

Проверка поворачивает камеру вверх/вниз и получает красный/синий фон. Перенос камеры при неизменной ориентации не меняет этот шейдер, поскольку он использует EYEDIR, но не POSITION. Параметры меняются у ShaderMaterial: material.SetShaderParameter("zenith_color", Colors.Blue). Передача default(Variant) возвращает начальное значение uniform.

Разделяйте фон и карту освещения

AT_CUBEMAP_PASS обозначает расчёт radiance-карты окружения. В основном фоновом проходе он false. Можно упростить освещение относительно видимого фона, но тогда отражения и фон намеренно различаются. В проверке одна ветка пишет синий в карту окружения, другая — красный на экран; чтение готовой панорамы подтверждает это различие.

Статическое дорогое вычисление можно перенести в ветку карты и читать её результат при отрисовке фона. Полный минимальный пример:

Шейдер
shader_type sky;
void sky() {
    if (AT_CUBEMAP_PASS) {
        COLOR = vec3(0.0, 0.0, 1.0);
    } else {
        COLOR = textureLod(RADIANCE, EYEDIR, 0.0).rgb;
    }
}

Читайте RADIANCE только вне расчёта самой карты: нельзя использовать незавершённый результат как собственный источник. textureLod с уровнем 0 явно выбирает базовую детализацию. Для панорамы из файла используйте отдельный sampler2D и SKY_COORDS либо PanoramaSkyMaterial; RADIANCE — уже обработанная карта окружения, а не исходный файл изображения.

Кэширование не бесплатное: фон всё равно выполняет выборку каждый кадр. Детализацию ограничивают разрешение карты и фильтрация; мелкие облака или звёзды могут потеряться. Пример доказывает работоспособность пути, а не ускорение любого эффекта.

Выберите способ обновления

Sky.ProcessModeНазначение
AutomaticРендерер выбирает режим по зависимостям шейдера и настройкам. Это не обещание постоянного Realtime.
QualityКачественное обновление карты при необходимости, рассчитанное на статичное или редко меняющееся небо.
IncrementalРазносит работу фильтрации карты по кадрам; обновление отражений может завершаться позже изменения фона.
RealtimeПуть для частых изменений, с ограничениями детализации и качества фильтрации.

В текущем RD-рендерере Realtime использует размер 256. Сочетание с другим RadianceSize вызывает предупреждение и внутреннее приведение. RadianceSize — enum, а не произвольное число пикселей. Ресурс хранит запрошенное значение, поэтому его getter не служит подтверждением фактического внутреннего размера после приведения. В проверке Realtime используется с Size256, а Quality — также с Size64.

Карта помечается для обновления при изменении материала/параметров, используемого времени, позиции камеры при наличии POSITION, используемых направленных источников и некоторых параметров тумана. При активных промежуточных проходах изменение разрешения требует обновить их буферы. Удалите ненужные зависимости: даже использование TIME в ветке, предназначенной только для фона, учитывается анализом шейдера. Automatic в текущем RD выбирает Realtime для TIME/POSITION при поддерживаемом размере, Incremental для света, рассеяния солнца в тумане или uniform-параметров, иначе Quality; детали политики не следует считать одинаковыми для всех рендереров.

TIME — время рендерера с учётом Engine.TimeScale и периодом rendering/limits/time/time_rollover_secs, по умолчанию 3600 секунд. Пауза дерева его сама по себе не останавливает. Для управляемой анимации передавайте собственное время и обновляйте его только при нужном изменении.

Половинный и четвертной проходы

use_half_res_pass создаёт проход с половиной ширины и высоты, use_quarter_res_pass — с четвертью каждой стороны. Это примерно 1/4 и 1/16 числа пикселей соответствующего полного прохода. Дополнительные проходы всё равно имеют стоимость; не включайте их без вычисления, которое можно перенести на низкое разрешение.

Следующий диагностический шейдер записывает отдельные значения в оба прохода и читает их в полном. ALPHA половинного прохода попадает в красный канал итогового цвета, зелёный и синий подтверждают чтение обеих текстур:

Шейдер
shader_type sky;
render_mode use_half_res_pass, use_quarter_res_pass;
void sky() {
    if (AT_QUARTER_RES_PASS) {
        COLOR = vec3(0.0, 0.0, 1.0);
        ALPHA = 0.25;
    } else if (AT_HALF_RES_PASS) {
        COLOR = vec3(0.0, 1.0, 0.0);
        ALPHA = 0.5;
    } else {
        COLOR = vec3(HALF_RES_COLOR.a, HALF_RES_COLOR.g, QUARTER_RES_COLOR.b);
    }
}

Для облаков вместо диагностических цветов вычисляйте цвет и покрытие на низком разрешении, затем самостоятельно смешивайте их с небом через mix. Чтение HALF_RES_COLOR или QUARTER_RES_COLOR не включает автоматическое смешивание. Их фильтрация сглаживает выборку, но не восстанавливает потерянные детали. AT_CUBEMAP_PASS может одновременно быть true с флагом промежуточного прохода: проверяйте флаги в нужном порядке.

ALPHA используется как данные промежуточного прохода. В основном небе ALPHA=0 не показывает прозрачный фон. Для экспорта с прозрачностью настройте отдельный способ композиции viewport; не рассчитывайте получить её выходом sky().

Направленный свет

Встроены четыре слота LIGHT0…LIGHT3. Проверяйте LIGHTX_ENABLED перед чтением остальных полей. В них попадают подходящие DirectionalLight3D, а не PointLight3D; номер слота не является стабильным ID источника. LightOnly исключает источник из неба, SkyOnly оставляет его для неба.

Полный пример формирует световое пятно по направлению источника. Это не физическая атмосфера и не диск с точным угловым диаметром:

Шейдер
shader_type sky;
void sky() {
    COLOR = vec3(0.0);
    if (LIGHT0_ENABLED) {
        float alignment = max(dot(EYEDIR, LIGHT0_DIRECTION), 0.0);
        COLOR = LIGHT0_COLOR * LIGHT0_ENERGY * pow(alignment, 64.0);
    }
}

В проверенном RD-пути LIGHTX_DIRECTION направлен к источнику вдоль мировой +Z его преобразования. Поэтому dot(EYEDIR, LIGHTX_DIRECTION) выделяет область взгляда на источник; не инвертируйте знак по названию «направление света». Поворот DirectionalLight3D на π вокруг Y делает пятно видимым для камеры, смотрящей вдоль −Z. LIGHTX_COLOR приходит в линейном пространстве, ENERGY учитывает настройки энергии и применимые физические единицы/экспозицию. LIGHTX_SIZE — угловой диаметр в радианах, не радиус: для диска нужен косинус половины диаметра.

Режимы и встроенные значения

РежимДействие
use_half_res_passВключает проход половинного разрешения.
use_quarter_res_passВключает проход четвертного разрешения.
disable_fogОтключает влияние тумана, включая пользовательский FOG в проверенном RD-пути.
use_debandingДобавляет шум для уменьшения полос на плавных градиентах; это не дополнительная детализация.
Тип и имяЗначение
in float TIMEВремя рендерера; влияние на обновления описано выше.
in float PI / TAU / EМатематические константы.
in vec3 POSITIONМировая позиция камеры; не положение пикселя неба.
samplerCube RADIANCEВыборка готовой карты окружения по направлению вне её собственного прохода.
in bool AT_CUBEMAP_PASSРасчёт карты окружения, включая её промежуточные проходы.
in bool AT_HALF_RES_PASS / AT_QUARTER_RES_PASSТекущий проход половинного / четвертного разрешения.
in bool LIGHTX_ENABLEDДоступность слота X от 0 до 3.
in vec3 LIGHTX_DIRECTION / LIGHTX_COLORНаправление к источнику / линейный цвет.
in float LIGHTX_ENERGY / LIGHTX_SIZEЭнергия / угловой диаметр в радианах.
in vec3 EYEDIRНормализованное направление текущего луча.
in vec2 SCREEN_UVКоординаты текущего прохода; не UV сферической панорамы.
in vec4 FRAGCOORDКоординаты фрагмента текущего целевого буфера.
in vec2 SKY_COORDSСферические UV для панорамной текстуры.
in vec4 HALF_RES_COLOR / QUARTER_RES_COLORВыборки соответствующих включённых проходов; цвет и записанная ALPHA.
out vec3 COLORВыходной линейный RGB; затем применяется экспозиция/тональная обработка.
out float ALPHAДанные прозрачности промежуточного прохода; не прозрачность основного фона.
out vec4 FOGПользовательский цвет тумана в RGB и вес смешивания в A.

in — только чтение, out — записываемый результат, sampler — источник выборки. Флаги прохода, POSITION, RADIANCE, LIGHTX и TIME доступны глобально; EYEDIR, SCREEN_UV, SKY_COORDS, FRAGCOORD и выходы относятся к sky(). FOG смешивается с результатом: RGB задаёт цвет, A — вес; это не плотность FogVolume. disable_fog в текущем RD отключает и этот вклад.

Диагностика

СимптомЧто проверить
Небо чёрноеBackgroundMode, Environment.Sky, SkyMaterial, shader_type sky, активную камеру и общий World3D.
Фон меняется, отражения запаздываютProcessMode и завершение обновления/фильтрации radiance-карты.
Небо слишком яркоеЗначения HDR в шейдере, энергию окружения, экспозицию камеры и тональную обработку.
ALPHA=0 не скрывает небоОсновной проход не смешивается по ALPHA; настройте композицию отдельно.
Неверный цвет или мелкие детали после кэшированияРазличие веток фона/карты, разрешение, LOD и фильтрацию RADIANCE.
Световое пятно с другой стороныЗнак LIGHTX_DIRECTION, поворот источника и выбранный слот.
Солнце не появляетсяLIGHTX_ENABLED, DirectionalLight3D.SkyMode, видимость и предел четырёх источников.
Полосы градиентаДиапазон и тональную обработку; при необходимости use_debanding.
Предупреждение о размере RealtimeИспользуйте Size256 в текущем RD или выберите другой режим обновления.

Проверены фактические пиксели Windows Forward+/Vulkan: направления, uniform, фон/radiance, чтение карты, промежуточные проходы, alpha, FOG и слоты направленного света. Настройки Quality/Incremental/Realtime проверены на статическом результате; это не замер производительности или задержки фильтрации. Политика обновления, прочие встроенные значения, вращение/FOV окружения и ограничения других конфигураций сверены по исходникам. Новые снимки редактора, художественная атмосфера, физическая корректность, HDR/XR и все платформы/экспорты здесь не проверялись.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.