Однопроходное рендеринг и пользовательские шейдеры
URP, HDRP, ShaderGraph, шейдеры Surface и встроенные шейдеры уже поддерживают однопроходное рендеринг стероидных экземпляров. Тем не менее, шейдеры из Asset Store, от других сторонних разработчиков, или те, которые вы написали сами, могут нуждаться в обновлении.
Более подробную информацию о поддержке инстанционного рендеринга в шейдерах см. в GPU Инстансирование. Информация в этом разделе конкретно касается стероидного рендеринга и может не включать все изменения, которые необходимо внести для поддержки инстанционного рендеринга в целом.
Обновление структуры входных атрибутов вершин
Добавить UNITY_VERTEX_INPUT_INSTANCE_ID макро к appdata struct.
Пример:
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};
Обновление структуры выходных атрибутов вершины
Добавить UNITY_VERTEX_OUTPUT_STEREO макро к v2f output struct.
Пример:
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //Insert
};
Обновление главной функции вершинного шейдера
Добавьте следующие макросы в начало вашего основного метода vert (в порядке):
UNITY_SETUP_INSTANCE_ID()UNITY_INITIALIZE_OUTPUT(v2f, o)UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO()
UNITY_SETUP_INSTANCE_ID() рассчитывает и устанавливает встроенные переменные шейдера unity_StereoEyeIndex и unity_InstanceID на правильные значения, основанные на том, какой глаз GPU в настоящее время рендирует.
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO сообщает GPU, какой глаз в массиве текстур он должен отображать, на основе значения unity_StereoEyeIndex. Этот макрос также передает значение unity_StereoEyeIndex из вершинного шейдера, так что оно будет доступно в шейдере фрагмента только в том случае, если UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX вызван в методе фрагментного шейдера frag.
UNITY_INITALIZE_OUTPUT(v2f,o) инициализирует все значения v2f в 0.
Пример:
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v); //Insert
UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
Шейдеры постпроцессорной обработки
Если вы хотите, чтобы ваши шейдеры Post-Processing поддерживали однопроходное создание стероидных экземпляров, выполните шаги для настраиваемых шейдеров, а также шаги ниже.
Примечание: Вы можете скачать все скрипты для Unity с сайта Unity.
Выполните следующие действия для каждого шейдера Post-Processing, для которого требуется поддержка однопроходного экземплярования:
Добавьте макрос
UNITY_DECLARE_SCREENSPACE_TEXTURE(tex)вне метода frag (см. пример ниже для размещения) в ваш скрипт Shader, так что при использовании определенного метода стероидного рендеринга GPU использует соответствующий семплер текстуры. Например, если вы используете многопроходное рендеринг, GPU использует семплер текстуры 2D. Для однопроходного инстанционирования или многовидового рендеринга семплер текстуры является массивом текстуры.Добавьте
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i)в начало метода fragment shader frag (см. пример ниже для размещения). Вам нужно добавить этот макрос только в том случае, если вы хотите использовать встроенную переменную shaderunity_StereoEyeIndex, чтобы узнать, для какого глаза GPU рендируется. Это полезно при тестировании эффектов после обработки.Используйте макрос
UNITY_SAMPLE_SCREENSPACE_TEXTURE()при выборке текстур 2D (см. пример ниже). Стандартные шейдеры используют текстурный обратный буфер 2D для выборки текстур. Однопроходный стероидный экземпляр не использует этого типа обратного буфера, поэтому если вы не указываете другой метод для выборки текстуры 2D, ваш шейдер не будет отображать текстуру правильно. Чтобы избежать проблем с отображением, макросUNITY_SAMPLE_SCREENSPACE_TEXTURE()определяет, какой стероидный путь отображения вы используете, и затем автоматически отображает текстуру в правильном порядке. См. документацию Unity по HLSLSupport.cginc для получения дополнительной информации о схожих макросах, используемых для текстур глубины и отображения теней экранного пространства.
Пример:
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); //Insert
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //Insert
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //Insert
// just invert the colors
col = 1 - col;
return col;
}
Полный образец кода шейдера
Ниже приведен простой пример шаблонного шейдера для эффектов изображений со всеми упомянутыми выше изменениями, примененными для поддержки однопроходного стероидного инстанционирования. Строчки, добавленные в код шейдера, помечены комментарием: //Insert.
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
};
//v2f output struct
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO //Insert
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v); //Insert
UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex); //Insert
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //Insert
fixed4 col = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_MainTex, i.uv); //Insert
// invert the colors
col = 1 - col;
return col;
}
Процедурная геометрия
Если вы используете методы Graphics.DrawProceduralIndirect() и CommandBuffer.DrawProceduralIndirect() для рисования полностью процедурной геометрии на GPU, обратите внимание, что оба метода получают свои аргументы из вычислительного буфера. Это означает, что трудно увеличить число экземпляров во время выполнения. Для увеличения числа экземпляров вы должны вручную удвоить число экземпляров, содержащихся в вычислительных буферах.
Отладка шейдера
Следующий код шейдера отображает GameObject как зеленый для левого глаза пользователя и красный для правого глаза. Этот шейдер полезен для отладки вашего стерео-рендеринга, так как он позволяет проверить, что все стерео-графики работают и функционируют правильно.
Shader "XR/StereoEyeIndexColor"
{
Properties
{
_LeftEyeColor("Left Eye Color", COLOR) = (0,1,0,1)
_RightEyeColor("Right Eye Color", COLOR) = (1,0,0,1)
}
SubShader
{
Tags { "RenderType" = "Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 _LeftEyeColor;
float4 _RightEyeColor;
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
return lerp(_LeftEyeColor, _RightEyeColor, unity_StereoEyeIndex);
}
ENDCG
}
}
}
ShaderGraph отладочный шейдер
ShaderGraph автоматически добавляет макросы, необходимые для поддержки однопроходного стероидного рендеринга. Чтобы реализовать отладочный шейдер в ShaderGraph, вы можете использовать узел Custom Function Node, который устанавливает базовый цвет на основе индекса глаза.
Используйте атрибут shader unity_StereoEyeIndex для определения базового цвета в зависимости от того, какой экземпляр глаза отображается. Узел Custom Function в вышеприведенном примере содержит следующий код:
Out = lerp(LeftColor, RightColor, unity_StereoEyeIndex);