2021-04-09

bing    UnitVectorToOctahedron

图形学几何数学知识

https://www.jianshu.com/p/59b71d2bfdf4

图形学几何数学知识

残编断简

2020.08.06 15:26:00字数 1,174阅读 71

1. 球面积分

球面积分跟普通的线性积分的区别在于需要考虑到半径的长度,因此只需要利用极坐标公式将球面积分转换为线性积分即可。

坐标系示意图

用球面坐标系表示,某个点的坐标为,各个变量含义如上图所示,变量的范围给出如下:

 

微分单元示意图

如上图所示,如果要进行球形空间积分,那么就需要提取积分的微分单元,半径上的微分单元很简单,就是,但是球面上的微分单元就不能直接使用了,直接使用就变成了线性坐标系积分了,正确来说应该需要进行一次转换,我们在球面上的积分,实际上是对圆弧的积分,因此需要将角度转换为圆弧的长度,如果用弧度来表示角度的话,我们知道角对应的弧度为,因此在这个角度维度上的微分单元就可以用表示,在指定了之后,对应维度上的圆弧也可以按照相同的算法求得,不过这里需要注意的是,角度的圆弧对应的半径不再是,而是以为长度,以为角度旋转360度得到的球面上的小圆,这个小圆的半径为,到目前为止,三个维度的微分单元就已经给出,如果要求取表面积,那么总的微分单元就可以给出为:
 

2. 降维法线编码

为了节省带宽,游戏中常见的一个做法是将三维法线数据用二维来进行压缩,而由于法线通常是单位长度的,因此也为这种压缩提供了可能。

UE中有一种常用的压缩编码方式是来自于Cigolle 2014年发表的的A Survey of Efficient Representations for Independent Unit Vectors论文中的名叫Octahedron Normal Vectors的编码方法。

这种压缩编码的原理是将法线看成是一个单位球面上的点,以这个球的球心为中心点,可以构建一个正八面体,那么球面上的任意点刚好可以实现与正八面体的面上的某一点(称之为投影点)一一对应,根据这个原理将法线对应的点与球心连线,与正八面体的交点就是投影点,如果只是这么做的话,依然不能得到二维压缩向量,因为Z轴的正负情况还依然存在。

示意图

如上图所示,实际上一个半球最终投影的区域对应的是最后一个小图中大正方形中的旋转了90度的小正方形区域,而小正方形周边还剩下四个等腰直角三角形,恰好组成一个额外的小正方形,这部分区域还暂时没有使用,因此这里对于z<0的情况,就将之沿着前面小正方形的四条边进行翻转就能够将z小于零的部分完美安置:

翻转示意图

这种编码方式在原survey中被认为是最佳的编码方式,其主要优点为:

  1. 提供了接近均匀的编码算法,不会出现部分区域精度严重下降的情况
  2. 编解码公式十分简单
  3. 编码结果十分直观(直接投影到八面体上,再从八面体投影到z=0的正方形上)

编解码公式给出如下(相关说明直接写在注释中,不再额外赘述):

2.1 编码

编码有两种实现,一种是UnitVectorToOctahedron,另一种是UnitVectorToHemiOctahedron。从名字上来看,一种是将球面上的点投影到整个八面体上,另一个则是将上半球球面上的点投影到半个八面体上,前者的应用范围更广,而后者的实现更为简单,且精度更高(因为使用了更多的数据来存储xy),可以在实际使用的时候根据需要进行选用。

2.1.1 UnitVectorToOctahedron

    N.xy /= dot( 1, abs(N) );//将球面上点转移到正八面体上,得到的对应于z=0区域上的投影的xy坐标
    if( N.z <= 0 )//对z<=0情况进行翻转处理,用于填充边角等腰直角三角形
    {
        N.xy = ( 1 - abs(N.yx) ) * ( N.xy >= 0 ? float2(1,1) : float2(-1,-1) );
    }
    return N.xy;

2.1.2 UnitVectorToHemiOctahedron

    N.xy /= dot( 1, abs(N) );//投影到Z=0的正方形上
    //相当于乘了一个45度旋转矩阵与一个scale为二分之根号二的缩放系数的缩放矩阵,用于将小正方形的数据扩充至整个大正方形。
    return float2( N.x + N.y, N.x - N.y );

2.2 解码

2.2.1 OctahedronToUnitVector

    float3 N = float3( Oct, 1 - dot( 1, abs(Oct) ) );//与编码进行对称解码处理
    if( N.z < 0 )//处于边角等腰三角形区域的数据,得到的z值必定<=0,对之进行恢复处理
    {
        N.xy = ( 1 - abs(N.yx) ) * ( N.xy >= 0 ? float2(1,1) : float2(-1,-1) );
    }
    return normalize(N);

2.2.2 HemiOctahedronToUnitVector

    Oct = float2( Oct.x + Oct.y, Oct.x - Oct.y ) * 0.5;
    float3 N = float3( Oct, 1 - dot( 1, abs(Oct) ) );
    return normalize(N);

参考文献

1. 球面积分
2. A Survey of Efficient Representations for Independent Unit Vectors

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值