您的位置:主页 > 新闻资讯 > 科技情报 >

深度分析VR头显分辨率:渲染、失真与校正

发布时间:2018-03-04 17:10   来源: 映维网

导读:本文来自美国加州大学戴维斯分校的研究类计算机科学家Oliver Kreylos

  我曾撰写过一篇关于(当时)当前头显显示器光学属性的长文,一篇关于宽视场头显投影与扭曲的文章,以及一篇关于测量头显显示器有效分辨率的文章,但从未涉足过真正的显示器分辨率。所以现在正是时候。

  当然,一个简短的答案取决于头显的型号。但如果你恰巧拥有htc vive,不妨看看图1和图2中的数据(其他头显类似,但实际数字不同)。这些数字显示了显示分辨率,单位为像素/度(pixels/°),以及通过我的Vive头显右边透镜中心的两条线(分别为水平和垂直)。红色,绿色和蓝色曲线分别代表红色,绿色和蓝色基本色的分辨率,但这一次不是由我本人测量所得,而是通过分析工厂对每个头显进行测量后所得的并存储在固件中的显示器校准数据。

  图1

2.png

  图2

  在这一点上,你可能会认为上述图表十分奇怪。对于这一点,建议阅读以下这个冗长的答案。在开始阐释之前,我要先给你一个数字:在我的Vive的右边透镜中心(像素是492602),绿色通道的分辨率为11.42像素/度,包含水平方向和垂直方向。如果你希望引起一个分辨率数字,这是我会选择的数字,因为当你看向正前方或远处时,这就是你得到的数字。然而,图1和图2清楚表明了一个数字无法解释完整的故事。

  下面,我们将开始详细解释这个冗长的答案。

  为什么上文的分辨率图表会如此怪异呢?我们都十分清楚不同显示器的分辨率都不尽相同,我们同样明白三个基本色的分辨率同样不同。但图中的锯齿是什么意思呢?要理解这一点,我们首先需要仔细研究现代VR头显是如何把3D环境渲染成一对2D图片,然后又是如何将其映射至左边和右边显示器。

  使得当今头显成为可能的主要创新之一是,厂商排除了复杂的,笨重的和昂贵的光学元件,并在软件中校正由简单,轻便和廉价单透镜带来的缺陷,亦即几何失真和色差。这种校正是通过在标准3D渲染管道末端添加额外的处理步骤来完成。现代VR头显不是直接把3D环境渲染到显示器,而是通过标准的(扭曲的)透视投影将3D环境渲染为中间图像,然后使用能够抵消由透镜(感知近眼屏幕的必须品)引起的失真的非线性校正函数,以此来把中间图像翘曲至实际显示器上。

  第1步:对中间直线式图像进行渲染

  详细来说,第一个渲染步骤如下。每个VR头显已经在固件中存储了渲染适当3D环境视图所需的各眼投影参数(水平和垂直视场),以及中间图像的推荐像素大小(Vive为1512×1680)。对于我的Vive的右眼,视场参数如下:左(left) = -1.24627,右(right) = 1.39228,下(bottom) = -1.46862,上(top) = 1.46388。这些数值位于所谓的“切线空间(tangent space)”之中,以兼容3D图形库。转换为角度,它们就会变成这样:左(left) = 51.257度,右(right) = 54.312度,下(bottom) = 55.749度,上(top) = 55.662度。它们为什么不是对称的呢?左右值不同是为了将每只眼睛的视场“偏斜”至外部,从而以立体重叠为代价来提供更多的周边视觉。由于制造公差的不同,上下值有所不同。所有这些值都是在工厂单独测量所得。

  在这一点上,你可能会试图简单地将水平和垂直视场相加,并得到总数105.569度×111.411度(左右:51.257+54.312;上下:55.749+55.662),但这是过于轻率的做法。这个矩形是头显实际视场的上限值,但不一定是实际尺寸,因为不是所有中间图像的像素都呈现在实际显示器之上,而且并非所有像素都对用户可见。

  我们不妨设想一下不存在透镜,并且直接显示中间图像的情况。以像素/度为单位的分辨率是多少呢?将总像素数除以总视场可能看起来是相当可行,这将产生水平分辨率为14.322像素/度,垂直分辨率为15.079像素/度。但这是错误的做法。问题是,由于图像在概念上为平面,所以整个图像的分辨率将不会均匀。下面请参考图3:两个相同大小的像素,一个直接位于眼睛前方,一个位于侧面,涵盖两个不同的角度α1和α2。

