Just Google "It"

Loading...

Sunday, April 13, 2014

Android Setting up OpenGLES 2.0 Environment - Gravity with Object Bounce

This is just a quick look at how I setup my Android OpenGLES 2.0 environment using my Obj File Importer to create a simple gravity playing game.

Below is just the base code I used to create my gravity and bounce simulation
  1.     float TERMINAL_VELOCITY = -2;
  2.     float speed = 0;
  3.     float GRAVITY = -0.25f;
  4.     
  5. private float calcGravity(float last, int i) {
  6. // TODO Auto-generated method stub
  7. float current;
  8. double s = objectValues[i][3];
  9. if (s < TERMINAL_VELOCITY) { 
  10.          s = TERMINAL_VELOCITY; 
  11. } else if(-s > -TERMINAL_VELOCITY){
  12. s = -TERMINAL_VELOCITY; 
  13.         } else {
  14.          s += GRAVITY;
  15.         }
  16. if(last <= bottomShelf){
  17. s = -(-s/4 * objectValues[i][2]);
  18. if(objectValues[i][2] < 0){
  19. objectValues[i][2] += 0.5;
  20. }
  21. }
  22.     
  23.         objectValues[i][3] = (float) s;
  24. current = last + objectValues[i][3];
  25. return current;
  26. }


