簡體   English   中英

WebGL-在平面上顯示球體

[英]WebGL - display a sphere on a plane

我想顯示一個像在球體上但在飛機上的圖像。 此操作的一個示例是Mercatore投影,即從行星“展開”的地球地圖。 為了更好地說明自己,在球體上具有正方形紋理-不是在整個球體上,而是僅在一部分上-我想在飛機上展示在球體上看到這種紋理的結果。 我已經發現了這一點: 如何使用three.js在平面上包裹飛機?

但是我想使用着色器,因為它可能是最高效的,但也可能是最困難的。 我很難找到合適的公式。 有什么數學框架嗎?

您應該指定您真正想要的投影。 有很多方法可以處理曲面(不僅限於球體)。 您的問題是這種變換的逆過程,因此首先是直接投影(平面->球面)。 我使用這兩個(兩者都用於特定目的):

推算

  1. 球面到區域中心的距離與平面上的距離匹配

    這用於校正曲面上的紋理,例如眼鏡上的裝飾裝飾物等。

  2. 球面上與視軸的垂直距離與平面上的距離匹配

    因此,如果您從視軸上看,您會在球體和平面上看到相同的圖像,只需設置坐標系,使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));

Sphere_EquirectangularProjection

如果您想反向轉換谷歌球坐標系

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM