应用地球纹理的地图球形 [英] Applying map of the earth texture a Sphere

查看:136
本文介绍了应用地球纹理的地图球形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 add a map of the earth texture on a Sphere can anybody help me on how its done?

这是我目前在显示方法中的代码:

This is the code i have so far in my Display method:

@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. 创建自己的球体网格

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

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

a 是经度和 b 纬度所以从 0 a c>至 2 * PI [rad]和 b 来自 -0.5 * PI + 0.5 * PI [rad]其中 PI = 3.1415 ... 是Pi(在C ++ math.h中,它被称为 M_PI )。如果你的数学api使用度数然后转换为度 PI [rad] = 180.0 [度]

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]

每个顶点添加必要的信息

照明法线

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

顶点位置

    // 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);


  • 将所有这些发送到OpenGL

    所以以上所有内容存储在一些内存空间( CPU GPU )中,然后发送到渲染。您可以使用旧版 glBegin(QUAD_STRIP); ... glEnd(); 或displaylist / VBO / VAO。在每个行星/身体之前绑定正确的纹理,并且不要忘记更新 ModelView 矩阵。这是矿井坐标系的样子:

    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 ++示例

    //---------------------------------------------------------------------------
    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();
        }
    //---------------------------------------------------------------------------
    

    用法:

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

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

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

    这篇关于应用地球纹理的地图球形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