Локальные отражения: настройка ReflectionProbe
Размеры, точка захвата, маски, обновление и диагностика чёрного отражения.
ReflectionProbe хранит локальный захват окружения для материалов, использующих отражённый свет. Это приближение с одной точкой захвата, а не точное зеркальное изображение с позиции каждого пикселя. Область влияния пробы и объекты, попадающие в её захват, настраиваются отдельно.
Для изолированной проверки отражения без ambient используйте материал с DisableSpecularOcclusion = true. Причина и границы этой настройки описаны ниже.
Разместите пробу в помещении
- Добавьте ReflectionProbe как Entity в нужный 3D-мир. Держите её положение внутри помещения и вне сплошной геометрии.
- Задайте Size полными размерами области по X/Y/Z. Например, (8,4,6) означает ширину 8, высоту 4 и глубину 6, а не полуразмеры. Не используйте масштаб Entity вместо Size.
- Задайте Origin Offset — смещение точки захвата относительно центра. Оно не перемещает область влияния. Для корректного положительного Size движок удерживает его внутри границ с отступом 0.01; уменьшение Size может изменить сохранённый OriginOffset.
- Для прямоугольного помещения попробуйте Box Projection. Коррекция направления помогает согласовать отражение с коробкой, но не восстанавливает настоящую геометрию комнаты и не устраняет все ошибки параллакса.
- На время диагностики возьмите непрозрачный материал с небольшим Roughness и заметным отражением. Материал с unshaded не подходит для проверки освещения от пробы.
Не путайте две маски
| Настройка | Назначение |
|---|---|
| CullMask | Какие слои VisualInstance3D захватываются внутренними камерами |
| ReflectionMask | Какие слои геометрии получают результат этой пробы |
| Camera3D.CullMask | Что видит основная камера; это отдельная настройка |
Маски — биты, а не номера слоёв: 1u выбирает первый слой, 2u — второй, 3u — оба. Скрыть объект из отражения и запретить ему получать отражение — разные действия. Для исключения самого отражателя из захвата настройте CullMask; не убирайте его слой из ReflectionMask, если он должен показывать результат.
Готовые настройки из C#
Этот метод создаёт настройки интерьерной пробы: без добавочного ambient-вклада, с коррекцией коробки и режимом Once. Размер проверяется до передачи движку. Сам конструктор не подтверждает завершение захвата GPU.
using System;
using Reckfell;
public static class ReflectionRoom
{
public static StandardMaterial3D ReflectiveMaterial(Color color)
{
return new StandardMaterial3D
{
AlbedoColor = color,
Metallic = 1.0f,
Roughness = 0.15f,
DisableSpecularOcclusion = true,
};
}
public static ReflectionProbe Create(Vector3 size, uint captureLayers, uint receiverLayers)
{
if (!float.IsFinite(size.X) || !float.IsFinite(size.Y) || !float.IsFinite(size.Z) ||
size.X < 0.02f || size.Y < 0.02f || size.Z < 0.02f)
throw new ArgumentOutOfRangeException(nameof(size), "Use finite positive full dimensions of at least 0.02 units.");
return new ReflectionProbe
{
Size = size,
BoxProjection = true,
Interior = true,
AmbientMode = ReflectionProbe.AmbientModeEnum.Disabled,
UpdateMode = ReflectionProbe.UpdateModeEnum.Once,
CullMask = captureLayers,
ReflectionMask = receiverLayers,
MaxDistance = 0,
};
}
}Вызовите ReflectionRoom.Create(new Vector3(8, 4, 6), 2u, 1u) и добавьте возвращённую Entity через AddChild в нужный 3D-мир. Затем разместите её в комнате. Это конфигурационный пример: успешная проверка его полей не заменяет проверку готового отражения. Не освобождайте внутренние RID, принадлежащие пробе.
Что меняют параметры
| Параметр | Смысл |
|---|---|
| UpdateMode.Once | Захват сохраняется до необходимости обновления; это не автоматическое отражение каждого изменения движущихся объектов |
| UpdateMode.Always | Регулярное повторение захвата; требует измерения стоимости рендеринга на целевой платформе |
| Intensity | Сила вклада пробы, а не мощность источников света в захватываемой комнате |
| BlendDistance | Ширина перехода у границы области; не дальность камеры захвата |
| MaxDistance | Запрошенная дальность камер; обёртка ограничивает её диапазоном 0…262144 |
| Interior | Убирает окружение неба из интерьерного захвата; не заменяет освещение помещения |
| EnableShadows | Включает вычисление теней при захвате; увеличивает работу, особенно при частом обновлении |
| MeshLodThreshold | Управляет выбором имеющихся LOD в захвате; не создаёт LOD автоматически |
MaxDistance по умолчанию равен 0. Фактическая дальняя плоскость дополнительно учитывает Size и OriginOffset, поэтому 0 не означает отключение пробы. Этот параметр не задаёт расстояние видимости пробы от основной камеры.
AmbientMode.Disabled не добавляет диффузный ambient-вклад пробы. Environment использует информацию окружения захвата; Color — AmbientColor с множителем AmbientColorEnergy. Ambient-вклад не является полноценным расчётом многократных отражений света. Для интерьера не компенсируйте отсутствие света произвольным увеличением яркости пробы.
Чёрное отражение при нулевом ambient
В текущих Forward+ и Mobile стандартное specular occlusion без bent-normal карты оценивает видимость отражения по яркости ambient. Если ambient окружения и ambient пробы выключены, множитель получается нулевым: даже корректный захват или явно заданный RADIANCE может исчезнуть. Это не проверка заполненности захвата.
Для изолированного теста назначьте получателю ReflectionRoom.ReflectiveMaterial(Colors.White). Метод включает DisableSpecularOcclusion на конкретном материале. Эквивалент для ShaderMaterial — режим specular_occlusion_disabled. Контрольное переключение выключено → включено → выключено воспроизводимо даёт чёрное → видимое отражение → чёрное отражение.
В рабочей сцене сначала настройте содержательный ambient и освещение. Отключение этой коррекции убирает приблизительное затенение зеркального вклада; оно не создаёт свет, не отключает прямые тени и не отменяет diffuse AO. Не используйте глобальное выключение как универсальную настройку качества. Глобальный параметр rendering/reflections/specular_occlusion/enabled и настройка материала — отдельные уровни.
Как принять результат
Проверяйте по одной переменной. Отражаемый объект должен находиться в области влияния и иметь слой из ReflectionMask; захватываемая геометрия — слой из CullMask. Сначала подтвердите само отражение контрастного объекта. Затем отдельно проверьте перемещение пробы, обновление движущегося объекта, переход у границы и несколько перекрывающихся проб.
Если отражение чёрное, проверьте освещение захватываемой геометрии, положение OriginOffset, обе маски, материал-получатель, наличие активного 3D-мира и завершение обновления. Если отражается старая обстановка, проверьте UpdateMode. Если искажается положение стены, проверьте Size, OriginOffset и BoxProjection. Не меняйте одновременно яркость, экспозицию, маски и режим обновления: так нельзя определить причину.
Проверки подтвердили постоянный цветовой ambient, его отключение через ReflectionMask и диффузный вклад захваченного неба. Отдельные контрольные шейдеры подтвердили причину исчезновения зеркального вклада: отключение specular occlusion на материале восстанавливает его при нулевом ambient.
Увеличение области не повышает детализацию захвата. Разрешение и число ячеек атласа задаются отдельно: rendering/reflections/reflection_atlas/reflection_size и rendering/reflections/reflection_atlas/reflection_count. Проверяйте бюджет выбранного рендерера; универсальное обещание «четыре пробы везде» здесь неприменимо. Произвольное увеличение числа проб, разрешения и частоты обновления не является бесплатным улучшением качества.
Известное ограничение освобождения ресурсов
В установленном runtime тест перехода Once → Always с последующим удалением тестового мира выдаёт предупреждение об оставшихся 14 Texture RID. Проверки изображения проходят, но освобождение GPU-текстур этим сценарием не принято. Учитывайте это отдельно при многократном создании и удалении миров; не считайте успешное отражение доказательством отсутствия роста памяти.
На Windows Forward+/Vulkan проверены полный C#-метод, настройки и ограничения размеров, отражение геометрии вне видимости основной камеры, сохранение Once при изменении материала, обновление после перемещения пробы, обновление Always, Intensity=0 и обе маски. Причина чёрного зеркального вклада дополнительно проверена в Forward+ и Mobile без пробы. Малые тестовые кадры не являются демонстрацией качества графики. Интерфейс редактора, качество теней, точность параллакса и ambient, смешивание нескольких проб, производительность и прочие платформы отдельно не приняты.
Связанные материалы: ReflectionProbe API, материалы 3D, глобальное освещение.