简体   繁体   English

WebGL-在平面上显示球体

[英]WebGL - display a sphere on a plane

I would like to show an image like it was on a sphere - but on a plane. 我想显示一个像在球体上但在飞机上的图像。 An example of this operation, would be the Mercatore projection, the map of the earth "unrolled" from the planet. 此操作的一个示例是Mercatore投影,即从行星“展开”的地球地图。 To better explain myself, having a squared texture on a sphere - not on the WHOLE sphere, but on a part of it only - I would like to show on a plane the result of seeing this texture on the sphere. 为了更好地说明自己,在球体上具有正方形纹理-不是在整个球体上,而是仅在一部分上-我想在飞机上展示在球体上看到这种纹理的结果。 I found this, already: How do I 'wrap' a plane over a sphere with three.js? 我已经发现了这一点: 如何使用three.js在平面上包裹飞机?

But I would like to do it with shaders, because it might the most efficient, but probably also the most difficult. 但是我想使用着色器,因为它可能是最高效的,但也可能是最困难的。 I have problems finding the right formula for it. 我很难找到合适的公式。 There exists any mathematical framework for it? 有什么数学框架吗?

You should specify what projection you really want. 您应该指定您真正想要的投影。 There are many approaches for curved surfaces (not just for spheres). 有很多方法可以处理曲面(不仅限于球体)。 Your problem is the inverse of such transform so first the direct projection (plane -> sphere surface). 您的问题是这种变换的逆过程,因此首先是直接投影(平面->球面)。 I use these two (both are used for specific purposes): 我使用这两个(两者都用于特定目的):

推算

  1. distances from middle of area on the sphere match the distances on the plane 球面到区域中心的距离与平面上的距离匹配

    this is used to correct textures on curved surfaces for example Ornament dekors on glasses etc... 这用于校正曲面上的纹理,例如眼镜上的装饰装饰物等。

  2. perpendicular distances to the view axis on the sphere match the distances on the plane 球面上与视轴的垂直距离与平面上的距离匹配

    so if you are looking from the view axis you see the same image on the sphere and on the plane just set the coordinate system so Z axis is the viewing direction and x,y axises are corresponding to your 2D plane axises. 因此,如果您从视轴上看,您会在球体和平面上看到相同的图像,只需设置坐标系,使Z轴为视线方向, x,y轴与2D平面轴相对应。 Then just compute z-coordinate to match sphere surface 然后只需计算z坐标以匹配球面

I think you want the first option 我想你要第一选择

so compute middle point (x0,y0) as center of bounding box or for evenly spaced point average point. 因此,将中点(x0,y0)计算为边界框的中心或平均间隔的点平均点。 Compute ang for each point and coordinate (from middle point) via atan2 in radians !!! 计算每个点的ang并通过弧度的 atan2坐标(从中间点开始) !!!

Then compute dx,dy and compute 2D coordinates as (x,y)=(x0+dx,y0+dy) 然后计算dx,dy并计算2D坐标为(x,y)=(x0+dx,y0+dy)

Here example of the result (I use this for any kind of curvature): 这是结果示例(我将其用于任何曲率):

例

[Notes] [笔记]

There are also another approaches based on ray casting,and possibly much more ... 还有其他基于射线投射的方法,可能还有更多...

[edit1] C++ example [edit1] C ++示例

Busted small C++ class for you: 为您淘汰了小型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);
            }
        }
    };
//---------------------------------------------------------------------------

This is how to use this (render in OpenGL): 这是使用它的方法(在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);

This is the result: 结果如下:

例

  • sp.uv2xy converts 2D (u,v) image coordinate to projection corrected 2D (x,y) coordinate (image) sp.uv2xy将2D(u,v)图像坐标转换为投影校正的2D(x,y)坐标(图像)
  • sp.uv2xyz converts 2D (u,v) image coordinate to projection corrected 3D (x,y,x) coordinate (sphere surface where x,y axises corresponds with screen x,y axises) sp.uv2xyz将2D(u,v)图像坐标转换为投影校正的3D(x,y,x)坐标(x,y轴与屏幕x,y轴对应的球面)
  • sp.mode {1,2} selects whitch type of projection you want to use sp.mode {1,2}选择您要使用的投影类型
  • sp.u0,v0,m selects the projection image mid point and scale sp.u0,v0,m选择投影图像的中点和比例
  • sp.x0,y0,z0,r0 defines the sphere on which you are projecting sp.x0,y0,z0,r0定义要投影的球体

[edit2] Sphere EquirectangularProjection [edit2] Sphere EquirectangularProjection

There is no correction needed for this one 2D u,v coordinate is directly converted to spherical angles a=long,b=lat so for u,v in range <0,+1> : 这个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;

Then the 3D coordinate is just spherical transformation: 那么3D坐标就是球面变换:

x=x0+(r0*cos(b)*cos(a));
y=y0+(r0*cos(b)*sin(a));
z=z0+(r0*sin(b));

Sphere_EquirectangularProjection

if you want the reverse transform google spherical coordinate system 如果您想反向转换谷歌球坐标系

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM