Android纹理球体

时间:2011-09-21 07:58:34

标签: android opengl-es geometry textures

我想在android上画一个地球地球仪。此时我需要UV纹理坐标的帮助。我正在使用这个地球纹理(kibotu.net/earth.jpg)。目前它看起来像这个正面(kibotu.net/earthsphere.png),但90°旋转它看起来像这样(kibotu.net/earthsphere2.png)。

由于OpenGL ES不支持Quadrics,并且它没有原生GLUT库,我发现它相当困难。所以也许有人遇到同样的问题,可以帮助我。

我的第一种方法是使用Blender并将其导出为OBJ文件并将其加载到我的应用程序中。然而,有两个副作用:完全奇怪的看法(kibotu.net/sphere.png),最重要的是没有纹理坐标。

(我使用过这些Blender导出选项[kibotu.net/blenderobjoptions.png])

我的第二次尝试是使用freeglut库来完成这项工作。现在我有一个漂亮的球体(kibotu.net/sphere5.png)。但是也没有纹理坐标。由于它的最后一个版本于2009年11月27日发布,我非常怀疑将很快发布更新。

之后我尝试应用wiki approach to calculate sphere uvs。但它看起来像这个kibotu.net/sphere2.png。在遇到此问题后,我正在搜索每个stackoverflow线程并遇到this uv approach。然而,没有最终解决方案。我已将它应用于freeglut代码。

static private FloatBuffer sphereVertex;
static private FloatBuffer sphereNormal;
static private FloatBuffer sphereTexture;
static float sphere_parms[]=new float[3];
private static void plotSpherePoints(float radius, int stacks, int slices)
{
    sphereVertex = OpenGLUtils.allocateFloatBuffer( 4* 6 * stacks * (slices+1) );
    sphereNormal = OpenGLUtils.allocateFloatBuffer( 4* 6 * stacks * (slices+1) );
    sphereTexture = OpenGLUtils.allocateFloatBuffer( 4* 4 * stacks * (slices+1) );

    int i, j; 
    float slicestep, stackstep;

    stackstep = ((float)Math.PI) / stacks;
    slicestep = 2.0f * ((float)Math.PI) / slices;

    int counter = 0;

    for (i = 0; i < stacks; ++i) {
        float a = i * stackstep;
        float b = a + stackstep;

        float s0 =  (float)Math.sin(a);
        float s1 =  (float)Math.sin(b);

        float c0 =  (float)Math.cos(a);
        float c1 =  (float)Math.cos(b);

        float nv,u,v,dx,dy,dz;
        for (j = 0; j <= slices; ++j)       
        {
            float c = j * slicestep;
            float x = (float)Math.cos(c);
            float y = (float)Math.sin(c);

            nv=x * s0;
            sphereNormal.put(nv);
            sphereVertex.put( dx = nv * radius);

            nv=y * s0;
            sphereNormal.put(nv);
            sphereVertex.put( dy = nv * radius);

            nv=c0;

            sphereNormal.put(nv);
            sphereVertex.put( dz = nv * radius);
            // uv 1
            if (dz < 0)
                u = (float) (1 + dx/Math.sqrt(dx*dx+dy*dy+dz*dz)  / 4);
            else
                u = (float) (1 - (1 + dx/Math.sqrt(dx*dx+dy*dy+dz*dz) ) / 4);

            v = (float) (0.5 + ( -dy/Math.sqrt(dx*dx+dy*dy+dz*dz) ) /2);

            // u = (float) (dx / Math.sqrt(dx*dx + dy*dy +dz*dz));
            // v = (float) (dy / Math.sqrt(dx*dx + dy*dy +dz*dz));
            sphereTexture.put(u);
            sphereTexture.put(v);

            nv=x * s1;

            sphereNormal.put(nv);
            sphereVertex.put( dx = nv * radius);

            nv=y * s1;

            sphereNormal.put(nv);
            sphereVertex.put( dy = nv * radius);

            nv=c1;

            sphereNormal.put(nv);
            sphereVertex.put( dz = nv * radius);

            // uv 2
            if (dz < 0)
                u = (float) (1 + dx/Math.sqrt(dx*dx+dy*dy+dz*dz)  / 4);
            else
                u = (float) (1 - (1 + dx/Math.sqrt(dx*dx+dy*dy+dz*dz) ) / 4);

            v = (float) (0.5 + ( -dy/Math.sqrt(dx*dx+dy*dy+dz*dz) ) /2);

            sphereTexture.put(u);
            sphereTexture.put(v);
        }
    }
    sphereNormal.position(0);
    sphereVertex.position(0);
    sphereTexture.position(0);
}

绘图算法:

public static class SolidSphere{
    public static void draw(GL10 gl,float radius, int slices, int stacks) 
    {
        int i, triangles;

        if (sphereVertex!=null) 
        {
            if (sphere_parms[0] != radius || sphere_parms[1] != slices || sphere_parms[2] != stacks) 
            {
                sphereVertex=null;
                sphereNormal=null;
                sphereTexture = null;

                gl.glVertexPointer(3, GL10.GL_FLOAT, 0, OpenGLUtils.allocateFloatBuffer(0));
                gl.glNormalPointer(GL10.GL_FLOAT, 0, OpenGLUtils.allocateFloatBuffer(0));
                gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, OpenGLUtils.allocateFloatBuffer(0));
            }
        }

        if (sphereVertex==null) 
        {
            sphere_parms[0] = radius; 
            sphere_parms[1] = (float)slices; 
            sphere_parms[2] = (float)stacks;

            plotSpherePoints(radius, stacks, slices);
        }

        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, sphereVertex);
        gl.glNormalPointer(GL10.GL_FLOAT, 0, sphereNormal);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, sphereTexture);

        gl.glEnableClientState (GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState (GL10.GL_NORMAL_ARRAY);
        gl.glEnableClientState (GL10.GL_TEXTURE_COORD_ARRAY);

        triangles = (slices + 1) * 2;
        for(i = 0; i < stacks; i++)
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, i * triangles, triangles);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }
}

有人能帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

您应该可以为(单位)球体拍摄任何三角形网格,并应用从顶点(X,Y,Z)到(UV)的映射。

我太懒/忙(删除你想要的任何一个)来完成你的代码,但是你可能会在Watt&amp;的第6章找到答案。瓦特的“高级动画和渲染技术”。它提供了一些简单的方法来为球体生成合适的紫外线。

IIRC,为避免极点发生过多失真,他们的映射使用正弦来挤压/拉伸纬度映射。