Освещение 3D: источники, слои и тени
Получить освещённый уровень и реальные тени, проверить область света и отделить визуальные маски от физических.
Запустить освещённый уровень
Нужны C# SDK 1.0.0, net10.0 и уровень .rscene с Entity3D-корнем. Сохраните LightingMaterials.cs из руководства материалов и LightingLab3D.cs ниже. Выполните dotnet build, назначьте LightingLab3D.cs корню и запустите. Внешние ассеты не нужны.
Виден белый куб, синий шар и пол. Key — DirectionalLight3D с включёнными тенями. Point и Spot созданы, но Visible=false: их включают отдельно для сравнения, не складывают все источники сразу.
LightingLab3D.cs
using Reckfell;
public partial class LightingLab3D : Entity3D
{
public MeshInstance3D Floor { get; private set; } = null!;
public MeshInstance3D Cube { get; private set; } = null!;
public MeshInstance3D MetalSphere { get; private set; } = null!;
public DirectionalLight3D Key { get; private set; } = null!;
public OmniLight3D Point { get; private set; } = null!;
public SpotLight3D Spot { get; private set; } = null!;
public Camera3D Camera { get; private set; } = null!;
public WorldEnvironment World { get; private set; } = null!;
public override void _Ready()
{
World = new WorldEnvironment { Environment = LightingMaterials.Environment() };
AddChild(World);
Floor = new MeshInstance3D
{
Mesh = new PlaneMesh { Size = new Vector2(10, 10) },
MaterialOverride = LightingMaterials.Surface(new Color(0.48f, 0.5f, 0.55f))
};
Cube = new MeshInstance3D
{
Mesh = new BoxMesh { Size = new Vector3(1.4f, 2, 1.4f) },
Position = new Vector3(0, 1, 0),
MaterialOverride = LightingMaterials.Surface(Colors.White)
};
MetalSphere = new MeshInstance3D
{
Mesh = new SphereMesh { Radius = 0.8f, Height = 1.6f },
Position = new Vector3(-2.2f, 0.8f, 0),
MaterialOverride = LightingMaterials.Surface(new Color(0.08f, 0.25f, 1), 0.2f, 0.8f)
};
AddChild(Floor); AddChild(Cube); AddChild(MetalSphere);
Key = new DirectionalLight3D
{
RotationDegrees = new Vector3(-50, -25, 0),
LightColor = Colors.White,
LightEnergy = 1,
ShadowEnabled = true
};
Point = new OmniLight3D
{
Position = new Vector3(0, 3, 1),
OmniRange = 8,
LightEnergy = 3,
Visible = false
};
Spot = new SpotLight3D
{
Position = new Vector3(0, 4, 3),
SpotRange = 10,
SpotAngle = 35,
LightEnergy = 4,
Visible = false
};
AddChild(Key); AddChild(Point); AddChild(Spot);
Spot.LookAt(Vector3.Zero);
Camera = new Camera3D { Current = true, Position = new Vector3(5, 4, 7), Fov = 55 };
AddChild(Camera);
Camera.LookAt(new Vector3(0, 0.7f, 0));
}
}Кадр текущей локальной сборки 1.0.0, Compatibility/OpenGL, 512×384. Коллизий и контроллера персонажа в этом примере нет.
Выбрать источник
| Тип | Использование | Что проверить |
|---|---|---|
| DirectionalLight3D | Солнце или общий направленный свет | Поворот, дистанцию покрытия теней; позиция не задаёт точку лампы |
| OmniLight3D | Лампа, освещающая вокруг себя | Положение, OmniRange, затухание |
| SpotLight3D | Фонарь или прожектор | Направление локальной -Z, SpotRange и SpotAngle |
| AreaLight3D | Протяжённый источник | Поддержку конкретного renderer; в Compatibility по исходникам нет его теней и текстурированного area light |
Первые три типа проверены в текущем runtime. AreaLight3D здесь не запускается. У Spot после добавления вызывается LookAt(Vector3.Zero), чтобы направить конус к полу, а не полагаться на случайный поворот.
LightEnergy — множитель, а не универсальная «правильная яркость». На результат влияют материал, расстояние, настройки физических единиц и окружение. Если свет не достаёт до объекта, рост энергии не исправляет слишком маленький range или неверный конус.
Изолировать проблему света
После _Ready доступны Key, Point, Spot и World.Environment. Выключите Key.Visible, поставьте AmbientLightEnergy=0 и включите только Point.Visible. Затем верните Point.Visible=false и включите Spot.Visible. Делайте изменения после создания этих объектов; до _Ready свойства ещё не готовы.
При OmniRange=8 Point осветил геометрию, при 0.2 — перестал до неё доставать. Spot осветил поверхность внутри направленного конуса. AmbientLightSource=Color с энергией 1 также осветил уровень без Key, но не создал направленных теней.
LightCullMask сравнивается с визуальными Layers геометрии. Смена маски источника с 1 на 2 исключила объекты, оставшиеся на первом визуальном слое. CollisionLayer/CollisionMask физики к этому не относятся.
Получить тень
Проверьте цепочку целиком:
- У источника включён ShadowEnabled, а его тип и режим рендеринга поддерживают нужные тени.
- Геометрия находится в области влияния и допустимых визуальных слоях.
- У отбрасывающей геометрии CastShadow не Off.
- Получатель имеет материал, принимающий нужное освещение/тени, и попадает в кадр.
- Дистанция покрытия и качество теневой карты подходят масштабу уровня.
В проверке ShadowEnabled=false убрал тени, а отдельное переключение CastShadow=Off у куба и шара убрало их тени без скрытия мешей. ShadowBias и ShadowNormalBias уменьшают самозатенение, но чрезмерные значения отрывают тень от поверхности и портят тонкие детали. Подбирайте их после масштаба и покрытия, а не вместо них.
Реальная тень источника, AO материала и экранный SSAO — разные эффекты. SSAO добавляет контактное затемнение по видимой глубине, но не заменяет отбрасываемую через весь уровень тень. Запускаемый пример SSAO и glow.
Не спутать свечение с освещением
Emission делает материал ярким. Glow добавляет ореол вокруг ярких пикселей. Ни одно из них само по себе не создаёт прямой Light3D для пола и соседних объектов. Для такой лампы добавьте источник; непрямое освещение и отражения настраиваются отдельно.
Если в редакторе уровень выглядит иначе, сверяйте фактические источники и WorldEnvironment проекта. Этот пример задаёт их явно и не использует редакторский preview как настройку игры.
Диагностика
| Симптом | Проверка |
|---|---|
| Чёрный куб | Материал, включённый источник/ambient, LightCullMask и Layers |
| Point не влияет | Расстояние до поверхности и OmniRange |
| Spot светит мимо | Поворот/LookAt, SpotAngle и SpotRange |
| Объект светится, тени нет | ShadowEnabled, CastShadow, тип источника и покрытие теней |
| Тень дрожит или отрывается | Масштаб, разрешение/покрытие, затем bias |
| Много источников сильно снижает FPS | Профиль целевого уровня; уменьшить перекрытие, range и количество динамических теней |
Проверены базовые источники и направленные тени в Compatibility. Все режимы shadow atlas, физические единицы, GI, экспорт и производительность больших уровней здесь не подтверждаются.