#c# #c #unity3d #shader #fragment-shader
#c# #c #unity3d #шейдер #фрагмент-шейдер
Вопрос:
У меня есть шейдер размытия в Unity, и этот шейдер не поддерживает режим однопроходного рендеринга (после сборки на Oculus GO с однопроходными графическими артефактами появляются). Я попытался реализовать поддержку однопроходного рендеринга с использованием руководств Unity, но без каких-либо эффектов. У меня нет никаких идей, что может быть не так.
Однопроходные руководства Unity, которые я пробовал применять: https://docs.unity3d.com/Manual/SinglePassStereoRendering.html
https://docs.unity3d.com/Manual/SinglePassInstancing.html
СТАРАЯ ВЕРСИЯ НЕ ПОДДЕРЖИВАЛА ОДНОПРОХОДНЫЙ РЕНДЕРИНГ:
Шейдер «Пользовательский / РАЗМЫТИЕ» { Свойства { _Radius(«Радиус», диапазон (1, 255)) = 1 }
Category
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
SubShader
{
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
{
half4 sum = half4(0,0,0,0);
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum = GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 0.1f; range <= _Radius; range = 0.1f)
{
sum = GRABXYPIXEL(range, range);
sum = GRABXYPIXEL(range, -range);
sum = GRABXYPIXEL(-range, range);
sum = GRABXYPIXEL(-range, -range);
measurments = 4;
}
return sum / measurments;
}
ENDCG
}
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
{
half4 sum = half4(0,0,0,0);
float radius = 1.41421356237 * _Radius;
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum = GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 1.41421356237f; range <= radius * 1.41; range = 1.41421356237f)
{
sum = GRABXYPIXEL(range, 0);
sum = GRABXYPIXEL(-range, 0);
sum = GRABXYPIXEL(0, range);
sum = GRABXYPIXEL(0, -range);
measurments = 4;
}
return sum / measurments;
}
ENDCG
}
}
}
}
МОИ НЕРАБОЧИЕ ИЗМЕНЕНИЯ:
Шейдер «Пользовательский / РАЗМЫТИЕ» { Свойства { _Radius(«Радиус», диапазон (1, 255)) = 1 }
Category
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
SubShader
{
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 _MainTex_ST;
half4 frag(v2f i) : SV_Target
{
half4 sum = half4(0,0,0,0);
#if UNITY_SINGLE_PASS
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(UnityStereoScreenSpaceUVAdjust(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w),_MainTex_ST)))
#else
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
#endif
sum = GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 0.1f; range <= _Radius; range = 0.1f)
{
sum = GRABXYPIXEL(range, range);
sum = GRABXYPIXEL(range, -range);
sum = GRABXYPIXEL(-range, range);
sum = GRABXYPIXEL(-range, -range);
measurments = 4;
}
return sum / measurments;
}
ENDCG
}
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 _MainTex_ST;
half4 frag(v2f i) : SV_Target
{
half4 sum = half4(0,0,0,0);
float radius = 1.41421356237 * _Radius;
#if UNITY_SINGLE_PASS
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(UnityStereoScreenSpaceUVAdjust(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w),_MainTex_ST)))
#else
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
#endif
sum = GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 1.41421356237f; range <= radius * 1.41; range = 1.41421356237f)
{
sum = GRABXYPIXEL(range, 0);
sum = GRABXYPIXEL(-range, 0);
sum = GRABXYPIXEL(0, range);
sum = GRABXYPIXEL(0, -range);
measurments = 4;
}
return sum / measurments;
}
ENDCG
}
}
}
}
Я ожидаю, что этот шейдер будет поддерживать однопроходный режим рендеринга VR.
Комментарии:
1. Я не совсем разбираюсь в шейдерах Unity, но в вашем «новом» все еще есть два
Pass
блока. Вы уверены, что это правильно?2. @Immersive, однопроходный проход в данном случае относится к рендерингу обоих глаз одновременно для виртуальной реальности — это не связано с проходами рендеринга внутри шейдера.