Spatial: поверхность, свет, alpha и глубина
Полные шейдеры и реестр 95 имён: нормали, прозрачность, stencil и выбор материалов.
Spatial-шейдер задаёт поверхность 3D-меша. Назначьте Shader в ShaderMaterial, затем материал поверхности MeshInstance3D или его MaterialOverride. vertex() изменяет геометрию/атрибуты, fragment() задаёт свойства материала, light() при необходимости заменяет расчёт прямого света.
Первый материал и место назначения
Полный непрозрачный материал использует текстуру и tint. source_color отмечает цветовые данные, а hint_default_white позволяет получить цвет tint без отдельной текстуры:
shader_type spatial;
uniform sampler2D albedo_texture : source_color, hint_default_white;
uniform vec4 tint : source_color = vec4(1.0);
void fragment() {
ALBEDO = texture(albedo_texture, UV).rgb * tint.rgb;
METALLIC = 0.0;
ROUGHNESS = 0.7;
}ALBEDO — базовый цвет, не гарантированный итоговый RGB: освещение, белый блик неметалла, отражения, туман и тональная обработка меняют пиксель. Красный ALBEDO может дать ненулевые G/B из-за блика. Для просмотра только базового цвета используйте unshaded как диагностический режим.
Полный C#-помощник создаёт QuadMesh с материалом:
using Reckfell;
public static class SpatialSetup
{
public static MeshInstance3D Create(Shader shader)
{
return new MeshInstance3D
{
Mesh = new QuadMesh { Size = new Vector2(1, 1) },
MaterialOverride = new ShaderMaterial { Shader = shader },
};
}
}Загрузите Shader через ResourceLoader.Load<Shader>("asset://PbrSurface.reckfellshader"), вызовите SpatialSetup.Create(shader) и добавьте результат в дерево. Камера у (0,0,5), смотрящая вдоль −Z, видит лицевую сторону этого quad. Для освещённого материала нужен свет или подходящее окружение.
Порядок выбора материала: MaterialOverride объекта → override конкретной поверхности → материал поверхности ресурса Mesh. GetSurfaceOverrideMaterial возвращает сохранённый override, который может быть неактивен из-за MaterialOverride. GetActiveMaterial помогает проверить фактически выбранный базовый материал. GetSurfaceOverrideMaterialCount считает слоты поверхностей, не число непустых override.
MaterialOverlay добавляет проход, подчинённый своей очереди, смешиванию и глубине; это не безусловный слой поверх. В проверке непрозрачный overlay на той же глубине не оказался сверху, а прозрачный корректно смешался с базой. Не рассчитывайте исправить порядок прозрачности одним названием overlay.
Координаты вершин и нормалей
По умолчанию VERTEX, NORMAL, TANGENT и BINORMAL входят в vertex() в локальном пространстве меша. MODEL_MATRIX переводит позицию в мир, VIEW_MATRIX — в пространство камеры, PROJECTION_MATRIX — в clip. В fragment() VERTEX и обычная NORMAL уже в пространстве вида. Матрица активного прохода тени может относиться к свету; MAIN_CAM_INV_VIEW_MATRIX относится к основной камере viewport.
Нормаль при неравномерном масштабе преобразуется обратной транспонированной матрицей. Умножение на обычную MODELVIEW_MATRIX как направления даёт неверный угол. Полный диагностический пример ручного пути:
shader_type spatial;
render_mode unshaded, skip_vertex_transform;
void vertex() {
VERTEX = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
NORMAL = normalize(MODELVIEW_NORMAL_MATRIX * NORMAL);
TANGENT = normalize(mat3(MODELVIEW_MATRIX) * TANGENT);
BINORMAL = normalize(mat3(MODELVIEW_MATRIX) * BINORMAL);
}
void fragment() {
ALBEDO = normalize(NORMAL) * 0.5 + 0.5;
}skip_vertex_transform отключает автоматический model→view для позиции и базиса; проекция остаётся. Здесь NORMAL использует MODELVIEW_NORMAL_MATRIX, а касательные — линейную часть MODELVIEW_MATRIX. При сложных деформациях/неортогональном TBN дополнительно восстановите согласованный касательный базис. Не используйте эту запись как универсальное исправление любого normal-mapped/skinned меша.
В world_vertex_coords пользовательский vertex() получает мировые атрибуты; не применяйте MODEL_MATRIX второй раз. Если пишете POSITION, задавайте полный clip-space vec4 на всех ветках: автоматическая проекция позиции заменяется, но fragment VERTEX всё ещё формируется из VERTEX. Нельзя считать эти два выхода одним пространством. Нормализованный UV, SCREEN_UV viewport и пиксельный FRAGCOORD — также разные координаты.
Прозрачность и вырезание
У пространственного материала blend_mix является исходным режимом смешивания, но непрозрачность определяется и использованием ALPHA. В PbrSurface tint.a не используется: установка alpha цвета в 0 не делает поверхность прозрачной. Чтение/запись ALPHA может перевести материал в прозрачную очередь даже при значении 1; это меняет сортировку и участие в других эффектах.
Для плавной прозрачности запишите ALPHA. Для вырезанной формы можно сохранить жёсткую границу через ALPHA_SCISSOR_THRESHOLD. Полный пример оставляет правую половину quad непрозрачной:
shader_type spatial;
render_mode unshaded;
void fragment() {
ALBEDO = vec3(1.0, 0.0, 0.0);
ALPHA = UV.x;
ALPHA_SCISSOR_THRESHOLD = 0.5;
}Alpha hash использует ALPHA_HASH_SCALE для стохастического покрытия. Alpha-to-coverage требует соответствующего MSAA и настроек сглаживания; это не замена разрешению текстуры. Прозрачные поверхности сортируются с ограничениями и не ведут себя как набор попиксельно упорядоченных слоёв. depth_prepass_alpha помогает некоторым случаям, но не решает произвольную взаимную прозрачность.
NORMAL_MAP принимает карту нормалей в её кодировке, NORMAL — вектор нормали пространства вида. Не присваивайте NORMAL необработанный RGB текстуры. Цветовые текстуры/параметры помечайте source_color, карты данных — по их назначению; не переносите sRGB-преобразование на векторы, маски и физические параметры.
Собственный light()
Если light() не задан, движок использует готовое освещение. Пользовательская функция работает для источника, в пространстве вида. LIGHT — направление к нему, ATTENUATION учитывает ослабление/тени, LIGHT_COLOR — энергию и цвет. Для сложения источников накапливайте вклад через +=.
Полный простой диффузный расчёт:
shader_type spatial;
uniform vec3 base_color : source_color = vec3(1.0);
void fragment() {
ALBEDO = base_color;
ROUGHNESS = 1.0;
}
void light() {
float ndotl = max(dot(NORMAL, LIGHT), 0.0);
DIFFUSE_LIGHT += ndotl * ATTENUATION * LIGHT_COLOR / PI;
}В текущем Forward+ итоговый diffuse ещё умножается на ALBEDO. Поэтому повторное умножение на ALBEDO в примере light() затемнило бы цвет дважды. Проверка подтверждает однократное применение. source_color также переводит введённый цвет в линейное пространство: значение 0.5 в цветовом параметре нельзя автоматически считать линейной интенсивностью 0.5.
Пример рассчитан на обычный прямой диффузный свет, не на полную PBR-модель. Для area light учитывайте специальные данные/множители, а для блика задавайте SPECULAR_LIGHT. unshaded обходит освещение; vertex_lighting может обходить пользовательский попиксельный light(). Сначала проверьте требуемый путь, затем усложняйте BRDF.
Глубина: учитывайте проход, а не только число
В проверенном Forward+/Vulkan используется reverse-Z: DEPTH=0 — далеко, DEPTH=1 — близко. CLIP_SPACE_FAR описывает дальнюю clip-координату рендерера; это не готовое мировое расстояние. Для восстановления позиции по экранной глубине используйте подходящую INV_PROJECTION_MATRIX и деление на w; см. экранные шейдеры.
Если DEPTH записывается на одной ветке, задайте его осмысленно на всех ветках. Отдельно проверьте depth-prepass и тени: они не обязаны повторять произвольный фрагментный алгоритм.
В установленном Forward+ воспроизведён конкретный дефект: простой opaque-материал с пользовательским DEPTH может использовать общий prepass, где эта запись не учитывается. Геометрия закрывает задний объект в prepass, а затем её цвет не проходит проверку новой глубины — появляется чёрный участок. В исходнике выбор общего материала prepass не проверяет запись DEPTH. Это ограничение данной конфигурации, не признак того, что reverse-Z равен обычному Z. Отдельная проверка прозрачного пути без записи глубины подтвердила 0/1 относительно задней непрозрачной поверхности. Не используйте пользовательский DEPTH как универсальный трюк перекрытия без проверки всех нужных проходов.
Stencil: запись и чтение маски
Текущий синтаксис использует stencil_mode, значение 0–255 и режимы write/read/write_depth_fail. Правильное имя — write_depth_fail, не write_if_depth_fail. Чтение должно идти через прозрачную очередь. Эти примеры дают синюю поверхность-записыватель и красного читателя внутри её маски:
shader_type spatial;
render_mode unshaded;
stencil_mode write, 1;
void fragment() {
ALBEDO = vec3(0.0, 0.0, 1.0);
}shader_type spatial;
render_mode unshaded, depth_test_disabled;
stencil_mode read, compare_equal, 1;
void fragment() {
ALBEDO = vec3(1.0, 0.0, 0.0);
ALPHA = 1.0;
}Назначьте их двум мешам; читатель может быть крупнее записывателя. В проверке красный виден только внутри маски, а движение записывателя обновляет её. Читатель специально пишет ALPHA=1 и отключает depth test. Это минимальная проверка маски, не готовый портал или outline-эффект.
Для сравнения доступны compare_always, compare_equal, compare_not_equal, compare_less, compare_less_or_equal, compare_greater и compare_greater_or_equal. Сравнивается reference с содержимым stencil. Не считайте stencil обычной цветовой текстурой: в spatial нет встроенного sampler этого буфера. Поддержку конкретного рендерера/прохода проверяйте отдельно.
Полный реестр встроенных значений
G — глобально; V — vertex(); F — fragment(); L — light(). Звёздочка после этапа означает, что значение допускает запись. Имена без неё доступны только для чтения. Начальные значения и назначение результата зависят от поля; при условной записи выходов задавайте их на всех нужных ветках.
| Имя | Тип | Этапы | Значение |
|---|---|---|---|
TIME | float | G | Время рендерера с Engine.TimeScale; пауза дерева сама по себе его не останавливает. |
EXPOSURE | float | G | Обратный коэффициент нормализации emission в текущем Forward+; не базовый цвет. |
IN_SHADOW_PASS | bool | G | Признак текущего прохода карты теней. |
PI | float | G | Математическая константа float. |
TAU | float | G | Математическая константа float. |
E | float | G | Математическая константа float. |
OUTPUT_IS_SRGB | bool | G | Признак sRGB-выхода: в текущем Forward+ false, в Compatibility путь отличается. |
CLIP_SPACE_FAR | float | G | Дальняя clip-координата: Forward+/Mobile 0, Compatibility −1; не мировая глубина. |
IS_MULTIVIEW | bool | G | Признак многовидового вывода. |
VERTEX | vec3 | V* / F | Позиция: на входе vertex() локальная по умолчанию, в fragment() — пространство вида. |
NORMAL | vec3 | V* / F* / L | Вектор нормали; пространство зависит от этапа, см. раздел преобразований. |
TANGENT | vec3 | V* / F* | Касательный базис поверхности; правильное имя BINORMAL. |
BINORMAL | vec3 | V* / F* | Касательный базис поверхности; правильное имя BINORMAL. |
POSITION | vec4 | V* | Полная clip-space позиция, заменяющая автоматическую проекцию. |
UV | vec2 | V* / F / L | Первый/второй набор UV меша; интерполируется к фрагментам. |
UV2 | vec2 | V* / F / L | Первый/второй набор UV меша; интерполируется к фрагментам. |
COLOR | vec4 | V* / F | Цвет вершин/экземпляра; не подменяет ALBEDO автоматически в собственном шейдере. |
POINT_SIZE | float | V* | Размер точечного примитива, не масштаб произвольного меша. |
Z_CLIP_SCALE | float | V* | Масштаб clip-Z: текущий Forward+ смешивает z от w к обычному z; не действует в теневом проходе. |
INSTANCE_ID | int | V | Индекс экземпляра отрисовки; не Object/Entity instance ID игрового объекта. |
INSTANCE_CUSTOM | vec4 | V | Данные экземпляра; для частиц это CUSTOM их процесса. |
VERTEX_ID | int | V | Индекс вершины в текущем буфере. |
ROUGHNESS | float | V* / F* / L | Шероховатость для соответствующего пути освещения/отражений. |
BONE_INDICES | uvec4 | V | Индексы/веса костей из атрибутов меша, если они предоставлены. |
BONE_WEIGHTS | vec4 | V | Индексы/веса костей из атрибутов меша, если они предоставлены. |
CUSTOM0 | vec4 | V | Дополнительные атрибуты меша; заполнение/упаковка определяется Mesh. |
CUSTOM1 | vec4 | V | Дополнительные атрибуты меша; заполнение/упаковка определяется Mesh. |
CUSTOM2 | vec4 | V | Дополнительные атрибуты меша; заполнение/упаковка определяется Mesh. |
CUSTOM3 | vec4 | V | Дополнительные атрибуты меша; заполнение/упаковка определяется Mesh. |
MODEL_MATRIX | mat4 | V / F / L | Преобразование локальной позиции в мировую. |
MODEL_NORMAL_MATRIX | mat3 | V / F | Нормальная матрица локальное→мир для NORMAL. |
VIEW_MATRIX | mat4 | V / F / L | Мир→вид текущего прохода. |
INV_VIEW_MATRIX | mat4 | V / F / L | Вид→мир текущего прохода; при тенях это не обязательно основная камера. |
PROJECTION_MATRIX | mat4 | V* / F / L | Вид→clip; в vertex() допускает изменение. |
INV_PROJECTION_MATRIX | mat4 | V / F / L | Clip→вид; для позиции после умножения нужно деление на w. |
MODELVIEW_MATRIX | mat4 | V* | Локальное→вид; доступна для ручного преобразования. |
MODELVIEW_NORMAL_MATRIX | mat3 | V* | Нормальная матрица локальное→вид; нужна при неравномерном масштабе. |
VIEWPORT_SIZE | vec2 | V / F / L | Размер текущего viewport в пикселях. |
MAIN_CAM_INV_VIEW_MATRIX | mat4 | V | Матрица вид→мир основной камеры viewport, отдельно от камеры теней. |
NODE_POSITION_WORLD | vec3 | V / F | Позиция объекта в мире/виде по суффиксу; не позиция каждой вершины. |
CAMERA_POSITION_WORLD | vec3 | V / F | Мировая позиция/направление камеры текущего контекста; учитывайте stereo/проходы. |
CAMERA_DIRECTION_WORLD | vec3 | V / F | Мировая позиция/направление камеры текущего контекста; учитывайте stereo/проходы. |
CAMERA_VISIBLE_LAYERS | uint | V / F | Маска видимых слоёв камеры прохода. |
NODE_POSITION_VIEW | vec3 | V / F | Позиция объекта в мире/виде по суффиксу; не позиция каждой вершины. |
VIEW_INDEX | int | V / F | Индекс вида и константы выбора mono/левого или правого глаза. |
VIEW_MONO_LEFT | int | V / F | Индекс вида и константы выбора mono/левого или правого глаза. |
VIEW_RIGHT | int | V / F | Индекс вида и константы выбора mono/левого или правого глаза. |
EYE_OFFSET | vec3 | V / F | Смещение глаза в многовидовом рендеринге. |
LIGHT_VERTEX | vec3 | F* | Позиция пространства вида для освещения; запись не перемещает растеризованный меш. |
FRAGCOORD | vec4 | F / L | Координаты центра фрагмента; xy в пикселях целевого буфера. |
FRONT_FACING | bool | F | Лицевая/обратная сторона текущего примитива. |
VIEW | vec3 | F / L | Нормализованное направление к наблюдателю в пространстве вида. |
NORMAL_MAP | vec3 | F* | Закодированная карта нормалей в касательном базисе, не готовый NORMAL вида. |
NORMAL_MAP_DEPTH | float | F* | Вес/глубина применения карты нормалей. |
BENT_NORMAL_MAP | vec3 | F* | Закодированное bent-normal направление для путей окклюзии окружения. |
STREAMING_UV | vec2 | F* | UV для обратной связи стриминга/выбора mip; не автоматическая замена координат texture(). |
ALBEDO | vec3 | F* / L | Базовый линейный цвет материала, отдельно от итогового света и блика. |
PREMUL_ALPHA_FACTOR | float | F* | Коэффициент premultiplied-alpha пути освещённой поверхности; не замена ALPHA. |
ALPHA | float | F* / L* | Прозрачность/покрытие; использование влияет на очередь и проходы. |
METALLIC | float | F* / L | Доля металлической модели, обычно 0–1. |
SPECULAR | float | F* | Неметаллическая отражательная настройка; metallic-отражение также зависит от ALBEDO/METALLIC. |
RIM | float | F* | Вес краевого освещения и окраска края базовым цветом. |
RIM_TINT | float | F* | Вес краевого освещения и окраска края базовым цветом. |
CLEARCOAT | float | F* | Вес и шероховатость верхнего отражающего слоя. |
CLEARCOAT_ROUGHNESS | float | F* | Вес и шероховатость верхнего отражающего слоя. |
ANISOTROPY | float | F* | Сила анизотропии и направление потока в касательном пространстве. |
ANISOTROPY_FLOW | vec2 | F* | Сила анизотропии и направление потока в касательном пространстве. |
SSS_STRENGTH | float | F* | Вес подповерхностного рассеяния; поддержка зависит от рендерера. |
SSS_TRANSMITTANCE_COLOR | vec4 | F* | Цвет, глубина и усиление пути пропускания света через поверхность. |
SSS_TRANSMITTANCE_DEPTH | float | F* | Цвет, глубина и усиление пути пропускания света через поверхность. |
SSS_TRANSMITTANCE_BOOST | float | F* | Цвет, глубина и усиление пути пропускания света через поверхность. |
BACKLIGHT | vec3 | F* / L | Обратное рассеяние/просвечивание в световой модели. |
AO | float | F* | Материальный ambient occlusion; не включатель экранного SSAO. |
AO_LIGHT_AFFECT | float | F* | Доля влияния AO на прямой свет. |
EMISSION | vec3 | F* | Собственное HDR-свечение поверхности; само по себе не создаёт Light3D. |
DEPTH | float | F* | Записываемая глубина; проверяйте диапазон, ветки и взаимодействие prepass. |
SCREEN_UV | vec2 | F / L | Нормализованные координаты viewport, не UV меша. |
POINT_COORD | vec2 | F | Координаты внутри точечного примитива. |
FOG | vec4 | F* | Пользовательское смешивание с RGB тумана по весу A. |
RADIANCE | vec4 | F* | RGBA-переопределение вклада окружения по весу A; в spatial это не sampler RADIANCE из sky. |
IRRADIANCE | vec4 | F* | RGBA-переопределение вклада окружения по весу A; в spatial это не sampler RADIANCE из sky. |
ALPHA_SCISSOR_THRESHOLD | float | F* | Порог жёсткого вырезания по ALPHA. |
ALPHA_HASH_SCALE | float | F* | Масштаб стохастического alpha hash покрытия. |
ALPHA_ANTIALIASING_EDGE | float | F* | Край сглаживания alpha и координаты текстуры для соответствующего покрытия. |
ALPHA_TEXTURE_COORDINATE | vec2 | F* | Край сглаживания alpha и координаты текстуры для соответствующего покрытия. |
SPECULAR_AMOUNT | float | L | Множитель зеркального вклада текущего источника. |
LIGHT | vec3 | L | Направление к источнику в пространстве вида. |
LIGHT_COLOR | vec3 | L | Цвет/энергия источника для световой функции; учитывайте её нормализацию. |
LIGHT_IS_DIRECTIONAL | bool | L | Признак направленного или area-источника. |
LIGHT_IS_AREA | bool | L | Признак направленного или area-источника. |
LIGHT_AREA_DIFFUSE_MULTIPLIER | vec3 | L | Множители диффузного/зеркального вклада area light для пользовательского расчёта. |
LIGHT_AREA_SPECULAR_MULTIPLIER | vec3 | L | Множители диффузного/зеркального вклада area light для пользовательского расчёта. |
ATTENUATION | float | L | Ослабление текущего источника, включая тени. |
DIFFUSE_LIGHT | vec3 | L* | Накапливаемый диффузный/зеркальный свет; используйте += для суммы. |
SPECULAR_LIGHT | vec3 | L* | Накапливаемый диффузный/зеркальный свет; используйте += для суммы. |
Режимы отрисовки
Выбирайте согласованные режимы, а не все одновременно. Политика записи depth не отменяет тест глубины и ограничения очереди.
| Режим | Назначение |
|---|---|
blend_mix / blend_add / blend_sub / blend_mul / blend_premul_alpha | Обычное, аддитивное, вычитающее, умножающее и premultiplied смешивание. Учитывайте ALPHA и очередь; premultiplied-вход нельзя повторно умножать на alpha. |
depth_draw_opaque / depth_draw_always / depth_draw_never | Политика записи глубины непрозрачных/всех/никаких поверхностей с учётом выбранного прохода. |
depth_prepass_alpha | Предварительный depth-проход для подходящей прозрачной геометрии; не полное решение сортировки. |
depth_test_default / depth_test_disabled / depth_test_inverted | Обычный, отключённый или обратный тест глубины. Не смешивайте проверку с записью глубины. |
cull_back / cull_front / cull_disabled | Отсечение обратных/лицевых сторон или двусторонняя отрисовка. |
unshaded | Обход световой модели; удобно для диагностики ALBEDO. |
diffuse_burley / diffuse_lambert / diffuse_lambert_wrap / diffuse_toon | Модель диффузного света при использовании встроенного расчёта. |
specular_schlick_ggx / specular_toon / specular_disabled | Модель/отключение прямого зеркального вклада; отключение не равнозначно удалению всех отражений окружения. |
skip_vertex_transform / world_vertex_coords | Ручной model→view либо мировое пространство пользовательского vertex(); см. примеры выше. |
ensure_correct_normals | Имя принимается, но его макрос не реализует отдельное исправление в текущем Forward+ GLSL. Используйте правильную normal matrix. |
sss_mode_skin | Специализация подповерхностного рассеяния для кожи при поддержке рендерера. |
shadows_disabled | Отключает получение теней материалом; отбрасывание тени настраивается отдельно. |
ambient_light_disabled | Отключает вклад ambient/radiance окружения в поддерживаемом пути. |
shadow_to_opacity | Связывает освещение/тени с alpha для специальных shadow-catcher эффектов. |
vertex_lighting | Вершинное освещение вместо обычного попиксельного пути; учитывайте обход light(). |
particle_trails | Специальный путь геометрии trails GPU-частиц, не самостоятельное создание следа. |
alpha_to_coverage / alpha_to_coverage_and_one | Alpha-покрытие для соответствующего MSAA-пути. |
fog_disabled | Отключает получение тумана поверхностью. |
specular_occlusion_disabled | Отключает ветку спекулярной окклюзии окружения в текущем RD. |
wireframe / debug_shadow_splits | Диагностический каркас / раскраска каскадов теней. Подготовка данных wireframe зависит от бэкенда. |
TIME сбрасывается по rendering/limits/time/time_rollover_secs, по умолчанию через 3600 секунд. Для паузируемой игровой анимации передавайте собственное время uniform.
При выключенном ambient стандартное specular occlusion может обнулить зеркальный вклад даже при корректном RADIANCE или ReflectionProbe. В текущих Forward+ и Mobile ветка без bent-normal карты использует яркость ambient как приближение видимости отражения. Для изолированной проверки используйте specular_occlusion_disabled; в StandardMaterial3D — DisableSpecularOcclusion. Это не отключение прямых теней или diffuse AO. Настройка и проверенные условия.
Диагностика
| Симптом | Что проверить |
|---|---|
| Изменённый материал не виден | GetActiveMaterial, общий MaterialOverride, override поверхности и материал Mesh. |
| Красный материал содержит белый блик | ALBEDO не равен итоговому RGB; проверьте SPECULAR, METALLIC и освещение. |
| Цветовой параметр 0.5 даёт другую линейную яркость | source_color и sRGB→linear, затем тональную обработку вывода. |
| Ошибка нормалей при растяжении | MODELVIEW_NORMAL_MATRIX для NORMAL и согласованный TBN; не обычная матрица позиции. |
| Полигон исчез при повороте | Лицевую сторону и cull-режим. |
| Прозрачность не работает | Использование ALPHA, материал, очередь и видимость задней поверхности. |
| Чёрные участки после DEPTH | Значения всех веток и воспроизведённое ограничение общего depth-prepass. |
| Пользовательский свет слишком тёмный | Повторное ALBEDO, линейные цвета, нормализацию, ATTENUATION и пространство векторов. |
| Stencil не маскирует | stencil_mode, reference, правильное write_depth_fail и прозрачную очередь читателя. |
| Overlay не сверху | Его blending, depth и порядок проходов; это не UI-слой. |
В установленном Windows Forward+/Vulkan проверены шесть полных шейдеров и C#-помощник: базовая поверхность, нормали, culling, ALPHA/scissor, прямой свет, DEPTH, stencil и приоритет материалов. Реестр 95 имён и остальные режимы сверены с исходниками. Это не полная проверка всех BRDF, SSS, area light, MSAA, деформаций/скелета, стриминга, XR, теней и платформ. Функциональные пиксельные чтения не публикуются как художественные иллюстрации; дефект пользовательского DEPTH зафиксирован в проверке.