title: Android OpenGL ES 2.0: Cube model is not only distorted (perspective is wrong?), but also the faces are loaded incorrectly (vertices not correct?)
body: <p>I have come across some problems I'm not able to explain very well without you guys trying it out.</p>
  
  <p>I'm unable to get a cube to load correctly. I was able to make it rotate nicely on all axes, though. (plural of "axis" is "axes"?)</p>
  
  <p>I haven't ventured on with lighting and textures, so I'm sorry if you can't seem to make out the model yet.</p>
  
  <p>This is what it looks like right now (snapshot of a freely-spinning model):</p>
  
  <p><img src="https://i.stack.imgur.com/97Kop.png" alt="Snapshot of the cube. No depth shown yet."></p>
  
  <p>This is the expected outcome:</p>
  
  <p><img src="https://i.stack.imgur.com/335Uo.png" alt="Blender model. Expectations are too high, sir."></p>
  
  <p>This is the code for my <code>GLSurfaceView.Renderer</code>:</p>
  
  <pre><code>package dd.ww;
  
  import javax.microedition.khronos.egl.EGLConfig;
  import javax.microedition.khronos.opengles.GL10;
  import android.content.Context;
  import android.opengl.GLES20;
  import android.opengl.GLSurfaceView.Renderer;
  import android.opengl.Matrix;
  
  public class Render implements Renderer {
  
      private Context context;
      private Cube cube;
  
      private float[] modelViewProjectionMatrix = new float[16];
      private float[] projectionMatrix = new float[16];
      private float[] viewMatrix = new float[16];
      private float[] rotationMatrix = new float[16];
      private float angle = 0f;
  
      public Render(Context context) {
          this.context = context;
      }
  
      @Override
      public void onSurfaceCreated(GL10 unused, EGLConfig config) {
          GLES20.glClearColor(1f, 1f, 1f, 1f);
          cube = new Cube(context);
      }
  
      @Override
      public void onSurfaceChanged(GL10 unused, int width, int height) {
          GLES20.glViewport(0, 0, width, height);
          float ratio = (float) width / (float) height;
          Matrix.frustumM(projectionMatrix, 0, -3f, 3f, -3f, 3f, 1f, 10f);
      }
  
      @Override
      public void onDrawFrame(GL10 unused) {
          GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
          //Camera position
          Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -4f, 0f, 0f, 0f, 0f, 1f, 0f);
          // projection x view = modelView
          Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
          //Creating rotation matrix
          Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1f);
          //rotation x camera = modelView
          Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
          Matrix.setRotateM(rotationMatrix, 0, angle, 0f, -1f, 0f);
          Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
          Matrix.setRotateM(rotationMatrix, 0, angle, -1f, 0f, 0f);
          Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
  
          cube.draw(modelViewProjectionMatrix);
  
          angle += 0.7f;
          if (angle &gt; 360f)
              angle = 0f;
      }
  
  }
  </code></pre>
  
  <p>This is the code for the Cube class, along with its OBJ loader. The OBJ Loader is used for loading the OBJ model that was exported from Blender (which is the expected outcome of the Cube, shown in Blender.):</p>
  
  <pre><code>package dd.ww;
  
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.nio.ByteBuffer;
  import java.nio.ByteOrder;
  import java.nio.FloatBuffer;
  import java.nio.ShortBuffer;
  import java.util.ArrayList;
  import android.content.Context;
  import android.content.res.AssetManager;
  import android.opengl.GLES20;
  import android.util.Log;
  
  public class Cube {
      private Context context;
      private FloatBuffer vertexBuffer;
      private ShortBuffer indexBuffer;
  
      private int shaderProgram;
  
      //TODO: Go to Google Code, find OpenGL ES 2.0 Programming Guide source code, Android,
      //check in the ESShapes.java, and study the FloatBuffers...
  
      public Cube(Context c) {
          context = c;
          loadCube("cube/cube.obj");
      }
  
      private void loadCube(String filename) {
  
          ArrayList&lt;Float&gt; tempVertices = new ArrayList&lt;Float&gt;();
          //ArrayList&lt;Float&gt; tempNormals = new ArrayList&lt;Float&gt;();
          ArrayList&lt;Short&gt; vertexIndices = new ArrayList&lt;Short&gt;();
          //ArrayList&lt;Short&gt; normalIndices = new ArrayList&lt;Short&gt;();
  
          try {
              AssetManager manager = context.getAssets();
              BufferedReader reader = new BufferedReader(new InputStreamReader(manager.open(filename)));
              String line;
              while ((line = reader.readLine()) != null) {
                  if (line.startsWith("v")) {
                      tempVertices.add(Float.valueOf(line.split(" ")[1])); //vx
                      tempVertices.add(Float.valueOf(line.split(" ")[2])); //vy
                      tempVertices.add(Float.valueOf(line.split(" ")[3])); //vz
                  }
                  //              else if (line.startsWith("vn")) {
                  //                  tempNormals.add(Float.valueOf(line.split(" ")[1])); //nx
                  //                  tempNormals.add(Float.valueOf(line.split(" ")[2])); //ny
                  //                  tempNormals.add(Float.valueOf(line.split(" ")[3])); //nz
                  //              }
                  else if (line.startsWith("f")) {
  
                      /*
                      vertexIndices.add(Short.valueOf(tokens[1].split("/")[0])); //first point of a face
                      vertexIndices.add(Short.valueOf(tokens[2].split("/")[0])); //second point
                      vertexIndices.add(Short.valueOf(tokens[3].split("/")[0])); //third point
                      normalIndices.add(Short.valueOf(tokens[1].split("/")[2])); //first normal
                      normalIndices.add(Short.valueOf(tokens[2].split("/")[2])); //second normal
                      normalIndices.add(Short.valueOf(tokens[3].split("/")[2])); //third
                       */
                      //                  for (int i = 1; i &lt;= 3; i++) {
                      //                      //String[] s = tokens[i].split("/");
                      //                      vertexIndices.add(Short.valueOf());
                      //                      //normalIndices.add(Short.valueOf(s[2]));
                      //                  }
  
                      vertexIndices.add(Short.valueOf(line.split(" ")[1]));
                      vertexIndices.add(Short.valueOf(line.split(" ")[2]));
                      vertexIndices.add(Short.valueOf(line.split(" ")[3]));
                  }
              }
  
              float[] vertices = new float[tempVertices.size()];
              for (int i = 0; i &lt; tempVertices.size(); i++) {
                  Float f = tempVertices.get(i);
                  vertices[i] = (f != null ? f : Float.NaN);
              }
  
              short[] indices = new short[vertexIndices.size()];
              for (int i = 0; i &lt; vertexIndices.size(); i++) {
                  Short s = vertexIndices.get(i);
                  indices[i] = (s != null ? s : 1);
              }
  
              vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
              vertexBuffer.put(vertices).position(0);
  
              indexBuffer = ByteBuffer.allocateDirect(indices.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();
              indexBuffer.put(indices).position(0);
  
  
              int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
              GLES20.glShaderSource(vertexShader, vertexCode);
              GLES20.glCompileShader(vertexShader);
              int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
              GLES20.glShaderSource(fragmentShader, fragmentCode);
              GLES20.glCompileShader(fragmentShader);
  
              shaderProgram = GLES20.glCreateProgram();
              GLES20.glAttachShader(shaderProgram, vertexShader);
              GLES20.glAttachShader(shaderProgram, fragmentShader);
              GLES20.glLinkProgram(shaderProgram);
  
              int[] linked = new int[1];
              GLES20.glGetProgramiv(shaderProgram, GLES20.GL_LINK_STATUS, linked, 0);
              if (linked[0] == 0){
                  Log.d("DEBUG", "Shader code error.");
                  Log.d("DEBUG", GLES20.glGetProgramInfoLog(shaderProgram));
                  GLES20.glDeleteProgram(shaderProgram);
                  return;
              }
  
              GLES20.glDeleteShader(vertexShader);
              GLES20.glDeleteShader(fragmentShader);
  
  
  
  
          }
          catch (Exception e) {
              Log.d("DEBUG", "Error.", e);
          }
      }
  
      private String vertexCode = "" +
              "attribute vec4 a_position;  \n" +
              "uniform mat4 mvpMatrix;     \n" +
              "void main() {               \n" +
              "   gl_Position = a_position * mvpMatrix;\n" +
              "}                           \n";
  
      private String fragmentCode = "" +
              "precision mediump float;                   \n" +
              "void main() {                              \n" +
              "   gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" +
              "}                                          \n";
  
      private int attribute_Position;
      private int uniform_mvpMatrix;
  
      public void draw(float[] mvpMatrix){
          GLES20.glUseProgram(shaderProgram);
          attribute_Position = GLES20.glGetAttribLocation(shaderProgram, "a_position");
          GLES20.glVertexAttribPointer(attribute_Position, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer);
          GLES20.glEnableVertexAttribArray(attribute_Position);
          uniform_mvpMatrix = GLES20.glGetUniformLocation(shaderProgram, "mvpMatrix");
          GLES20.glUniformMatrix4fv(uniform_mvpMatrix, 1, false, mvpMatrix, 0);
          GLES20.glDrawElements(GLES20.GL_TRIANGLES, indexBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT, indexBuffer);
          GLES20.glDisableVertexAttribArray(attribute_Position);
      }
  }
  </code></pre>
  
  <p>And finally, here's the APK attachment (Uploaded to Mediafire, should not get removed. It's non-licensed freeware). The attached APK file is signed, exported straight from my project, and can only be run on Gingerbread or above. (This is what OpenGL ES 2.0 is for...):
  <a href="http://www.mediafire.com/?7gh6vaacx22xwbq" rel="nofollow noreferrer">Mediafire download link to the APK file.</a></p>
  
  <p>If anyone is willing to help me realize what I'm doing wrong, I'll be glad for the rest of my life. <a href="https://stackoverflow.com/questions/10625868/opengl-es-object-is-displaying-strangely-distorted-android">This question here is the closest that I find when searching on SO that has a 40% chance my problem is related to.</a> Unfortunately, he still has his model distorted. All the rest of the questions I found seems to be about textures not rendering correctly, translating the model around, etc. But I will try my best to find questions with similar problems as mine.</p>