Below is the whole class file used in the GLRenderer. I kept the couple bottom methods to show one way I am accessing the change of environment variables for OpenGLES to use via touch events in the custom GLSurfaceView.
  1. public class GLRenderer implements Renderer {
  2.     
  3. static String TAG = "Blender Importer";

  4.   int howManyObjects = 5;

  5.     // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
  6.     private final float[] mMVPMatrix = new float[16];
  7.     private final float[] mplatformVPMatrix = new float[16];
  8.     float[][]scratch;
  9.     
  10.     private final float[] mProjectionMatrix = new float[16];
  11.     private final float[] mViewMatrix = new float[16];
  12.     private final float[] mRotationMatrix = new float[16];

  13.     private float mAngle;
  14.     
  15.     private ObjFileImport[] objFileArray;
  16. private ObjFileImport platform;
  17. private Context c;
  18. private SharedPreferences prefs;
  19. private String currentObjName;
  20. private boolean changed = false;
  21. private long lastTime;
  22.     float bottomShelf = -20;
  23.     float objectOffset = 3;
  24.     
  25.     float[][] objectValues = new float[howManyObjects][4];
  26.     
  27. public GLRenderer(Context context)
  28. {
  29. c = context;
  30. prefs = PreferenceManager.getDefaultSharedPreferences(c);                 
  31. currentObjName = prefs.getString("currentObj", "cube.obj");
  32. for(int i = 0; i < objectValues.length; i++){
  33. objectValues[i][0] = 30; // Current height
  34. objectValues[i][1] = 30; // last height
  35. objectValues[i][2] = -(new Random().nextInt(15)); // bounce variable
  36. objectValues[i][3] = 0; // speed variable
  37. }
  38. scratch = new float[objectValues.length][16];
  39. }

  40. @Override
  41. public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
  42. {
  43. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);                 
  44. String usedObj = prefs.getString("currentObj", "cube.obj");
  45. String imgName = prefs.getString("currentImg", "cube");
  46. //instantiate items
  47. objFileArray = new ObjFileImport[objectValues.length];
  48. for(int i = 0; i < objectValues.length; i++){
  49. objFileArray[i] = new ObjFileImport(c, usedObj, imgName);
  50. }
  51. platform = new ObjFileImport(c, "platform.obj", "platform.png");
  52. //
  53. // Set the background clear color to gray.
  54. GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
  55. // Position the eye behind the origin.
  56. final float eyeX = 0.0f;
  57. final float eyeY = 0.0f;
  58. final float eyeZ = 10f;

  59. // We are looking toward the distance
  60. final float lookX = 0.0f;
  61. final float lookY = 0.0f;
  62. final float lookZ = -10.0f;

  63. // Set our up vector. This is where our head would be pointing were we holding the camera.
  64. final float upX = 0.0f;
  65. final float upY = 1.0f;
  66. final float upZ = 0.0f;

  67. // Set the view matrix. This matrix can be said to represent the camera position.
  68. // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
  69. // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
  70. Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);       
  71. }

  72. @Override
  73. public void onSurfaceChanged(GL10 glUnused, int width, int height) 
  74. {
  75. // Set the OpenGL viewport to the same size as the surface.
  76. GLES20.glViewport(0, 0, width, height);

  77. // Create a new perspective projection matrix. The height will stay the same
  78. // while the width will vary as per aspect ratio.
  79. final float ratio = (float) width / height;
  80. final float left = -ratio;
  81. final float right = ratio;
  82. final float bottom = -1.0f;
  83. final float top = 1.0f;
  84. final float near = 1.0f;
  85. final float far = 100.0f;

  86. Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
  87. lastTime = System.currentTimeMillis();
  88. }

  89. @Override
  90. public void onDrawFrame(GL10 glUnused){
  91. // long currentTime = System.currentTimeMillis();
  92. //      if (currentTime - lastTime >= 1000) { lastTime = currentTime; }
  93. //refresh items on change
  94. if(changed){
  95. if(!prefs.getString("currentObj", "cube.obj").equals(currentObjName)){
  96. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);                 
  97. String usedObj = prefs.getString("currentObj", "cube.obj");
  98. String imgName = prefs.getString("currentImg", "cube");  
  99. for(int i = 0; i < objectValues.length; i++){
  100. objFileArray[i] = new ObjFileImport(c, usedObj, imgName);
  101. }
  102. changed = false;
  103. }
  104. }
  105. //

  106.         // Draw background color
  107.         GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

  108.         // Set the camera position (View matrix)
  109.         Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
  110.         Matrix.translateM(mViewMatrix, 0, 0, shift, 0);  
  111.         // Calculate the projection and view transformation
  112.         
  113.         Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);                     
  114.         
  115.         //drawing platform
  116.         Matrix.multiplyMM(mplatformVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);     
  117.         
  118.         Matrix.setRotateM(mRotationMatrix, 0, 0, 0.0f, 1.0f, 0.0f);        
  119.         Matrix.translateM(mplatformVPMatrix, 0, 0, bottomShelf-objectOffset, distance);        
  120.         Matrix.multiplyMM(mplatformVPMatrix, 0, mplatformVPMatrix, 0, mRotationMatrix, 0);        
  121.         platform.draw(mplatformVPMatrix);
  122.         //end drawing platform

  123.                 
  124.         //start object drawing 
  125.         Matrix.setRotateM(mRotationMatrix, 0, mAngle, 1.0f, 1.0f, 1.0f);
  126.         
  127.         for(int i = 0; i < objectValues.length; i++){
  128.         objectValues[i][0] = calcGravity(objectValues[i][1], i);
  129.        
  130.             Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 
  131.             Matrix.translateM(mMVPMatrix, 0, 5 * i + (-howManyObjects*2), objectValues[i][0], distance);        
  132.             Matrix.multiplyMM(scratch[i], 0, mMVPMatrix, 0, mRotationMatrix, 0);
  133.             
  134.             objectValues[i][1] = objectValues[i][0];
  135.         }
  136.         
  137. for(int i = 0; i < objectValues.length; i++){
  138. objFileArray[i].draw(scratch[i]);
  139. }
  140.         //end object drawing
  141.         
  142.         //refresh/change environment variables for motion
  143.         mAngle = -mAngle / 100;
  144.         angleRotate += 1;
  145.         mAngle += angleRotate ;
  146.         //
  147. }

  148.     float GRAVITY = -0.25f;
  149.     float TERMINAL_VELOCITY = -2;
  150.     float speed = 0;
  151.     
  152. private float calcGravity(float last, int i) {
  153. // TODO Auto-generated method stub
  154. float current;
  155. double s = objectValues[i][3];
  156. if (s < TERMINAL_VELOCITY) { 
  157.         s = TERMINAL_VELOCITY; 
  158. } else if(-s > -TERMINAL_VELOCITY){
  159. s = -TERMINAL_VELOCITY; 
  160.         } else {
  161.         s += GRAVITY;
  162.         }
  163. if(last <= bottomShelf){
  164. s = -(-s/4 * objectValues[i][2]);
  165. if(objectValues[i][2] < 0){
  166. objectValues[i][2] += 0.5;
  167. }
  168. }
  169.    
  170.         objectValues[i][3] = (float) s;
  171. current = last + objectValues[i][3];
  172. return current;
  173. }

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

  181.     public float getAngle() {
  182.         return mAngle;
  183.     }

  184.     public void setAngle(float angle) {
  185.         mAngle = angle;
  186.     }

  187. public void changedObj() {
  188. // TODO Auto-generated method stub
  189. changed  = true;
  190. }
  191. float distance = 35;
  192. float shift = 0;
  193. float angleRotate = 0;

  194. public void moveObjectOnZ(float change) {
  195. // TODO Auto-generated method stub
  196. if(change > 0){
  197. distance += 0.5;
  198. Log.d("moveObjectOnZ", "Move farther " + String.valueOf(distance));
  199. } else if(change < 0){
  200. distance -= 0.5;
  201. Log.d("moveObjectOnZ", "Move closer " + String.valueOf(distance));
  202. }
  203. }
  204. public void moveObjectOnX(float change) {
  205. // TODO Auto-generated method stub
  206. if(change > 0){
  207. shift += 0.1;
  208. Log.d("moveObjectOnY", "Camera move up " + String.valueOf(shift));
  209. } else if(change < 0){
  210. shift -= 0.1;
  211. Log.d("moveObjectOnY", "Camera move down " + String.valueOf(shift));
  212. }
  213. }

  214. public void changeObject() {
  215. // TODO Auto-generated method stub
  216. float[] newColors = null;
  217. for(int i = 0; i < objectValues.length; i++){
  218. objectValues[i][0] = 30;
  219. objectValues[i][1] = 30;
  220. objectValues[i][2] = -(new Random().nextInt(15));//-4
  221. newColors = new float[objFileArray[i].lightColor.length];
  222. }
  223. // R G B A
  224.  //float[] newColors = new float[objFile.lightColor.length];  
  225.  int count = 0;
  226.  int colorChange = 0;
  227.  Random r = new Random();
  228.  int cc = r.nextInt(100);
  229.  float ccf = ((float) cc) / 100;
  230.  for(int i = 0; i < newColors.length; i++){  
  231.  if(count == 0){
  232.  newColors[i] = ccf;
  233.  } else if(count == 1){
  234.  newColors[i] = ccf;
  235.  } else if(count == 2){
  236.  newColors[i] = ccf;
  237.  } else if(count == 3){
  238.  newColors[i] = 1.0f;
  239.  count = -1;
  240.  }
  241.  count++;
  242.  if(colorChange == 5){
  243.  cc = r.nextInt(100);
  244.  ccf = (float) cc;
  245.  colorChange = -1;
  246.  } else {
  247.  colorChange++;
  248.  }
  249.  }
  250.  for(int i = 0; i < objectValues.length; i++){
  251.  objFileArray[i].lightColor = newColors;
  252.  }
  253. }

  254. }