3.png

  图3

  一般来说,如果图像的一个轴是N像素长,并且覆盖从x0到x1的切线空间视场,则像素n(其中n介于0和N-1之间)覆盖的角度范围是α1-α0,其中α0=tan-1(n⋅(x1-x0)/N+x0) 和α1=tan-1((n+1)⋅(x1-x0)/N+x0),得出的分辨率为1/(α1-α0)。记住这一点,用微分进行绘图将更加容易。

  根据前面的段落,将像素索引与角度相关的函数为α(n)=tan-1((n+0.5)⋅(x1-x0)/N+x0),其中0.5与n相加以计算像素中心角。对于α(n)=((x1-x0)/N)/(1+((n+0.5)⋅(x1-x0)/N+x0)2)的总导数,tan-1(x)的导数可以合宜地设为1/(1+x2)。反相这一点并且从弧度转换为角度,我们可以得出(π/180)/(d/dn α(n))像素/度的像素位置n的分辨率。插入从我的Vive接收到的值,我们可以绘制图4中的函数结果(因为没有透镜,因此没有色差,三原色的分辨率曲线合并为一):

4.png

  图4

  我们可以从图表中得出大量的信息。首先,平面中间图像不适合VR渲染,因为分辨率在中心和边缘之间增加了2.5到3倍,这意味着不成比例的大量渲染像素被分配到外围,而它们在那里不是十分有用。尽管平面上投影为3D图形所固有,但没有人规定3D仿射空间(affine space)上的平面必须是平的。在3D投影空间中使用平坦平面会产生很好的渲染技巧,但这不是本文的话题。

  不过,图4中的曲线是否令你想起什么呢?我们设想一下将图4垂直缩放3.5倍,然后取出剪刀,将其切成31个相同大小的垂直条状。接下来,我们通过增加从中心往四面的量来向下移位这些条状。现在将这幅画面与图1进行比较。是否看到任何相似之处呢?前方剧透:这正是下一个渲染步骤中会发生的事情。

  第2步:透镜失真和色差的非线性校正

  成功校正透镜失真的秘诀是:在校准步骤中测量失真情况。理想情况下是在工厂中对每个头显进行相关处理。确切的校准步可能有所不同,但一个选项是利用校准的相机来捕捉显示在头显显示器上的已知校准图像将如何呈现给用户。

  这里的要点是:创建一种可信的虚拟现实幻觉。如果虚拟对象位于虚拟用户的特定方向,则虚拟对象需要呈现在与真实用户相同的方向。换句话说:对于头显显示器的每一个像素,我们需要知道像素呈现给头显用户的确切方向。最容易表达这一方向的方法是利用水平和垂直切线空间参数。

  现在,如果校准为我们提供了每个显示像素的切线空间方向映射,我们在渲染过程中又该如何为任意像素指定颜色呢?幸运的是,我们已经拥有了一个用于表示切线空间中的虚拟3D环境的图像:在步骤1生成的中间图像。这为透镜失真校正提供了一个简单的步骤:对于每个显示像素,在校准映射中查找切线空间坐标,然后在中间图像复制具有相同切线空间坐标的像素。由于中间图像的直线式结构,最后一部分的查找其实相当简单。

  更幸运的是:相同的步骤可以校正色差。我们无需为每个显示像素储存一个切线空间坐标,我们只需储存三个:为红,绿,蓝颜色组件各储存一个。因为三种颜色在相同透镜下的衍射程度不同,因此它们对于同一像素的切线空间坐标将有所不同。

  这非常好,但剩下的问题是如何表示校准映射。原则上,校准映射是一个1080×1200像素的图像(对Vive来说),每个像素有六个组件:三种颜色各一个切线空间(x,y)。由于技术原因,表示这样的映射在渲染性能方面效率不高。更好的方法是(这也是Vive和所有其他OpenVR头显所使用的方法),将映射简化为NxM相同大小(在显示空间中)矩形的“畸变网格”,每个颜色的切线空间坐标仅存储在那些矩形的边角,并在每个矩形的边角值之间进行插值。这样做更好,因为它非常紧凑(N和M可以很小),而且性能很好(因为现代显卡非常擅于绘图,以及在矩形中插值)。图5显示了我的Vive的右屏幕绿色通道失真网格,包括显示空间和切线空间。对于后一种情况,失真网格都叠加在中间图像的矩形边界上。

