Applying map of the earth texture a Sphere

  1. create your own sphere mesh

    simple 2D loop through 2 angles (spherical coordinate system 2 Cartesian). You can easily add ellipsoid properties (earth is not a sphere) if you want more precision. If not then you can use single sphere mesh for all planets and just scale it before use …

    let a be the longitude and b the latitude so loop a from 0 to 2*PI [rad] and b from -0.5*PI to +0.5*PI [rad] where PI=3.1415... is the Pi (in C++ math.h it is called M_PI). If your math api uses degrees then convert to degrees PI [rad] = 180.0 [deg]

  2. add necessary info per vertex

    normals for lighting

        // just unit sphere
        nx=cos(b)*cos(a);
        ny=cos(b)*sin(a);
        nz=sin(b);
    

    texture coordinate (assuming rectangle non distorted image)

        // just convert a,b to <0,1> range
        tx=a/(2.0*PI)
        ty=(b/PI)+0.5;
    

    texture example

    vertex position

        // just sphere(rx=ry=rz=r) or ellipsoid (rx=ry=equatorial and rz=polar radius)
        // can also use rx*nx,ry*ny,rz*nz instead ...
        x=rx*cos(b)*cos(a);
        y=ry*cos(b)*sin(a);
        z=rz*sin(b);
    
  3. send all of this to OpenGL

    so all above store in some memory space (CPU or GPU) and then send to rendering. You can use legacy glBegin(QUAD_STRIP); ... glEnd(); or displaylist/VBO/VAO. Bind the right texture before each planet/body and do not forget to update ModelView matrix too. This is how mine coordinate systems looks like:

    coordinate systems

Also have a look at these related Q/As:

[edit1] C++ example

//---------------------------------------------------------------------------
const int nb=15;        // slices
const int na=nb<<1;     // points per equator
class planet
    {
public:
    bool _init;             // has been initiated ?
    GLfloat x0,y0,z0;       // center of planet [GCS]
    GLfloat pos[na][nb][3]; // vertex
    GLfloat nor[na][nb][3]; // normal
    GLfloat txr[na][nb][2]; // texcoord
    GLuint  txrid;          // texture id
    GLfloat t;              // dayly rotation angle [deg]
    planet() { _init=false; txrid=0; x0=0.0; y0=0.0; z0=0.0; t=0.0; }
    ~planet() { if (_init) glDeleteTextures(1,&txrid); }
    void init(GLfloat r,AnsiString texture);        // call after OpenGL is already working !!!
    void draw();
    };
void planet::init(GLfloat r,AnsiString texture)
    {
    if (!_init) { _init=true; glGenTextures(1,&txrid); }

    GLfloat x,y,z,a,b,da,db;
    GLfloat tx0,tdx,ty0,tdy;// just correction if CLAMP_TO_EDGE is not available
    int ia,ib;

    // a,b to texture coordinate system
    tx0=0.0;
    ty0=0.5;
    tdx=0.5/M_PI;
    tdy=1.0/M_PI;

    // load texture to GPU memory
    if (texture!="")
        {
        Byte q;
        unsigned int *pp;
        int xs,ys,x,y,adr,*txr;
        union { unsigned int c32; Byte db[4]; } c;
        Graphics::TBitmap *bmp=new Graphics::TBitmap;   // new bmp
        bmp->LoadFromFile(texture); // load from file
        bmp->HandleType=bmDIB;      // allow direct access to pixels
        bmp->PixelFormat=pf32bit;   // set pixel to 32bit so int is the same size as pixel
        xs=bmp->Width;              // resolution should be power of 2
        ys=bmp->Height;
        txr=new int[xs*ys];
        for(adr=0,y=0;y<ys;y++)
            {
            pp=(unsigned int*)bmp->ScanLine[y];
            for(x=0;x<xs;x++,adr++)
                {
                // rgb2bgr and copy bmp -> txr[]
                c.c32=pp[x];
                q      =c.db[2];
                c.db[2]=c.db[0];
                c.db[0]=q;
                txr[adr]=c.c32;
                }
            }
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,txrid);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
        glDisable(GL_TEXTURE_2D);
        delete bmp;
        delete[] txr;

        // texture coordinates by 1 pixel from each edge (GL_CLAMP_TO_EDGE)
        tx0+=1.0/GLfloat(xs);
        ty0+=1.0/GLfloat(ys);
        tdx*=GLfloat(xs-2)/GLfloat(xs);
        tdy*=GLfloat(ys-2)/GLfloat(ys);
        }
    // correct texture coordinate system (invert x)
    tx0=1.0-tx0; tdx=-tdx;

    da=(2.0*M_PI)/GLfloat(na-1);
    db=     M_PI /GLfloat(nb-1);
    for (ib=0,b=-0.5*M_PI;ib<nb;ib++,b+=db)
    for (ia=0,a= 0.0     ;ia<na;ia++,a+=da)
        {
        x=cos(b)*cos(a);
        y=cos(b)*sin(a);
        z=sin(b);
        nor[ia][ib][0]=x;
        nor[ia][ib][1]=y;
        nor[ia][ib][2]=z;
        pos[ia][ib][0]=r*x;
        pos[ia][ib][1]=r*y;
        pos[ia][ib][2]=r*z;
        txr[ia][ib][0]=tx0+(a*tdx);
        txr[ia][ib][1]=ty0+(b*tdy);
        }
    }
void planet::draw()
    {
    if (!_init) return;
    int ia,ib0,ib1;
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(x0,y0,z0);
    glRotatef(90.0,1.0,0.0,0.0); // rotate planets z axis (North) to OpenGL y axis (Up)
    glRotatef(-t,0.0,0.0,1.0); // rotate planets z axis (North) to OpenGL y axis (Up)

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,txrid);
    glColor3f(1.0,1.0,1.0);
    for (ib0=0,ib1=1;ib1<nb;ib0=ib1,ib1++)
        {
        glBegin(GL_QUAD_STRIP);
        for (ia=0;ia<na;ia++)
            {
            glNormal3fv  (nor[ia][ib0]);
            glTexCoord2fv(txr[ia][ib0]);
            glVertex3fv  (pos[ia][ib0]);
            glNormal3fv  (nor[ia][ib1]);
            glTexCoord2fv(txr[ia][ib1]);
            glVertex3fv  (pos[ia][ib1]);
            }
        glEnd();
        }
    glDisable(GL_TEXTURE_2D);
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    }
//---------------------------------------------------------------------------

usage:

// variable to store planet (global)
planet earth;

// init after OpenGL initialisation
earth.init(1.0,"earth.bmp");

// position update
earth.x0=  0.0;
earth.y0=  0.0;
earth.z0=-20.0;

// add this to render loop
earth.draw(); // draws the planet
earth.t+=2.5; // just rotate planet by 2.5 deg each frame...

example

I know its ugly but it does not use any funny stuff just legacy OpenGL and Math.h (cos(),sin(),M_PI) and VCL for bitmap loading. So rewrite to your environment and you will be fine. Do not forget that each planet has its own texture so you need to have one txrid per planet so either have each planet as separate planet variable or rewrite …

Leave a Comment