应用地球纹理的地图球形

我一直在尝试在太阳系的openGL(使用JOGL)中实现3D动画到目前为止我有5个不同大小的行星但我似乎有的问题是我无法在球体上添加地球纹理的地图可以任何人帮助我如何完成它?

这是我在Display方法中到目前为止的代码:

@Override public void display(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); GLU glu = new GLU(); gl.glClear(GL.GL_COLOR_BUFFER_BIT); //make sure we are in model_view mode gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); glu.gluLookAt(10,20,20,0,3,0,0, 20, 0); //gl.glMatrixMode(GL2.GL_PROJECTION); //glu.gluPerspective(45,1,1,25); //render ground plane gl.glPushMatrix(); gl.glTranslatef(-10.75f, 3.0f, -1.0f); gl.glColor3f(0.3f, 0.5f, 1f); GLUquadric earth = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL); glu.gluQuadricNormals(earth, GLU.GLU_FLAT); glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE); final float radius = 3.378f; final int slices = 89; final int stacks = 16; glu.gluSphere(earth, radius, slices, stacks); glu.gluDeleteQuadric(earth); Texture earths; try { earths = TextureIO.newTexture(new File("earth.png"), true); } catch (IOException e) { javax.swing.JOptionPane.showMessageDialog(null, e); } gl.glPopMatrix(); //gl.glEnd(); gl.glPushMatrix(); gl.glTranslatef(2.75f, 3.0f, -0.0f); gl.glColor3f(0.3f, 0.5f, 1f); GLUquadric earth1 = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(earth1, GLU.GLU_FILL); glu.gluQuadricNormals(earth1, GLU.GLU_FLAT); glu.gluQuadricOrientation(earth1, GLU.GLU_OUTSIDE); final float radius1 = 3.378f; final int slices1 = 90; final int stacks1 = 63; glu.gluSphere(earth1, radius1, slices1, stacks1); glu.gluDeleteQuadric(earth1); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(3.75f, 6.0f, -7.20f); gl.glColor3f(0.3f, 0.5f, 1f); GLUquadric earth3 = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(earth3, GLU.GLU_FILL); glu.gluQuadricNormals(earth3, GLU.GLU_FLAT); glu.gluQuadricOrientation(earth1, GLU.GLU_OUTSIDE); final float radius3 = 1.878f; final int slices3 = 89; final int stacks3 = 16; glu.gluSphere(earth3, radius3, slices3, stacks3); glu.gluDeleteQuadric(earth3); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(12.75f, 2.0f, -7.20f); gl.glColor3f(0.3f, 0.5f, 1f); GLUquadric earth4 = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(earth4, GLU.GLU_FILL); glu.gluQuadricNormals(earth4, GLU.GLU_FLAT); glu.gluQuadricOrientation(earth4, GLU.GLU_OUTSIDE); final float radius4 = 1.078f; final int slices4 = 89; final int stacks4 = 16; glu.gluSphere(earth4, radius4, slices4, stacks4); glu.gluDeleteQuadric(earth4); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(2.75f, -6.0f, -0.0f); gl.glColor3f(0.3f, 0.5f, 1f); GLUquadric earth5 = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(earth5, GLU.GLU_FILL); glu.gluQuadricNormals(earth5, GLU.GLU_FLAT); glu.gluQuadricOrientation(earth5, GLU.GLU_OUTSIDE); final float radius5 = 3.778f; final int slices5 = 90; final int stacks5 = 63; glu.gluSphere(earth5, radius5, slices5, stacks5); glu.gluDeleteQuadric(earth5); gl.glPopMatrix(); } 

  1. 创建自己的球体网格

    通过2个角度的简单2D环(球面坐标系2笛卡尔坐标)。 如果想要更高的精度,可以轻松添加椭球属性(地球不是球体)。 如果没有,则可以对所有行星使用单球面网格,并在使用之前进行缩放…

    a是经度, b是纬度,所以从02*PI [rad]循环ab-0.5*PI+0.5*PI [rad]其中PI=3.1415...是Pi(在C ++数学中) .h它被称为M_PI )。 如果你的数学api使用度数然后转换为度数PI [rad] = 180.0 [deg]

  2. 每个顶点添加必要的信息

    照明法线

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

    纹理坐标(假设矩形非扭曲图像)

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

    纹理的例子

    顶点位置

      // 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. 将所有这些发送给OpenGL

    所以以上都存储在一些内存空间( CPUGPU )中,然后发送到渲染。 您可以使用遗留glBegin(QUAD_STRIP); ... glEnd(); glBegin(QUAD_STRIP); ... glEnd(); 或者displaylist / VBO / VAO。 在每个行星/身体之前绑定正确的纹理,并且不要忘记更新ModelView矩阵。 这是我的坐标系看起来像:

    坐标系

另外看看这些相关的问答:

  • 现实的n体太阳系
  • 球体网格细分

[edit1] C ++示例

 //--------------------------------------------------------------------------- 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;yScanLine[y]; for(x=0;x 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 

用法:

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

例

我知道它的丑陋,但它没有使用任何有趣的东西只是传统的OpenGLMath.hcos(),sin(),M_PI )和VCL的位图加载。 所以重写你的环境,你会没事的。 不要忘记每个行星都有自己的纹理,所以你需要每个行星有一个txrid ,所以要么将每个行星作为单独的planet变量或重写......