2012-07-07 72 views
2

我想在Android上的openGL ES 2.0中繪製一個球體。我已經看過相關的問題,並嘗試了一些他們的代碼,但我仍然無法實現它的工作。在OpenGL ES 2.0中繪製一個球體

基於Android developer examplesthis code found on gamedev.net我想出了下面的代碼。但是它不能正確繪製;當使用glDrawArrays()呈現工程但結果不正確時,使用glDrawElements()時出現GL_INVALID_OPERATION錯誤。我在下面列出了我的緩衝區的內容。

Sphere.java

public class Sphere 
{ 
    private int stacks; 
    private int slices; 
    private float radius; 

    //Buffers 
    private FloatBuffer vertexBuffer; 
    private FloatBuffer colorBuffer; 
    private ShortBuffer indexBuffer; 

    //Buffer sizes in aantal bytes 
    private int vertexBufferSize; 
    private int colorBufferSize; 
    private int indexBufferSize; 

    private int vertexCount; 

    private int program; 

    static final int FLOATS_PER_VERTEX = 3; // Het aantal floats in een vertex (x, y, z) 
    static final int FLOATS_PER_COLOR = 4; // Het aantal floats in een kleur (r, g, b, a) 
    static final int SHORTS_PER_INDEX = 2; 
    static final int BYTES_PER_FLOAT = 4; 
    static final int BYTES_PER_SHORT = 2; 

    static final int BYTES_PER_VERTEX = FLOATS_PER_VERTEX * BYTES_PER_FLOAT; 
    static final int BYTES_PER_COLOR = FLOATS_PER_COLOR * BYTES_PER_FLOAT; 
    static final int BYTES_PER_INDEX_ENTRY = SHORTS_PER_INDEX * BYTES_PER_SHORT; 

    // Set color with red, green, blue and alpha (opacity) values 
    private float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f }; 

    public Sphere(float radius, int stacks, int slices) 
    { 
     this.stacks = stacks; 
     this.slices = slices; 
     this.radius = radius; 

     vertexCount   = (stacks+1) * (slices+1); 
     vertexBufferSize = vertexCount * BYTES_PER_VERTEX; 
     colorBufferSize  = vertexCount * BYTES_PER_COLOR; 
     indexBufferSize  = vertexCount * BYTES_PER_INDEX_ENTRY; 

     program = GLHelpers.createProgram(); 
     if (program == 0) { 
      return; 
     } 
     GLHelpers.checkGlError("program"); 

     // Setup vertex-array buffer. Vertices in float. A float has 4 bytes. 
     vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     colorBuffer = ByteBuffer.allocateDirect(colorBufferSize).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     indexBuffer = ByteBuffer.allocateDirect(indexBufferSize).order(ByteOrder.nativeOrder()).asShortBuffer();  

     generateSphereCoords(radius, stacks, slices); 

     vertexBuffer.position(0); 
     colorBuffer.position(0); 
     indexBuffer.position(0); 
    } 


    public void draw(float[] modelViewProjectionMatrix) 
    { 
     GLES20.glUseProgram(program); 

     GLHelpers.checkGlError("useprogram"); 

     int positionHandle = GLES20.glGetAttribLocation(program, "a_Position"); 
     GLES20.glEnableVertexAttribArray(positionHandle); 
     GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, BYTES_PER_VERTEX, vertexBuffer); 
     GLHelpers.checkGlError("pos"); 

     //int colorHandle = GLES20.glGetAttribLocation(program, "a_Color"); 
     //GLES20.glEnableVertexAttribArray(colorHandle); 
     //GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, BYTES_PER_COLOR, colorBuffer); 
     //GLHelpers.checkGlError("color"); 

     int matrixHandle = GLES20.glGetUniformLocation(program, "u_Matrix"); 
     GLES20.glUniformMatrix4fv(matrixHandle, 1, false, modelViewProjectionMatrix, 0); 

     /* 
     * When using glDrawArrays rendering works but the results are not correct, when using glDrawElements I get an GL_INVALID_OPERATION error. 
     */ 
     GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexBuffer.capacity(), GLES20.GL_SHORT, indexBuffer); 
     //GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); 

     GLHelpers.checkGlError("draw"); 

     // Disable vertex array 
     GLES20.glDisableVertexAttribArray(positionHandle); 
     //GLES20.glDisableVertexAttribArray(colorHandle); 
    } 

    private void generateSphereCoords(float radius, int stacks, int slices) 
    { 
     for (int stackNumber = 0; stackNumber <= stacks; ++stackNumber) 
     { 
      for (int sliceNumber = 0; sliceNumber < slices; ++sliceNumber) 
      { 
       float theta = (float) (stackNumber * Math.PI/stacks); 
       float phi = (float) (sliceNumber * 2 * Math.PI/slices); 
       float sinTheta = FloatMath.sin(theta); 
       float sinPhi = FloatMath.sin(phi); 
       float cosTheta = FloatMath.cos(theta); 
       float cosPhi = FloatMath.cos(phi); 
       vertexBuffer.put(new float[]{radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta}); 
      } 
     } 

     for (int stackNumber = 0; stackNumber < stacks; ++stackNumber) 
     { 
      for (int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber) 
      { 
       indexBuffer.put((short) ((stackNumber * slices) + (sliceNumber % slices))); 
       indexBuffer.put((short) (((stackNumber + 1) * slices) + (sliceNumber % slices))); 
      } 
     } 
    } 
} 

