Android 纹理球体

发布于 2024-12-05 19:35:33 字数 5420 浏览 1 评论 0原文

我想在安卓上画一个地球仪。此时我需要有关 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 方法来计算球体 uv 。然而它看起来像这个 kibotu.net/sphere2.png。在这个问题之后,我正在搜索每个 stackoverflow 线程,并遇到了这种 uv 方法。但目前还没有最终的解决方案。我已将其应用到 f​​reeglut 代码中。

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

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

I want to draw an earth globe on android. At this point I need help with the UV texture coordinates. I'm using this earth texture (kibotu.net/earth.jpg). Currently it looks like this front side (kibotu.net/earthsphere.png), but 90° rotated it looks like this (kibotu.net/earthsphere2.png).

Since OpenGL ES doesn't support Quadrics and it has not a native GLUT library I find it rather difficult. So maybe someone came across the same Problem and can help me.

My first approach was to use Blender and export it as OBJ File and load it into my application. However there are 2 side effects: totally weird looking normals (kibotu.net/sphere.png) and most importantly no texture coordinates.

(I've used these Blender Export Options [kibotu.net/blenderobjoptions.png])

My second attempt was to use the freeglut library to do the job. Now I've got a nice looking sphere (kibotu.net/sphere5.png). However there are no texture coordinates either. Since it's last version was released on 27 November 2009 I very much doubt that there will be an update any time soon.

So after that I've tried to apply the wiki approach to calculate sphere uvs. However it looked like this kibotu.net/sphere2.png. I was searching every single stackoverflow thread after this problem and came across this uv approach. However there is no final solution. I've applied it to the freeglut code.

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

And the drawing algorithm:

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

Can anyone help me figuring this out please?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月棠 2024-12-12 19:35:34

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

我太懒/太忙(删除您想要的任何内容)而无法浏览您的代码,但您可能会在 Watt & 的第 6 章中找到答案。瓦特的“高级动画和渲染技术”。它提供了一些简单的方法来为球体生成合适的 UV 坐标。

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

You should be able to take any triangle mesh for a (unit) sphere and apply a mapping from vertex (X,Y,Z) to (UV).

I'm too lazy / busy (delete whichever you wish) to go through your code, but you might find the answer in chapter 6 of Watt & Watt's "Advanced Animation and Rendering Techniques". It gives some simple approaches to generating suitable UV coords for spheres.

IIRC, to avoid too much distortion at the poles, their mapping uses sine to squeeze/stretch the latitude mapping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文