Sample images of what my obj file importer does along with this GLRenderer.




Download this sample app from the Google Play Store at:


Android Obj File Importer

This is just the source code I used for creating game objects from an imported Obj file type. I first used Blender to create my object and textured it as I feel. Then I select the object in the 3D View and go to File >> Export then export it as .obj file.




Export the file with the following options selected to gather the Normals, texture UVs, and the vertix coordinates properly.



Create your 3D OpenGl environment and create an object to this contructor and just call the draw method form this class file.

BTW, you will need to create yourself a way to actually save the file name of the obj file to your Preferences or just change the way you want to actually supply the obj file to the class file below.

The class file below references:

1) Shader files located in the 'raw' directory
2) Texture images located in the 'drawable' directory
3) Obj Files located in the 'assets' directory
  1. public class ObjFileImport {
  2.   String objText;
  3.   String TAG = "ObjFileImport";
  4.    
  5.   int selectedDrawable;
  6.   String usedObj;
  7.   
  8.   String vertexShaderCode;
  9.   String fragmentShaderCode;

  10.    private int mProgram;
  11.    private int mPositionHandle;
  12.    private int mColorHandle;
  13.    private int mMVPMatrixHandle;
  14.    private int mNormalCoordLoc;
  15.    private int mTexCoordLoc;
  16.    private int mSamplerLoc;
  17.   
  18.   FloatBuffer vertexBuffer;
  19.   FloatBuffer textureBuffer;
  20.   FloatBuffer normalBuffer;
  21.   FloatBuffer colorBuffer;
  22.   ShortBuffer indexBuffer;
  23.   ShortBuffer textureindexBuffer;
  24.   ShortBuffer normalindexBuffer;
  25.   
  26.   boolean vt = false;
  27.   boolean vn = false;
  28.   
  29.   int faces = 0;
  30.   
  31.   float[] vertices;
  32.   private List<Float> vList = new ArrayList<Float>();
  33.   
  34.   private float[] textureVertices;
  35.   private List<Float> vtList = new ArrayList<Float>();
  36.   
  37.   private float[] normalVertices;
  38.   private List<Float> vnList = new ArrayList<Float>();
  39.   
  40.   float[] lightColor = {0.1f, 0.0f, 0.0f, 1.0f};
  41.   
  42.   private short[] textures;
  43.   private List<Short> vtIndices = new ArrayList<Short>();
  44.   
  45.   private short[] normals;
  46.   private List<Short> vnIndices = new ArrayList<Short>();
  47.   
  48.   short[] indices;
  49.   private List<Short> vIndices = new ArrayList<Short>();
  50.   
  51.   private float[] colors;
  52.  
  53.   int[] textureIDs = new int[1];
  54.   int[] normalIDs = new int[1];

  55.   private Context c;
  56.    
  57.   public ObjFileImport(Context context, String thisObj, String imgName) {
  58.   c = context;
  59.   vt = false;
  60.   vn = false;
  61.   
  62.   usedObj = thisObj;
  63.   selectedDrawable = c.getResources().getIdentifier("drawable/"+imgName.trim().replace(".png",""), null, c.getPackageName());
  64.      
  65.  AssetManager assetManager = c.getAssets();
  66.  BufferedReader bf;
  67.  try {
  68.  try {
  69. bf = new BufferedReader(new InputStreamReader(assetManager.open(usedObj)));
  70. } catch (Exception e) {
  71. // TODO Auto-generated catch block
  72. e.printStackTrace();
  73. bf = new BufferedReader(new InputStreamReader(assetManager.open("cube.obj")));
  74. usedObj = "cube.obj";
  75. }
  76.   
  77.  String line;
  78.  while ((line = bf.readLine()) != null){ 
  79.  objText += line;
  80.  if(line.startsWith("v ")){
  81.  String s = line.replace("v ", "");
  82.  String[] sp = s.trim().split(" ");
  83.  for(String p : sp){  
  84.  vList.add(Float.parseFloat(p.trim()));  
  85.  }    
  86.  }
  87.  if(line.startsWith("vt ")){
  88.  
  89.  String s = line.replace("vt ", "");
  90.  String[] sp = s.trim().split(" ");
  91.  for(String p : sp){    
  92.  vtList.add(Float.parseFloat(p.trim()));  
  93.  }    
  94.  }
  95.  if(line.startsWith("vn ")){
  96.  String s = line.replace("vn ", "");
  97.  String[] sp = s.trim().split(" ");
  98.  for(String p : sp){  
  99.  vnList.add(Float.parseFloat(p.trim()));  
  100.  }    
  101.  }
  102.  if(line.startsWith("f ")){    
  103.  String s = line.replace("f ", "");
  104.  String[] each = s.replace("f ", "").split(" ");
  105.  for(int i = 0; i < each.length; i++){
  106.  faces++;
  107.  String[] sp = each[i].split("/");    
  108.  /* the f in obj file is in format 
  109.   * 'v/vt/vn' for vertices / vertices of texture / vertices of normals
  110.   * or 
  111.   * 'v' for vertices
  112.   * or 
  113.   * 'v//vn' for vertices // vertices of normals
  114.   * 
  115.   */
  116.  if(sp.length == 1){
  117.  vIndices.add((short) (Short.parseShort(sp[0].trim()) - 1));
  118.    } else if(sp.length == 2){
  119.    
  120.    vIndices.add((short) (Short.parseShort(sp[0].trim()) - 1));
  121.    
  122.    vt = true;
  123.    vtIndices.add((short) (Short.parseShort(sp[1].trim()) - 1));
  124.    } else if(sp.length == 3 && !sp[1].equals("")){    
  125.    
  126.    vIndices.add((short) (Short.parseShort(sp[0].trim()) - 1));
  127.    
  128.    vt = true;
  129.    vtIndices.add((short) (Short.parseShort(sp[1].trim()) - 1));
  130.    
  131.    vn = true;
  132.    vnIndices.add((short) (Short.parseShort(sp[2].trim()) - 1));
  133.    } else if(sp.length == 3){
  134.    
  135.    vIndices.add((short) (Short.parseShort(sp[0].trim()) - 1));
  136.    
  137.    vn = true;
  138.    vnIndices.add((short) (Short.parseShort(sp[2].trim()) - 1));
  139.    }
  140.  }
  141.  }
  142.  }
  143.  
  144.  bf.close();
  145.  
  146.  faces = vIndices.size() / faces; //tells if its created using triangles or quads
  147.  int counter = -1;
  148.  
  149.  indices = new short[vIndices.size()];
  150.  for(int i = 0; i < vIndices.size(); i++){
  151.  indices[i] = vIndices.get(i);
  152.  }
  153.  
  154.  vertices = new float[vIndices.size()*3];
  155.  counter = -1; 
  156.  for(int i = 0; i < vIndices.size(); i++){  
  157.  int q = vIndices.get(i)*3;
  158.  counter++;
  159.  vertices[counter] = vList.get(q);
  160.  counter++;q++;
  161.  
  162.  vertices[counter] = vList.get(q);
  163.  counter++;q++;
  164.  
  165.  vertices[counter] = vList.get(q);
  166.  }    
  167.  
  168.  if(vt){
  169.  textures = new short[vtIndices.size()];
  170.  for(int i = 0; i < vtIndices.size(); i++){  
  171.  textures[i] = vtIndices.get(i);
  172.  }  
  173.  
  174.  counter = -1;
  175.  textureVertices = new float[vtIndices.size()*2];
  176.  for(int i = 0; i < vtIndices.size(); i++){
  177.  int q = vtIndices.get(i)*2;
  178.  counter++;
  179.  textureVertices[counter] = vtList.get(q);

  180.  counter++;q++;
  181.  textureVertices[counter] = vtList.get(q);
  182.  }
  183.    
  184.  if(vn){
  185.  
  186.  normals = new short[vnIndices.size()];
  187.  for(int i = 0; i < vnIndices.size(); i++){
  188.  normals[i] = vnIndices.get(i);  
  189.  }
  190.  
  191.  counter = -1;
  192.  normalVertices = new float[vnIndices.size()*3];
  193.  for(int i = 0; i < vnIndices.size(); i++){
  194.  int q = vnIndices.get(i)*3;
  195.  counter++;
  196.  normalVertices[counter] = vnList.get(q);
  197.  counter++;q++;
  198.  
  199.  normalVertices[counter] = vnList.get(q);
  200.  counter++;q++;
  201.  
  202.  normalVertices[counter] = vnList.get(q);
  203.  }
  204.  
  205.  }
  206.  
  207.  }

  208.  colors = new float[(vertices.length/3)*4];
  209.  int count = 0;
  210.  for(int i = 0; i < colors.length; i++){  
  211.  if(count == 0){
  212.  colors[i] = 0.99f;
  213.  } else if(count == 1){
  214.  colors[i] = 0.99f;
  215.  } else if(count == 2){
  216.  colors[i] = 0.49f;
  217.  } else if(count == 3){
  218.  colors[i] = 1.0f;
  219.  count = -1;
  220.  }
  221.  count++;
  222.  }
  223.  
  224.      
  225. } catch (IOException e) {
  226. // TODO Auto-generated catch block
  227. e.printStackTrace();
  228. }
  229.  
  230.  initializeObjBuffer();  
  231.  if(vt){
  232.  initializeObjTextureBuffer();
  233.  initializeObjNormalBuffer();  
  234.  } else {
  235.  initializeObjColorBuffer(); 
  236.  }
  237.  initializeShaders();
  238.    
  239.   }
  240.   
  241.   private void initializeShaders() {
  242. // TODO Auto-generated method stub
  243.         if(!vt){
  244.         mProgram = ShaderHelper.CreateandLink("vertexshadercode", "colorarrayshader", c, 
  245.         vertexShaderCode, fragmentShaderCode, mProgram, new String[]{"vPosition", "a_Color"},
  246.         selectedDrawable);         
  247.         } else {         
  248.         if(vn){
  249.             mProgram = ShaderHelper.CreateandLink("texturenormalvertexshader", "texturenormalfragmentshader", c, 
  250.             vertexShaderCode, fragmentShaderCode, mProgram, new String[]{"vPosition", "a_Color", "a_texCoord", "a_normal"},
  251.             selectedDrawable);      
  252.         } else {
  253.             mProgram = ShaderHelper.CreateandLink("texturevertexshader", "texturefragmentshader", c, 
  254.             vertexShaderCode, fragmentShaderCode, mProgram, new String[]{"vPosition", "a_Color", "a_texCoord"},
  255.             selectedDrawable);
  256.         } 
  257.         }
  258.         Log.d(TAG,  String.valueOf(mProgram));        
  259.    GLES20.glUseProgram(mProgram);
  260.    texID = TextureHelper.loadTexture(c, selectedDrawable);   
  261. }
  262.   
  263.   int texID;

  264.    public void draw(float[] mvpMatrix) {        
  265.    
  266. GLES20.glEnable(GLES20.GL_CULL_FACE);
  267. GLES20.glEnable(GLES20.GL_DEPTH_TEST);
  268.        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
  269.        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
  270.        if(vt){
  271.         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID);
  272.         mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "a_texCoord" );
  273.         mSamplerLoc = GLES20.glGetUniformLocation(mProgram, "s_texture" );
  274.         if(vn){
  275.         mNormalCoordLoc = GLES20.glGetAttribLocation(mProgram, "a_normal");
  276.         }
  277.        } else {
  278.         mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color");
  279.        }
  280.        
  281.        GLES20.glEnableVertexAttribArray(mPositionHandle);
  282.        if(vt){        
  283.         GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
  284.         if(vn){
  285.         GLES20.glEnableVertexAttribArray(mNormalCoordLoc);
  286.         }
  287.        } else {
  288.         GLES20.glEnableVertexAttribArray(mColorHandle);
  289.        }
  290.      
  291.        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);//vertexStride
  292.        
  293.        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
  294.        if(vt){                
  295.        GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);        
  296.        GLES20.glUniform1i( mSamplerLoc, 0);
  297.        if(vn){
  298.         GLES20.glVertexAttribPointer (mNormalCoordLoc, 3, GLES20.GL_FLOAT, false, 0, normalBuffer);
  299.        }
  300.        } else {
  301.         GLES20.glVertexAttribPointer (mColorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);
  302.        }                        
  303.        
  304.       GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, indices.length);
  305.         
  306.        GLES20.glDisableVertexAttribArray(mPositionHandle);
  307.        if(vt){        
  308.         GLES20.glDisableVertexAttribArray ( mTexCoordLoc );        
  309.         if(vn){
  310.         GLES20.glDisableVertexAttribArray(mNormalCoordLoc);
  311.         }
  312.        } else {
  313.         GLES20.glDisableVertexAttribArray(mColorHandle);
  314.        }
  315.   }
  316. private void initializeObjBuffer() {
  317. // TODO Auto-generated method stub
  318.      ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
  319.      vbb.order(ByteOrder.nativeOrder()); 
  320.      vertexBuffer = vbb.asFloatBuffer(); 
  321.      vertexBuffer.put(vertices);         
  322.      vertexBuffer.position(0);          
  323.      
  324.      // Setup index-array buffer. Indices in byte.
  325.      ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 3);
  326.      ibb.order(ByteOrder.nativeOrder());
  327.      indexBuffer = ibb.asShortBuffer();
  328.                       indexBuffer.put(indices);
  329.                       indexBuffer.position(0);
  330.           
  331. }
  332. private void initializeObjColorBuffer() {
  333. // TODO Auto-generated method stub
  334.    ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
  335.    cbb.order(ByteOrder.nativeOrder());
  336.    colorBuffer = cbb.asFloatBuffer(); 
  337.    colorBuffer.put(colors);         
  338.    colorBuffer.position(0);        
  339. }
  340. private void initializeObjTextureBuffer() {
  341. // TODO Auto-generated method stub
  342.    ByteBuffer tbb = ByteBuffer.allocateDirect(textureVertices.length * 4);
  343.    tbb.order(ByteOrder.nativeOrder());
  344.    textureBuffer = tbb.asFloatBuffer(); 
  345.    textureBuffer.put(textureVertices);
  346.    textureBuffer.position(0);           
  347.    
  348.    ByteBuffer itbb = ByteBuffer.allocateDirect(textures.length * 3);
  349.    itbb.order(ByteOrder.nativeOrder()); 
  350.    textureindexBuffer = itbb.asShortBuffer();
  351.    textureindexBuffer.put(textures);
  352.    textureindexBuffer.position(0);
  353. }
  354. private void initializeObjNormalBuffer() {
  355. // TODO Auto-generated method stub
  356.    ByteBuffer tbb = ByteBuffer.allocateDirect(normalVertices.length * 4);
  357.    tbb.order(ByteOrder.nativeOrder()); 
  358.    normalBuffer = tbb.asFloatBuffer(); 
  359.    normalBuffer.put(normalVertices);        
  360.    normalBuffer.position(0);          
  361.    
  362.    ByteBuffer itbb = ByteBuffer.allocateDirect(normals.length * 3);
  363.    itbb.order(ByteOrder.nativeOrder()); 
  364.    normalindexBuffer = itbb.asShortBuffer();
  365.    normalindexBuffer.put(normals);
  366.    normalindexBuffer.position(0);
  367.    
  368. }
  369.  
  370. }

Download this sample app from the Google Play Store at: