了解问题
从我可以看到的问题来看,您所描述的问题是相机的近平面与门户定义的平面相交的结果。发生此交叉时,您可以在门户背后的墙后面看到。
这类似于其他游戏中玩家从水上过渡到水下时遇到的问题。如果相机正好在水面之上,则不会应用后期处理效果来模糊玩家的视线(使其变暗,变模糊和变蓝)。因此,如果近平面的底部在水下,则玩家可以清楚地看到在水下。
如果我是正确的,则可以在定义投影矩阵时通过更改此平面的位置来确认。随着从摄像机原点到近平面的距离增加,问题也应增加。
简单的解决方案
使近平面非常接近相机应该可以消除此问题。该解决方案不是一个完整的解决方案,但在绝大多数情况下将产生足够好的结果,并且是有效的。
完整的解决方案
如果仅使近平面靠近相机不满足要求,则可以创建一个“遮罩”以混合通过从播放器和门户的角度渲染场景而生成的图像。
假设只允许将门户应用到平坦的表面,则可以计算相机的近平面与门户定义的平面(或门户所在的墙)之间的相交线。此行会将屏幕分为两部分。确定屏幕像素在线条的哪一边将让您知道要使用哪个渲染图像,门户图像或播放器摄像机图像。
请记住,如果发生此问题,则摄像机视锥台必须完全位于门户内,因此相交线将始终从一个屏幕边缘完全切割到另一屏幕边缘。
此链接应有助于数学查找线。下面的代码应该大致正确。
相交线是使用线上的点和线的方向定义的。下方交点方向是使用门法线和摄像机视线方向(近平面法线)的叉积计算的。通过从近平面上的点直接朝向门平面(沿着门法线)投射射线并找到相交点,可以给出线上的点。
Vector3 intersectionDir = Vector3.cross(portalNorm, viewDir);
Ray ray = new Ray(camPos + viewDir * camNearPlaneDist, portalNorm);
Vector3 intersectionPos = ray.intersects(new Plane(portalVert1, portalVert2, portalVert3);
确保viewDir是单位向量。portalVert1、2和3只是用于Portal贴花或其上的表面的4个顶点中的3个。还有其他方法可以定义门户所在的平面,但是我认为这是最容易获得的信息。
一旦有了这两个向量来定义相交线,就将它们分别乘以视图,然后再将其投影矩阵以将其置于屏幕空间中。
然后,您可以使用后期处理着色器来混合这些图像。通过确定当前像素位于分界线的哪一侧,可以选择在每个像素处使用哪个图像。这是通过获取像素位置(这也是用于查找渲染目标texel的位置)并执行的;
float d = (pixelX - intersectionPos.X) * intersectionDir.Y - (pixelY - intersectionPos.Y) * intersectionDir.X;
通过d大于还是小于0给出边。如果正好是0,那么您就在网上。
有关以上数学的参考,请参见this。
创建深度蒙版/模板缓冲区以从门户网站透视图渲染之前使用时,也可以使用此方法。您可以创建一个全屏四边形,然后使用该行对其进行切片。