简体   繁体   English

OpenGL ES 2球形渲染

[英]OpenGL ES 2 Sphere Rendering

I've been working on rendering a sphere using Triangle Strips in OpenGL ES 2.0 for Android. 我一直在使用Android版OpenGL ES 2.0中的Triangle Strips渲染球体。 I'm having an issue where as the sphere rotates, it appears to be overlapping on itself. 我遇到一个问题,当球体旋转时,它似乎在自身上重叠。

领域问题

My code for creating the vertex list is 我创建顶点列表的代码是

private static final int FLOATS_PER_VERTEX = 5;
private final float[] vertexData;
private final List<DrawCommand> drawList = new ArrayList<>();
private int offset = 0;


private ObjectBuilder(int sizeInVertices)
{
    vertexData = new float[sizeInVertices * FLOATS_PER_VERTEX];
}


private void appendSphere(double radius, int depth)
{
double x, y, z, h, altitude, azimuth;

// Ensure that the depth is between 1 and MAX_DEPTH
int clampDepth = Math.max(1, Math.min(5, depth));

// Calculate the sphere values
int numStrips = (int) Math.pow(2, clampDepth - 1) * 5;

final int numVerticesPerStrip = (int) Math.pow(2, clampDepth) * 3;

double altitudeStepAngle = ONE_TWENTY_DEGREES / Math.pow(2, clampDepth);
double azimuthStepAngle = THREE_SIXTY_DEGREES / numStrips;

// Loop through each strip
for (int i = 0; i < numStrips; i++)
{
    final int startVertex = offset / FLOATS_PER_VERTEX;

    // Calculate the position of the first vertex in the strip
    altitude = NINETY_DEGREES;
    azimuth = i * azimuthStepAngle;

    // Draw the rest of the strip
    for (int j = 0; j < numVerticesPerStrip; j += 2)
    {
        // First point - Vertex.
        y = radius * Math.sin(altitude);
        h = radius * Math.cos(altitude);
        z = h * Math.sin(azimuth);
        x = h * Math.cos(azimuth);
        vertexData[offset++] = (float) x;
        vertexData[offset++] = (float) y;
        vertexData[offset++] = (float) z;

        // First point - Texture.
        vertexData[offset++] = (float) (1 - azimuth / THREE_SIXTY_DEGREES);
        vertexData[offset++] = (float) (1 - (altitude + NINETY_DEGREES) / ONE_EIGHTY_DEGREES);

        // Second point - Vertex.
        altitude -= altitudeStepAngle;
        azimuth -= azimuthStepAngle / 2.0;
        y = radius * Math.sin(altitude);
        h = radius * Math.cos(altitude);
        z = h * Math.sin(azimuth);
        x = h * Math.cos(azimuth);
        vertexData[offset++] = (float) x;
        vertexData[offset++] = (float) y;
        vertexData[offset++] = (float) z;

        // Second point - Texture.
        vertexData[offset++] = (float) (1 - azimuth / THREE_SIXTY_DEGREES);
        vertexData[offset++] = (float) (1 - (altitude + NINETY_DEGREES) / ONE_EIGHTY_DEGREES);

        azimuth += azimuthStepAngle;
    }

    drawList.add(new DrawCommand()
    {
        @Override
        public void draw()
        {
            glDrawArrays(GL_TRIANGLE_STRIP, startVertex, numVerticesPerStrip);
        }
    });
}
}

My code for rendering multiplies a number of viewing and perspective matrices together, and then does this: 我的渲染代码将多个视图矩阵和透视图矩阵相乘,然后执行以下操作:

positionObjectInScene(0f, 0f, 0f);
textureProgram.useProgram();
textureProgram.setUniforms(modelViewProjectionMatrix, texture);
planet.bindData(textureProgram);
glFrontFace(GL_CW);
planet.draw();

There's obviously a lot of different parts involved in the rendering. 渲染中显然涉及很多不同的部分。 I believe the issue is in the vertex generation, however. 我相信问题出在顶点世代。

The following code snippet will generate the vertices, normals, texture coordinates & vertex indexes for a sphere to be rendered in OpenGL-ES: 以下代码段将为要在OpenGL-ES中渲染的球体生成顶点,法线,纹理坐标和顶点索引:

public float[] mVertices;
public float[] mNormals;
public float[] mTexture;
public char[] mIndexes;