5.png

  图5

  图5告诉了我们一些有趣的事情。最重要的是,这表明Vive的透镜会导致相当多的枕形失真。靠近透镜中心的网格被压缩,而周围的网格被拉伸。这实现了把更多实际显示像素分配给重要的中央注视点区域,并且把更少显示像素分配给周边视觉的预期效果。换句话说,透镜远远消除了图4所示的糟糕分辨率分布。证据是中心位置的最终显示分辨率高于周边,如图1和图2所示。

  通过在切线空间中拉伸网格单元可以平衡分辨率。一个小单元会为实际显示的固定尺寸区域分配少量中间图像像素,从而增加局部分辨率;而拉伸单元会把更多像素填充至相同的固定尺寸区域,从而降低局部分辨率。这解释了图1和图2中倒置分辨率分布,但尚未出现锯齿的现象。

  结果表明,问题的解释十分简单:利用线性插值,显卡使用来自矩形边角的值进行插值,这意味着生成的失真映射是分段线性函数。分段线性函数的导数是片段间不连续跳变的分段常数函数。正是那些恒定分段(由每个网格单元内逐渐变化的局部分辨率调制)导致了图1和图2中的现象。导数中的不连续性不是问题,因为观察者无法知觉导数,只能知觉函数,而函数在什么地方都是连续的。

  对于图5,另一个有趣的观察结果是,切线空间中的畸变网格和中间图像之间的重叠并不完美。中间图像的一部分未被覆盖(沿着左边界的透镜形状区域),而且畸变网格的一部分落在中间图像之外。第一部分意味着用户无法看到中间图像的一部分,以及它的视场;第二部分意味着实际显示的部分不接收有效的图像数据,因此这变得无法使用。

  Vive的设计师在这里作出了一个有趣的决定:他们将右边中间图像的左边界延伸到右边显示器的左边缘之外(左边显示器也同样如此),从而获得与另一只眼睛的部分立体重叠。在直接向左看时视场不会延伸,因为那里没有更多的显示像素,但在向左或向上或向下看时视场将会延伸。“缺点”是Vive渲染的中间图像会出现奇怪的“偏食”形状,在内边缘缺失了两大块。

  最后要提的一点是:1512×1680像素的推荐中间图像大小来自于哪里呢?选择它的原因是:为了令中间图像的分辨率在通过畸变网格馈送之后能够大致与透镜中心区域中的真实屏幕分辨率相匹配,从而让重新采样过程中的混叠最小化(在把一个光栅图像翘曲到另一个光栅图像之上时的固有现象)。具体来说,中间图像在透镜中心的分辨率略低于实际显示的分辨率(10.01像素/度 vs 11.42像素/度),但往外来说中间图像能够快速超过实际显示的分辨率,请参见图6。

6.png

  图6

  总之:量化VR头显的真实物理分辨率是一个复杂的问题,因为这取决于透镜的光学属性,校准映射的表现形式和分辨率(网格 vs 图像 vs 分析函数),而且当然还包括真实显示的像素数目及其真实视场。但事实证明,通过在透镜中心引用绿色通道分辨率,存在一种合理的方法来将其整合为具体的数字并进行粗略比较。


推荐阅读