Que*_*ino 1 algorithm math projection mercator
美好的一天,
目前,我正在尝试将飞机弯曲到一个球体。我已经准备好尝试将Mercator投影与lla一起使用到efef。因此结果有所延缓,但它不像球形(半球形)。最成功的变体如下所示(更像是帐篷,而不是半球):
该帐篷的代码(pastebin)。我正在使用three.js进行渲染。
因此,我需要一些建议。我做错了什么?
使用球坐标系。角度long,lat是平面中的2D线性u,v坐标,输出是3D x,y,z。
将平面网格的顶点(点)转换为球面
我怀疑您的表格有积分,(x,y,z)因此您需要先计算u,v。设U,V在平面上的垂直单位基向量。可以通过在平面网格上减去2个点,标准化大小并利用叉积来确保垂直性来获得它们。所以:
u = `dot_product((x,y,z),U)` = x*U.x + y*U.y + z*U.z
v = `dot_product((x,y,z),V)` = x*V.x + y*V.y + z*V.z
Run Code Online (Sandbox Code Playgroud)
现在转换为球面角:
long=6.2831853*u/u_size_of_mesh
lat =3.1415926*v/v_size_of_mesh
Run Code Online (Sandbox Code Playgroud)
最后(x,y,z)在球面上计算新的:
x = R*cos(lat)*cos(long)
y = R*cos(lat)*sin(long)
z = R*sin(lat)
Run Code Online (Sandbox Code Playgroud)啮合
平面网格必须具有足够密集的点结构(足够的三角形/面),否则球体将无法正常显示。另一个问题是平面网格确实没有边缘和球体表面。Ti s可能会在连接平面边缘的球体表面上产生外观/间隙。如果要避免这种情况,可以在平面网格的相对两侧的边缘之间添加面以填充间隙,也可以完全抛弃网格并使用均匀的点网格重新采样平面。
如果要完全重新采样网格,则最好的方法是首先创建常规球体网格,例如:
然后通过逆过程计算到#1平面上的对应点,以便您可以插值点的其他参数(例如颜色,纹理坐标等)
[笔记]
如果要对此进行动画处理,则只需在原始平面点P0(x,y,z)和相应的球面点之间P1(x,y,z)使用带有动画参数的线性插值,t=<0.0,1.0>如下所示:
P = P0 + (P1-P0)*t
Run Code Online (Sandbox Code Playgroud)
如果是,t=0则输出为平面网格,否则t=1为球面。包装过程之间的任何地方都可以,因此请t以1足够小的步长(例如0.01)递增,并在某个计时器中进行渲染...
[Edit1] U,V基向量
这个想法很简单,获得2个非平行向量并更改其中一个向量,使其垂直于第一个但仍在同一平面上。
采取任何网状的面孔
例如三角形ABC
计算平面上的2个非零非平行向量
只需减去任意两对顶点即可,例如:
U.x=B.x-A.x
U.y=B.y-A.y
V.x=C.x-A.x
V.y=C.y-A.y
Run Code Online (Sandbox Code Playgroud)
并使其尺寸统一,因此将其除以尺寸
ul=sqrt((U.x*U.x)+(U.y*U.y))
vl=sqrt((V.x*V.x)+(V.y*V.y))
U.x/=ul
U.y/=ul
V.x/=vl
V.y/=vl
Run Code Online (Sandbox Code Playgroud)使它们垂直
因此,一个向量保持不变(例如U),然后计算另一个向量,使其垂直。为此,您可以使用交叉产品。两个单位向量的叉积是垂直于两个单位向量的新单位向量。这2种可能性中的哪一种仅取决于操作数((U x V) = - (V x U))的顺序,因此例如:
// W is perpendicular to U,V
W.x=(U.y*V.z)-(U.z*V.y)
W.y=(U.z*V.x)-(U.x*V.z)
W.z=(U.x*V.y)-(U.y*V.x)
// V is perpendicular to U,W
V.x=(U.y*W.z)-(U.z*W.y)
V.y=(U.z*W.x)-(U.x*W.z)
V.z=(U.x*W.y)-(U.y*W.x)
Run Code Online (Sandbox Code Playgroud)
的W只是暂时的矢量(图像中它被称为V')顺便说一句它是法向矢量的表面。
大小和对齐方式
现在,因为我没有有关您的网格的更多信息,所以我不知道其形状,大小等信息。理想的情况是网格是矩形且U,V矢量与边缘对齐。在这种情况下,您只需按每个方向上的矩形大小对坐标进行归一化(如左图所示)。
如果您的网格不是这样,并且您是U,V通过这种方法从面计算的,那么结果可能根本不与边缘对齐(它们可以旋转任何角度)...
如果无法避免这种情况(通过选择拐角面),则形状的拐角点将在每个边缘上具有各种坐标限制,并且您需要以某种完整的含义将它们插值或映射到正确的球面间隔(不能更具体一点,因为我不知道您到底在做什么。
对于几乎为矩形的形状,有时可以使用边缘,U,V即使它们彼此之间并非完全垂直。
[Edit2] C ++示例
好吧,如果您得到的Z轴上有一些噪声的完全对齐的方形网格(如高度图),那么这就是我进行网格转换的方式:
u = `dot_product((x,y,z),U)` = x*U.x + y*U.y + z*U.z
v = `dot_product((x,y,z),V)` = x*V.x + y*V.y + z*V.z
Run Code Online (Sandbox Code Playgroud)
我使用了我的动态列表模板,因此:
List<double> xxx; 是相同的 double xxx[];xxx.add(5);添加5到列表的末尾xxx[7] 访问数组元素(安全)xxx.dat[7] 访问数组元素(不安全但快速直接访问)xxx.num 是数组的实际使用大小xxx.reset() 清除数组并设置xxx.num = 0xxx.allocate(100)为100项目预分配空间用法如下:
mesh_init();
mesh_sphere();
Run Code Online (Sandbox Code Playgroud)
结果如下:
左侧是生成的带有噪声的平面网格,右侧是转换后的结果。
该代码反映了以上所有内容,并在球体半径上添加了Z-噪声以保留要素。以标准方式从几何体重新计算法线。对于整个TBN矩阵,您需要拓扑中的连接信息并从中进行重新计算(或利用球体几何体并从中使用TBN。
顺便说一句,如果要映射到球体而不是网格转换,则应查看相关的质量检查: