Applying map of the earth texture a Sphere

前端 未结 1 1845

i been trying to implement a 3D animation in openGL (using JOGL) of a solar system so far i have 5 planets of different sizes but the problem i seem to be having is i cant a

相关标签:
1条回答
  • 2020-11-27 09:18
    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;
      

      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:

    Also have a look at these related Q/As:

    • realistic n-body solar system
    • sphere mesh by subdivision

    [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...
    

    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 ...

    0 讨论(0)
提交回复
热议问题