2015-07-09 185 views
1

我一直致力于在Android的OpenGL ES 2.0中使用Triangle Strips渲染球体。当球体旋转时,我遇到了一个问题,它本身似乎是重叠的。OpenGL ES 2球体渲染

Sphere Issue

我的用于创建顶点一览表代码是

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

我的用于渲染乘以若干观看和透视的代码矩阵在一起,然后执行此:

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

渲染中涉及很多不同的部分。然而,我认为问题出现在顶点世代。

回答

0

下面的代码片段将生成的顶点,法线贴图坐标&顶点指数的球体在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; 
      } 
     } 
    } 

根据您的代码结构,您可能需要重构代码,以适应您的目的,但一般来说,顶点,法线,纹理坐标顶点索引将生成具有纹理和法线的球体(如果您使用的是照明或您有任何其他法线需求)。

你将需要一个缓冲器,用于每个这种代码生成阵列,然后在下面的方式结合它们:

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

注:getParamId()返回OpenGL的变量,如位置产生的数字ID ,正常&着色器使用的texCoords。

一旦你做到了这一点,所有剩下来要做的使用索引缓冲区得出:

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

希望这将帮助你开始。