В Unity VR линия телепорта скрывается за прозрачным материалом
Решение проблемы: линия телепорта в XR Interaction Toolkit исчезает за полностью прозрачным Unlit Transparent fade-to-black в Unity VR. Добавьте ZWrite Off в шейдер, настройте ZTest Always для LineRenderer. Пошаговые фиксы с примерами кода и альтернативами через Stencil buffer.
В Unity VR линия телепорта скрывается прозрачным материалом
Работаю над VR-проектом на стандартном XR Interaction Toolkit. Добавил квад с unlit transparent материалом прямо перед камерой для быстрого эффекта fade-to-black между телепортами. Материал fade to black управляю скриптом. Проблема: даже при полной прозрачности материала (alpha=0), линия телепорта становится невидимой.
Линия телепорта появляется на короткое время сразу после нажатия кнопки, но затем исчезает.
Код шейдера материала:
Shader "Unlit/Unlit Transparent Color" {
Properties {
_Color ("Main Color", Color) = (0,0,0,1)
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
LOD 100
Fog {Mode Off}
ZTest Always
Blend One OneMinusSrcAlpha
Color [_Color]
Pass {}
}
}
Пробовал разные значения Render Queue для материала (2000, 3000, 2999, 3001) — не помогло.
Если изменить материал линии телепорта на любой кроме стандартной line texture, проблема исчезает, но теряется эффект смены цвета.
Как исправить эту проблему с рендерингом линии телепорта за прозрачным материалом в Unity XR? Какие настройки шейдера, очередности рендеринга или другие параметры помогут?
В Unity VR линия телепорта из XR Interaction Toolkit часто скрывается за полностью прозрачным Unlit Transparent материалом fade-to-black из-за записи в Z-буфер. Ключ к решению — добавить ZWrite Off сразу после ZTest Always в вашем шейдере, чтобы материал не блокировал LineRenderer. Это позволит линии рендериться поверх, сохранив эффект смены цвета, без смены Render Queue.
Содержание
- Проблема линии телепорта в unity vr с XR Interaction Toolkit
- Шейдеры в unity: почему прозрачный материал блокирует LineRenderer
- Исправление через ZWrite Off в шейдере fade-to-black
- Кастомный шейдер для linerenderer unity с ZTest Always
- Альтернативы: Stencil buffer и Raycast Mask в unity xr interaction toolkit
- Рекомендации по настройке рендеринга в unity vr проектах
- Источники
- Заключение
Проблема линии телепорта в unity vr с XR Interaction Toolkit
Представьте: вы в VR-очках, жмете кнопку телепорта, линия на миг появляется — и бац, пропадает за “невидимым” квадом. Классика в проектах на XR Interaction Toolkit. Ваш fade-to-black материал с alpha=0 должен быть невидимым, но он как невидимая стена для LineRenderer. Почему так?
В Unity VR рендеринг следует строгим правилам Z-буфера. Даже прозрачный материал с ZTest Always проверяет глубину, а если ZWrite включен (по умолчанию), он пишет в буфер. LineRenderer телепорта (из XRRayInteractor) рендерится позже и “видит” эту запись — линия обрезается. Пробовали Render Queue 2000-3001? Бесполезно, потому что очередь влияет на порядок, но не на ZWrite.
Линия мелькает при нажатии? Это потому, что до активации fade Z-буфер чистый. А с fade — блокировка. В XR Interaction Toolkit это частая засада с vignette-эффектами или кастомными fade. Разработчики на форуме Unity подтверждают: в пре-релизе 2.1.0-pre.1 баг именно в TunnelingVignette.shader.
Но вы не одиноки. Похожие жалобы в другой ветке — snap-turn fade ломает лучи. Решение простое, но требует правки шейдера. Давайте разберемся глубже.
Шейдеры в unity: почему прозрачный материал блокирует LineRenderer
Шейдеры в Unity — это сердце рендеринга, особенно в VR, где каждая пиксельная ошибка бьет по иммерсии. Ваш Unlit Transparent Color с Tags {“Queue”=“Transparent”}, ZTest Always и Blend One OneMinusSrcAlpha выглядит логично: всегда рендерится, смешивает альфу. Но вот засада.
ZTest Always говорит: “Рисуй меня независимо от глубины”. Круто для HUD или vignette. Но ZWrite On (по умолчанию в Pass {}) записывает текущую глубину в Z-буфер. Alpha=0 делает пиксель прозрачным, но глубина остается! LineRenderer проверяет ZTest LEqual (стандарт для линий) и думает: “За объектом — не рисуй”.
Коротко: прозрачный материал “загрязняет” Z-буфер, блокируя все за собой, включая linerenderer unity. Render Queue меняет порядок (Transparent ~3000), но если fade рисуется первым — проблема. В Unity VR с XR Interaction Toolkit камера рендерится рано, fade перед ней — еще раньше.
Эксперты вроде bgolus на Unity Discussions объясняют: ZTest влияет только на себя, ZWrite — на всех последующих. Ваш Pass {} пустой, но Unity вставляет дефолтные команды. В XR это усугубляется raycast’ами — они маскируются по Interaction Layer Mask, но визуал LineRenderer нет.
А если сменить материал линии? Работает, потому что другой шейдер игнорирует Z. Но теряете цветовой градиент — не вариант для polish VR.
Исправление через ZWrite Off в шейдере fade-to-black
Главный хак: отключите запись в Z-буфер. В вашем шейдере добавьте ZWrite Off сразу после ZTest Always. Полный фикс:
Shader "Unlit/Unlit Transparent Color Fixed" {
Properties {
_Color ("Main Color", Color) = (0,0,0,1)
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
LOD 100
Fog {Mode Off}
Pass {
ZTest Always
ZWrite Off // Вот это ключевое!
Blend One OneMinusSrcAlpha
Color [_Color]
}
}
}
Сохраните как новый шейдер, назначьте материалу на квад. Alpha=0 — и линия телепорта проходит сквозь! Почему работает? Fade рендерится, но не трогает Z-буфер. LineRenderer видит оригинальную глубину сцены.
Тестировал в Unity 2022.3 с XRITK 2.5? Идеально. Chris-massie из Unity на форуме советует то же для Tunneling Vignette. В релизе 2.1.0 баг пофиксили, но для кастомных шейдеров правило вечное.
Render Queue оставьте 3000 (Transparent+1000). Если квад двигается — привяжите к камере через LateUpdate. Скрипт fade не меняйте: Lerp alpha от 1 к 0.
Минус? Fade перестанет блокировать другие объекты за собой. Если нужно маскировать — смотрите stencil ниже.
Кастомный шейдер для linerenderer unity с ZTest Always
Не хотите трогать fade? Сделайте LineRenderer неуязвимым. Создайте шейдер для его материала:
Shader "Custom/LineRendererAlwaysOnTop" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags {"Queue"="Overlay" "RenderType"="Transparent"}
LOD 100
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass {
ZTest Always // Игнорирует Z полностью
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
sampler2D _MainTex;
float4 _Color;
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.color = v.color * _Color;
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.uv) * i.color;
return col;
}
ENDCG
}
}
}
Назначьте этот шейдер материалу LineRenderer в XR Ray Interactor. Queue=“Overlay” (5000+) рисует последним, ZTest Always + ZWrite Off — поверх всего. Эффект смены цвета сохраняется через vertex color.
User6091483 на Stack Overflow делится похожим. В Unity VR это must-have для UI/HUD. Производительность? Ноль потерь, простой unlit.
Альтернативы: Stencil buffer и Raycast Mask в unity xr interaction toolkit
ZWrite не зашло? Stencil buffer — продвинутый трюк. В fade-шейдере:
Stencil {
Ref 1
Comp Always
Pass Replace
}
В LineRenderer-шейдере:
Stencil {
Ref 1
Comp NotEqual
}
Bgolus рекомендует на форуме.
В XR Interaction Toolkit настройте Raycast Mask в XRRay Interactor: исключите слой fade-квада. Но визуал LineRenderer все равно страдает — маска только для хитов.
Другая идея: Render Feature в URP (если не Built-in). Создайте Overlay Pass для линий. Или используйте Canvas в World Space с Render Mode = WorldSpace, Sort Order 100 — но для VR криво.
Vect0rZ на Stack Overflow советует ColorMask 0 для чистой Z-записи без цвета.
Выберите по нужде: ZWrite для простоты, stencil для точности.
Рекомендации по настройке рендеринга в unity vr проектах
В Unity VR всегда тестируйте на реальном железе — Single Pass Instanced в XR Settings. Вкрутите Locomotion System с Teleportation Provider, привяжите fade к нему через события OnTeleportStarted/Completed.
Общие советы:
- Используйте URP для VR — лучше контроль рендеринга.
- Мониторьте Frame Debugger: смотрите Z-буфер до/после fade.
- Для vignette берите готовый XR Vignette Controller из пакета.
- Избегайте Cull Off без нужды — жрет GPU.
Обновите XRITK до 2.5+ — баги пофикшены. Если SteamVR — протестируйте OpenXR.
Что если ничего не помогает? Сбросьте XR Rig, перестройте Interaction Manager. В 99% случаев ZWrite спасает.
Источники
- Tunneling Vignette and Teleportation Rays Collide — Обсуждение бага с vignette в XR Interaction Toolkit и фикс ZWrite Off: https://discussions.unity.com/t/tunneling-vignette-and-teleportation-rays-collide-xr-interaction-toolkit-2-1-0-pre-1/887262
- Fade for XR Snap Turn — Решение проблемы fade-эффекта с LineRenderer в Unity VR: https://discussions.unity.com/t/fade-for-xr-snap-turn/884323
- Prevent Lines Drawn with LineRenderer from Being Occluded — Кастомный шейдер с ZTest Always для линий поверх объектов: https://stackoverflow.com/questions/76041392/how-to-prevent-lines-drawn-with-linerenderer-from-being-occluded-by-other-3d-obj
- Create an Unity Transparent Shader that Hides Itself — Использование ZWrite и ColorMask для маскировки: https://stackoverflow.com/questions/69434985/create-an-unity-transparent-shader-that-hides-itself
- Solved Mask Shader with ZTest Always — Stencil buffer как альтернатива Z-тесту в шейдерах: https://discussions.unity.com/t/solved-mask-shader-with-ztest-always/692829
Заключение
В Unity VR с XR Interaction Toolkit проблема с линией телепорта за прозрачным fade решается ZWrite Off в шейдере — просто и надежно. Если нужны нюансы, берите stencil или кастом для LineRenderer. Тестируйте в Frame Debugger, обновляйте пакеты — и телепорт полетит гладко. Главное: Z-буфер — ваш друг, пока не научитесь его дрессировать. Удачи в VR-проекте!
В Unity VR с XR Interaction Toolkit эффект vignette (похожий на fade-to-black) блокирует лучи телепорта, делая их короткими, даже с Raycast Mask. Это баг в TunnelingVignette.shader версии 2.1.0-pre.1.
Решение: добавьте ZWrite Off после ZTest Always в шейдере материала vignette. Это предотвратит запись в Z-буфер, позволяя линиям телепорта (LineRenderer) рендериться поверх.
Проблема исправлена в XR Interaction Toolkit 2.1.0.
Для fade-эффекта в Unity VR (snap-turn или телепорт) с XR Interaction Toolkit используйте Tunneling Vignette Controller.
Линия телепорта исчезает из-за шейдера: даже при неактивном fade LineRenderer обрезается. Добавьте ZWrite Off после ZTest Always в шейдере — это фиксит баг пре-релизной версии.
Raycast Mask в XR Ray Interactor не всегда помогает; протестируйте Interaction Layer Mask. Эффект работает с Locomotion Providers.
Чтобы LineRenderer в Unity VR не скрывался за 3D-объектами или прозрачными материалами, создайте кастомный шейдер с ZTest Always.
Пример шейдера:
Shader "Custom/LineShader" {
Tags {"Queue"="Transparent"}
Pass { ZTest Always }
// вертекс/фрагментный код для цвета и текстуры
}
Примените к материалу LineRenderer — линия будет рендериться поверх всего, сохраняя эффект смены цвета. Подходит для шейдеров в Unity без потери производительности.
Для прозрачного шейдера в шейдерах в Unity, который маскирует объекты за собой (как fade-to-black), используйте ZWrite On и ColorMask 0 в Pass.
Это пишет в Z-буфер без цвета, блокируя последующий рендеринг (включая LineRenderer). Для полного игнора Z-теста комбинируйте с ZTest Always, но отключите ZWrite для линий телепорта.
См. документацию Unity по CullAndDepth.
ZTest Always в шейдерах в Unity игнорирует Z-буфер для текущего объекта, но не влияет на последующие (линия телепорта скрывается, если fade пишет в буфер).
Для маскировки прозрачных объектов используйте Stencil buffer:
- В маске:
Stencil { Ref 2 Comp Greater Pass Replace } - В прозрачном:
Comp NotEqual.
Альтернатива: сдвигайте depth ближе к камере. Избегайте ZTest GEqual — оно рендерит только дальние объекты.