GLHelpers.java

public class GLHelpers 
{ 
    private static final String TAG = "GLHelpers"; 

    private static final String VERTEX_SHADER_CODE = 
      "uniform mat4 u_Matrix;" + 
      "attribute vec4 a_Position;" + 
      "attribute vec4 a_Color;" + 
      "varying vec4 v_Color;" + 
      "void main() {" + 
      " v_Color = a_Color;" + 
      " gl_Position = a_Position * u_Matrix;" + 
      "}"; 

    private static final String FRAGMENT_SHADER_CODE = 
     "precision mediump float;" + 
     "varying vec4 v_Color;" + 
     "void main() {" + 
     " gl_FragColor = v_Color;" + 
     "}"; 

    private static int loadShader(int shaderType, String source) 
    { 
     int shader = GLES20.glCreateShader(shaderType); 
     if (shader != 0) { 
      GLES20.glShaderSource(shader, source); 
      GLES20.glCompileShader(shader); 
      int[] compiled = new int[1]; 
      GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 
      if (compiled[0] == 0) 
      { 
       Log.e(TAG, "Could not compile shader " + shaderType + ":"); 
       Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); 
       GLES20.glDeleteShader(shader); 
       shader = 0; 
      } 
     } 
     return shader; 
    } 

    public static int createProgram() 
    { 
     int vertexShader = GLHelpers.loadShader(GLES20.GL_VERTEX_SHADER, GLHelpers.VERTEX_SHADER_CODE); 
     if (vertexShader == 0) 
      return 0; 

     int pixelShader = GLHelpers.loadShader(GLES20.GL_FRAGMENT_SHADER, GLHelpers.FRAGMENT_SHADER_CODE); 
     if (pixelShader == 0) 
      return 0; 

     int program = GLES20.glCreateProgram(); 
     if (program != 0) { 
      GLES20.glAttachShader(program, vertexShader); 
      GLHelpers.checkGlError("glAttachShader"); 
      GLES20.glAttachShader(program, pixelShader); 
      GLHelpers.checkGlError("glAttachShader"); 
      GLES20.glLinkProgram(program); 
      int[] linkStatus = new int[1]; 
      GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); 
      if (linkStatus[0] != GLES20.GL_TRUE) 
      { 
       Log.e(TAG, "Could not link program: "); 
       Log.e(TAG, GLES20.glGetProgramInfoLog(program)); 
       GLES20.glDeleteProgram(program); 
       program = 0; 
      } 
     } 
     return program; 
    } 

    public static void checkGlError(String glOperation) 
    { 
     int error; 
     while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) 
     { 
      Log.e(TAG, glOperation + ": glError " + error); 
      throw new RuntimeException(glOperation + ": glError " + error); 
     } 
    } 
} 

vertexBuffer

X    Y    Z 
0.0,   0.0,   1.0, 
0.0,   0.0,   1.0, 
-0.0,   0.0,   1.0, 
-0.0,   -0.0,   1.0, 
0.0,   -0.0,   1.0, 
0.58778524,  0.0,   0.809017, 
0.18163562,  0.559017,  0.809017, 
-0.4755283,  0.34549147,  0.809017, 
-0.4755282,  -0.34549156, 0.809017, 
0.18163571,  -0.55901694, 0.809017, 
0.95105654,  0.0,   0.30901697, 
0.29389262,  0.90450853,  0.30901697, 
-0.769421,  0.55901694,  0.30901697, 
-0.76942086, -0.5590171,  0.30901697, 
0.29389274,  -0.9045085,  0.30901697, 
0.9510565,  0.0,   -0.30901703, 
0.2938926,  0.9045085,  -0.30901703, 
-0.7694209,  0.5590169,  -0.30901703, 
-0.7694208,  -0.55901706, -0.30901703, 
0.29389274,  -0.9045084,  -0.30901703, 
0.5877852,  0.0,   -0.80901706, 
0.1816356,  0.55901694,  -0.80901706, 
-0.47552824, 0.3454914,  -0.80901706, 
-0.47552818, -0.34549153, -0.80901706, 
0.1816357,  -0.5590169,  -0.80901706, 
-8.742278E-8, -0.0,   -1.0, 
-2.7015123E-8, -8.3144E-8,  -1.0, 
7.0726514E-8, -5.138581E-8, -1.0, 
7.072651E-8, 5.138583E-8, -1.0, 
-2.7015135E-8, 8.3143995E-8, -1.0, 
0.0,   0.0,   0.0, 
0.0,   0.0,   0.0, 
0.0,   0.0,   0.0, 
0.0,   0.0,   0.0, 
0.0,   0.0,   0.0, 
0.0,   0.0,   0.0 