// rings defines how many circles exists from the bottom to the top of the sphere
// sectors defines how many vertexes define a single ring
// radius defines the distance of every vertex from the center of the sphere.
public void generateSphereData(int totalRings, int totalSectors, float radius)
    {
        mVertices = new float[totalRings * totalSectors * 3];
        mNormals = new float[totalRings * totalSectors * 3];
        mTexture = new float[totalRings * totalSectors * 2];
        mIndexes = new char[totalRings * totalSectors * 6];

        float R = 1f / (float)(totalRings-1);
        float S = 1f / (float)(totalSectors-1);
        int r, s;

        float x, y, z;
        int vertexIndex = 0, textureIndex = 0, indexIndex = 0, normalIndex = 0;

        for(r = 0; r < totalRings; r++)
        {
            for(s = 0; s < totalSectors; s++)
            {
                y = (float)Math.sin((-Math.PI / 2f) + Math.PI * r * R );
                x = (float)Math.cos(2f * Math.PI * s * S) * (float)Math.sin(Math.PI * r * R );
                z = (float)Math.sin(2f * Math.PI * s * S) * (float)Math.sin(Math.PI * r * R );

                if (mTexture != null)
                {
                    mTexture[textureIndex] = s * S;
                    mTexture[textureIndex + 1] = r * R;

                    textureIndex += 2;
                }

                mVertices[vertexIndex] = x * radius;
                mVertices[vertexIndex + 1] = y * radius;
                mVertices[vertexIndex + 2] = z * radius;

                vertexIndex += 3;

                mNormals[normalIndex] = x;
                mNormals[normalIndex + 1] = y;
                mNormals[normalIndex + 2] = z;

                normalIndex += 3;
            }
        }


        int r1, s1;
        for(r = 0; r < totalRings ; r++)
        {
            for(s = 0; s < totalSectors ; s++)
            {
                r1 = (r + 1 == totalRings) ? 0 : r + 1;
                s1 = (s + 1 == totalSectors) ? 0 : s + 1;

                mIndexes[indexIndex] = (char)(r * totalSectors + s);
                mIndexes[indexIndex + 1] = (char)(r * totalSectors + (s1));
                mIndexes[indexIndex + 2] = (char)((r1) * totalSectors + (s1));

                mIndexes[indexIndex + 3] = (char)((r1) * totalSectors + s);
                mIndexes[indexIndex + 4] = (char)((r1) * totalSectors + (s1));
                mIndexes[indexIndex + 5] = (char)(r * totalSectors + s);
                indexIndex += 6;
            }
        }
    }

Depending on your code structure, you might need to refactor the code to suit your purposes, but in general, the vertices, normals, texture coordinates & vertex indexes will generate a sphere with a texture and normals (if you're using lighting or you have any other need for normals). 根据您的代码结构,您可能需要重构代码以适合您的目的,但是通常,顶点,法线,纹理坐标和顶点索引会生成一个带有纹理和法线的球体(如果您使用照明或对法线还有其他需求)。

You will need to make a Buffer for each of the arrays this code generates, then bind them in the following manner: 您需要为该代码生成的每个数组创建一个Buffer,然后以以下方式绑定它们:

    mVertexBuffer = ByteBuffer.allocateDirect(mVertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mVertexBuffer.put(mVertexArray).position(0);

    mIndexBuffer = ByteBuffer.allocateDirect(mIndexArray.length * 4).order(ByteOrder.nativeOrder()).asCharBuffer();
    mIndexBuffer.put(mIndexArray).position(0);

    mTextureCoordinateBuffer = ByteBuffer.allocateDirect(mTextureCoordinatesArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mTextureCoordinateBuffer.put(mTextureCoordinatesArray).position(0);

    mNormalBuffer = ByteBuffer.allocateDirect(mNormalArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mNormalBuffer.put(mNormalArray).position(0);


    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(getParamId(PARAM_VERTEX_POSITION), 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
    GLES20.glEnableVertexAttribArray(getParamId(PARAM_VERTEX_POSITION));

    normalBuffer.position(0);
    GLES20.glVertexAttribPointer(getParamId(PARAM_VERTEX_NORMAL), 3, GLES20.GL_FLOAT, false, 0, normalBuffer);
    GLES20.glEnableVertexAttribArray(getParamId(PARAM_VERTEX_NORMAL));

    textureCoordinateBuffer.position(0);
    GLES20.glVertexAttribPointer(getParamId(PARAM_VERTEX_TEXTURE_COORDINATES), 2, GLES20.GL_FLOAT, false, 0, textureCoordinateBuffer);
    GLES20.glEnableVertexAttribArray(getParamId(PARAM_VERTEX_TEXTURE_COORDINATES));

Note: getParamId() returns the numerical id that OpenGL generated for variables such as position, normal & texCoords which the shaders use. 注意: getParamId()返回OpenGL为着色器使用的位置,法线和texCoords等变量生成的数字ID。

Once you've done this, all that's left to do is draw using the index buffer: 完成此操作后,剩下要做的就是使用索引缓冲区进行绘制:

GLES20.glDrawElements(GLES20.GL_TRIANGLES, mIndexArray.length, GLES20.GL_UNSIGNED_SHORT, mIndexBuffer);

Hope this will help you get started. 希望这会帮助您入门。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM