从VR中的片段着色器采样屏幕空间纹理吗?

Thi*_*per 5 unity-game-engine fragment-shader virtual-reality

我一直在研究Unity着色器设置,该设置为VR项目融合了两种视觉效果。

  • 模糊的轮廓光。这很好。
  • “内部发光”类型的效果。这在VR /立体视觉中不起作用,但在单视场渲染中效果很好。

图片和原理图在这里。

似乎此过程的红色部分没有按预期工作。当我Prepass在片段的计算出的屏幕位置对RenderTexture进行采样时,它在渲染时与模型不对齐。结果,“内部辉光”被抵消了。应该在有色区域内的样品落在外面,反之亦然。

“红色”垂直着色器:

v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);

            // Get screen position of vertex so we can sample _GlowPrePassTex in screenspace
            o.screenpos = ComputeScreenPos(o.vertex);
            return o;
        }
Run Code Online (Sandbox Code Playgroud)

“红色”碎片着色器:

fixed4 frag (v2f i) : SV_Target
        {               
            // Get rim component
            half tDot = saturate(dot(i.normal, i.viewdir));

            // Sample from _GlowPrePassTex at the fragment's screenspace position
            float2 screenUV = i.screenpos.xy / i.screenpos.w;

            #if UNITY_SINGLE_PASS_STEREO
                float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
                screenUV = (screenUV - scaleOffset.zw) / scaleOffset.xy;    // I don't know?
            #endif

            fixed4 hlSample = tex2D(_GlowPrePassTex, screenUV);

            // Standard hard rim
            fixed4 col = _RimColor * pow(1.0 - tDot, _RimExponent);

            // Modulate hlSample by (softer) rim strength and add to result
            col += hlSample * pow(1.0 - tDot, _HLExponent);

            return col;
        }
Run Code Online (Sandbox Code Playgroud)

我尝试过的事情:

我已经研究了Unity手册页上的示例,并尝试了相关示例(上面的片段着色器中包含了一个示例),但无济于事。我不确定每个对象应该实现什么以及以什么顺序使用它们。附带问题:如果我们切换到单通道立体声,则许多其他效果会停止工作,需要进行调整。

我还编写了一个版本,可以重新计算“红色”片段着色器本身中的Prepass结果,并且可以正常工作。但是,到那时,我们实际上要执行两次相同的(昂贵的)计算。如果可能的话,我想避免这种解决方案。

问题:

  • 我是否正在尝试做一些根本无法在VR /立体视觉中使用的操作?
  • 如果没有,如何为给定片段获取正确的屏幕空间UV坐标,以从VR中的纹理采样?

提前谢谢了!

小智 1

您似乎遇到了 VR 渲染的常见问题,即屏幕空间坐标并不总是在两只眼睛之间正确对齐。这是因为每只眼睛从稍微不同的角度渲染场景,因此给定片段的屏幕空间坐标对于每只眼睛来说可能略有不同。

UNITY_SINGLE_PASS_STEREO 宏和 unity_StereoScaleOffset 变量是 Unity 处理此问题的方法。在单通道立体渲染中,双眼同时渲染,因此需要为每只眼睛调整屏幕空间坐标。

您突出显示的代码行:


    float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
screenUV = (screenUV - scaleOffset.zw) / scaleOffset.xy;    // I don't know?
Run Code Online (Sandbox Code Playgroud)

正是这样做的。它根据当前正在渲染的眼睛来调整屏幕空间坐标。unity_StereoEyeIndex 变量为 0 或 1,具体取决于渲染的是左眼还是右眼。unity_StereoScaleOffset 变量是一个由两个 float4 值组成的数组,每只眼睛一个,其中包含调整屏幕空间坐标所需的比例和偏移值。

如果此调整无法正常工作,可能是因为 unity_StereoScaleOffset 值设置不正确。这可能是由于多种原因造成的,例如 VR 相机配置错误或 VR 渲染设置存在问题。

至于你的问题:

不,你想要做的事情应该可以在 VR/立体中实现。这只是正确处理每只眼睛的屏幕空间坐标的问题。

您发布的代码应该为您提供 VR 中给定片段的正确屏幕空间 UV 坐标。如果不是,那么可能还有其他问题。