一个差评
闲来无事的时候,我也会发布一些插件到unity商店售卖,上个月的收入有500多美金,还行。
我发现大部分买插件的人都不评论的,买完即走,不留痕迹。当然有真心点赞的,也有一言不合就差评的。
有些差评确实反应了真实的代码问题,比如下面的这个差评,源自哥的一个水的插件:LWRP SSR Water

这位大哥说,我的水在VR下有奇怪的反射效果,我试了一下,果真如此:

正确的效果应该是这样的:

好吧,我本身不是做VR开发的,确实没为VR做考虑,不过顾客是上帝,我还是尝试去修复一下。
Bug分析
我的这个水基于前向渲染,利用屏幕空间反射带替代Unity提供的环境反射。在VR下,显示了错误的效果,看上去是没处理左右眼的问题。
奇怪的是,这个问题在标准管线下不存在,只存在于轻量管线。通过仔细的代码对比,我发现问题如下:
屏幕空间反射,顾名思义,我需要把世界坐标转换到屏幕坐标。计算屏幕坐标的时候,我用了Unity内置的ComputeScreenPos,但是标准版和LWRP版的ComputeScreenPos的代码略有差别:
标准版:
inline float4 ComputeScreenPos(float4 pos) {
float4 o = ComputeNonStereoScreenPos(pos);
#if defined(UNITY_SINGLE_PASS_STEREO)
o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
return o;
}
lightweight@6.9.0
// TODO: A similar function should be already available in SRP lib on master. Use that instead
float4 ComputeScreenPos(float4 positionCS)
{
float4 o = positionCS * 0.5f;
o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w;
o.zw = positionCS.zw;
return o;
}
原来lightweight版本并没有对UNITY_SINGLE_PASS_STEREO做处理。
修正
知道原因,修复就很容易了。
我封装了一个把世界坐标转换成屏幕坐标的函数,在函数最后加上对UNITY_SINGLE_PASS_STEREO的处理即可。
void SSRRayConvert(float3 worldPos, out float4 clipPos, out float3 screenPos)
{
clipPos = TransformWorldToHClip(worldPos);
float k = ((1.0) / (clipPos.w));
screenPos.xy = ComputeScreenPos(clipPos).xy * k;
screenPos.z = k;
#if defined(UNITY_SINGLE_PASS_STEREO)
screenPos.xy = UnityStereoTransformScreenSpaceTex(screenPos.xy);
#endif
}
再来一张

舒服。
网友评论