[英]WebGL - display a sphere on a plane
我想顯示一個像在球體上但在飛機上的圖像。 此操作的一個示例是Mercatore投影,即從行星“展開”的地球地圖。 為了更好地說明自己,在球體上具有正方形紋理-不是在整個球體上,而是僅在一部分上-我想在飛機上展示在球體上看到這種紋理的結果。 我已經發現了這一點: 如何使用three.js在平面上包裹飛機?
但是我想使用着色器,因為它可能是最高效的,但也可能是最困難的。 我很難找到合適的公式。 有什么數學框架嗎?
您應該指定您真正想要的投影。 有很多方法可以處理曲面(不僅限於球體)。 您的問題是這種變換的逆過程,因此首先是直接投影(平面->球面)。 我使用這兩個(兩者都用於特定目的):
球面到區域中心的距離與平面上的距離匹配
這用於校正曲面上的紋理,例如眼鏡上的裝飾裝飾物等。
球面上與視軸的垂直距離與平面上的距離匹配
因此,如果您從視軸上看,您會在球體和平面上看到相同的圖像,只需設置坐標系,使Z
軸為視線方向, x,y
軸與2D平面軸相對應。 然后只需計算z坐標以匹配球面
我想你要第一選擇
因此,將中點(x0,y0)
計算為邊界框的中心或平均間隔的點平均點。 計算每個點的ang
並通過弧度的 atan2
坐標(從中間點開始) !!!
然后計算dx,dy
並計算2D坐標為(x,y)=(x0+dx,y0+dy)
這是結果示例(我將其用於任何曲率):
[筆記]
還有其他基於射線投射的方法,可能還有更多...
[edit1] C ++示例
為您淘汰了小型C ++類:
//---------------------------------------------------------------------------
#include <Math.h>
class sphere_projection
{
public:
float x0,y0,z0,r0; // 3D sphere
float u0,v0; // mid point of 2D image
float m; // scale 2D image
int mode; // which projection type
sphere_projection()
{
x0=0.0; y0=0.0; z0=0.0; r0=1.0;
u0=0.0; v0=0.0; m=1.0;
mode=1;
}
void uv2xyz(float &x,float &y,float &z,float u,float v)
{
if (mode==1)
{
float a,b;
// 2D position scaled around midpoint and converted from arclength to angle
u=(u-u0)*m/r0;
v=(v-v0)*m/r0;
// correct on radius distrotion in both axises
a=u/cos(v);
b=v/cos(u);
// compute the 3D cartesian point on surface
z=z0+(r0*cos(b)*cos(a));
x=x0+(r0*cos(b)*sin(a));
y=y0+(r0*sin(b));
}
if (mode==2)
{
// 2D position scaled around midpoint
x=(u-u0)*m;
y=(v-v0)*m;
// compute the 3D cartesian point on surface
x=x0+x;
y=y0+y;
z=z0+sqrt(r0*r0-x*x-y*y);
}
}
void uv2xy (float &x,float &y, float u,float v)
{
if (mode==1)
{
float a,b,z;
// 2D position scaled around midpoint and converted from arclength to angle
a=(u-u0)*m/r0;
b=(v-v0)*m/r0;
// correct on radius distrotion in both axises and convert back to 2D position
x=u0+(a*r0/(m*cos(b)));
y=v0+(b*r0/(m*cos(a)));
}
if (mode==2)
{
float z;
// 2D position scaled around midpoint + Z axis
x=(u-u0)*m;
y=(v-v0)*m;
z=sqrt(r0*r0-x*x-y*y);
// compute arclengths and convert back to 2D position
x=u0+(r0*atan2(x,z)/m);
y=v0+(r0*atan2(y,z)/m);
}
}
};
//---------------------------------------------------------------------------
這是使用它的方法(在OpenGL中渲染):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0.0,+2.5,-20.0);
static float ang=0.0; ang+=2.5;
float x,y,z,u,v,d=0.2;
sphere_projection sp;
sp.x0=0.0;
sp.y0=0.0;
sp.z0=0.0;
sp.r0=1.5;
sp.u0=0.0;
sp.v0=0.0;
sp.m =0.5;
for (sp.mode=1;sp.mode<=2;sp.mode++)
{
// original 2D grid
glMatrixMode(GL_MODELVIEW);
glTranslatef(-5.0,0.0,0.0);
glColor3f(1.0f, 1.0f, 1.0f);
for (u=d-1.0;u<=1.0;u+=d)
for (v=d-1.0;v<=1.0;v+=d)
{
glBegin(GL_LINE_LOOP);
glVertex3f(u-d,v-d,0.0);
glVertex3f(u-d,v ,0.0);
glVertex3f(u ,v ,0.0);
glVertex3f(u ,v-d,0.0);
glEnd();
}
// sphere mapped corrected
glMatrixMode(GL_MODELVIEW);
glTranslatef(+5.0,0.0,0.0);
glPushMatrix();
glRotatef(ang,0.0,1.0,0.0);
glColor3f(1.0f, 0.0f, 0.0f);
for (u=d-1.0;u<=1.0;u+=d)
for (v=d-1.0;v<=1.0;v+=d)
{
glBegin(GL_LINE_LOOP);
sp.uv2xyz(x,y,z,u-d,v-d); glVertex3f(x,y,z);
sp.uv2xyz(x,y,z,u-d,v ); glVertex3f(x,y,z);
sp.uv2xyz(x,y,z,u ,v ); glVertex3f(x,y,z);
sp.uv2xyz(x,y,z,u ,v-d); glVertex3f(x,y,z);
glEnd();
}
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// sphere mapped corrected
glMatrixMode(GL_MODELVIEW);
glTranslatef(+5.0,0.0,0.0);
glColor3f(0.0f, 0.0f, 1.0f);
for (u=d-1.0;u<=1.0;u+=d)
for (v=d-1.0;v<=1.0;v+=d)
{
glBegin(GL_LINE_LOOP);
sp.uv2xy(x,y,u-d,v-d); glVertex3f(x,y,0.0);
sp.uv2xy(x,y,u-d,v ); glVertex3f(x,y,0.0);
sp.uv2xy(x,y,u ,v ); glVertex3f(x,y,0.0);
sp.uv2xy(x,y,u ,v-d); glVertex3f(x,y,0.0);
glEnd();
}
glTranslatef(-5.0,-5.0,0.0);
}
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glFlush();
SwapBuffers(hdc);
結果如下:
sp.uv2xy
將2D(u,v)圖像坐標轉換為投影校正的2D(x,y)坐標(圖像) sp.uv2xyz
將2D(u,v)圖像坐標轉換為投影校正的3D(x,y,x)坐標(x,y軸與屏幕x,y軸對應的球面) sp.mode
{1,2}選擇您要使用的投影類型 sp.u0,v0,m
選擇投影圖像的中點和比例 sp.x0,y0,z0,r0
定義要投影的球體 [edit2] Sphere EquirectangularProjection
這個2D的u,v
坐標不需要校正u,v
直接將其轉換為球角a=long,b=lat
因此對於u,v
在范圍<0,+1>
:
a=x*2.0*M_PI; b=(y-0.5)*M_PI;
那么3D坐標就是球面變換:
x=x0+(r0*cos(b)*cos(a));
y=y0+(r0*cos(b)*sin(a));
z=z0+(r0*sin(b));
如果您想反向轉換谷歌球坐標系
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.