內容的indexBuffer

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
012的內容

結果使用glDrawArrays()時:

result

+3

如果你只是想要一個光滑的球體,你也許可以做到這一點,只有兩個三角形作爲方式的騙子,我在描述[這個答案](http://stackoverflow.com/a/10506172/19679)。 – 2012-07-08 17:41:33

回答

1

你設置vertexCountlat * lon * bytes per float,這看起來很奇怪我。

我想你錯誤地命名了這個變量,因爲頂點的數量與每個浮點數的字節數無關。

你在glDrawArrays中使用了相同的變量,在我看來,它不會有精確的頂點數量。

+1

此外,整個球體是用_一個三角形風扇繪製的?我希望有兩個杆,然後可能有一些條。 – 2012-07-07 18:25:25

+0

感謝您的回答,代碼很混亂,問題可能會更好。我用更好的代碼和更多細節更新了我的問題。 – christiaanderidder 2012-07-08 10:12:58

3

如所承諾的工作代碼創建領域:

public static Model3D createSphere(float radius, int stacks, int slices) 
    { 
     int vertexCount = (stacks + 1) * (slices + 1); 
     FloatBuffer vertexBuffer  = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_VERTEX).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     FloatBuffer normalBuffer  = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_NORMAL).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     FloatBuffer textureCoordBuffer = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_TEXTURE_COORD).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
     ShortBuffer indexBuffer   = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_TRIANGLE_INDEX).order(ByteOrder.nativeOrder()).asShortBuffer(); 

     for (int stackNumber = 0; stackNumber <= stacks; ++stackNumber) 
     { 
      for (int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber) 
      { 
       float theta = (float) (stackNumber * Math.PI/stacks); 
       float phi = (float) (sliceNumber * 2 * Math.PI/slices); 
       float sinTheta = FloatMath.sin(theta); 
       float sinPhi = FloatMath.sin(phi); 
       float cosTheta = FloatMath.cos(theta); 
       float cosPhi = FloatMath.cos(phi); 

       float nx = cosPhi * sinTheta; 
       float ny = cosTheta; 
       float nz = sinPhi * sinTheta; 


       float x = radius * nx; 
       float y = radius * ny; 
       float z = radius * nz; 

       float u = 1.f - ((float)sliceNumber/(float)slices); 
       float v = (float)stackNumber/(float)stacks; 



       normalBuffer.put(nx); 
       normalBuffer.put(ny); 
       normalBuffer.put(nz); 

       vertexBuffer.put(x); 
       vertexBuffer.put(y); 
       vertexBuffer.put(z); 

       textureCoordBuffer.put(u); 
       textureCoordBuffer.put(v); 
      } 
     } 

     for (int stackNumber = 0; stackNumber < stacks; ++stackNumber) 
     { 
      for (int sliceNumber = 0; sliceNumber < slices; ++sliceNumber) 
      { 
       int second = (sliceNumber * (stacks + 1)) + stackNumber; 
       int first = second + stacks + 1; 

       //int first = (stackNumber * slices) + (sliceNumber % slices); 
       //int second = ((stackNumber + 1) * slices) + (sliceNumber % slices); 

       indexBuffer.put((short) first); 
       indexBuffer.put((short) second); 
       indexBuffer.put((short) (first + 1)); 

       indexBuffer.put((short) second); 
       indexBuffer.put((short) (second + 1)); 
       indexBuffer.put((short) (first + 1)); 
      } 
     } 

     vertexBuffer.rewind(); 
     normalBuffer.rewind(); 
     indexBuffer.rewind(); 
     textureCoordBuffer.rewind(); 

     Model3D sphere = new Model3D().setVertexBuffer(vertexBuffer) 
             .setNormalBuffer(normalBuffer) 
             .setIndexBuffer(indexBuffer) 
             .setTexture(R.drawable.earth) 
             .setTextureCoordBuffer(textureCoordBuffer) 
             .setDiffuseLighting(-3f, 2.3f, 2f); 
     return sphere; 

    } 
+1

什麼是Model3D? – AAverin 2016-10-02 18:54:18