在VR中的片段着色器中如何对屏幕空间纹理进行采样?

5
我一直在为VR项目开发Unity着色器设置,其中包括两种视觉效果。
  • 模糊的轮廓发光效果。这个效果很好。
  • “内发光”类型的效果。这在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;
        }

“红色”片段着色器:

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;
        }

我尝试过的方法:

我查看了这个Unity手册页面上的示例,并尝试了相关示例(其中一个包含在上面的片段着色器中),但没有成功。我不确定每个示例应该实现什么功能以及使用它们的顺序。另一个问题是:如果我们切换到单通道立体影像呈现,许多其他效果将停止工作,需要进行调整。

我也编写了一个版本,在“红色”片段着色器内重新计算Prepass结果,这种方法有效。但是,在那点上,我们本质上会执行相同(昂贵)的计算两次。如果可能的话,我想避免使用此解决方案。

问题:

  • 我是否试图在VR /立体声中做一些根本无法实现的事情?
  • 如果不是,如何获得给定片段的正确屏幕空间UV坐标,以从VR中的纹理中采样?

非常感谢您的帮助!

1个回答

0

看起来你遇到了一个常见的VR渲染问题,即两只眼睛之间的屏幕空间坐标不总是正确对齐。这是因为每只眼睛从稍微不同的角度渲染场景,所以给定片段的屏幕空间坐标对于每只眼睛可能会略有不同。

UNITY_SINGLE_PASS_STEREO宏和unity_StereoScaleOffset变量是Unity处理这个问题的方式。在单次渲染中,两只眼睛同时渲染,因此需要调整每只眼睛的屏幕空间坐标。

你标记出来的代码行:


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

这就是正在做的事情。它根据当前渲染的眼睛调整屏幕空间坐标。unity_StereoEyeIndex变量的值为0或1,取决于是左眼还是右眼正在被渲染。unity_StereoScaleOffset变量是一个包含两个float4值的数组,每个眼睛都有一个值,其中包含调整屏幕空间坐标所需的比例和偏移值。
如果这个调整没有正确工作,可能是因为unity_StereoScaleOffset值没有被正确设置。这可能是由于一些原因,比如配置错误的VR相机或者VR渲染设置有问题。
至于你的问题:
不,你在尝试的VR/立体视觉中应该是可行的。只需要正确处理每个眼睛的屏幕空间坐标。
你发布的代码应该为你提供给定片段在VR中的正确屏幕空间UV坐标。如果不是这样,那么很可能是其他地方出了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接