2013-03-27 3 views
0

나는 이전에 VBO를 사용하기 위해 디스플레이 목록을 사용하여 작성한 OBJ 파서를 변환하려고 노력해 왔으며 외부의 도움없이 직접 문제를 파악할 수 있는지 알아보기 위해 시도했지만 지금은 코드를 너무 오래보고 오류를 찾을 수 없습니다.VBO에서 데이터를로드하는 내 OBJ 파서를 작성하여 단일 인덱스 목록과 일치하도록 데이터를 다시 정렬하는 방법은 무엇입니까?

이것은 OpenGLES 2.0을 통한 Android 앱이며 일부 삼각형이 화면에 표시되지만 올바른 장소에는 표시되지 않습니다. 나는 하나의 인덱스 목록을 기반으로 각 얼굴의 모든 요소를 ​​얻으려는 나의 시도가 정확하지 않고 결국 모든 것을 던지지 만 내 오류를 발견 할 수 없다는 느낌이 들었습니다.

본질적으로 OBJ 형식은 정점, 텍스처 좌표 및 법선 벡터에 대해 별도의 색인을 제공하기 때문에 서로 순서가 완전히 다른 3 개의 데이터 목록이 작성되지만 VBO는 각 부분을 참조합니다 단일 색인 목록을 기반으로합니다. 여기

누군가가 나를 도울 수 있도록하기 위해, 내 코드입니다 :

OBJToolkit :

public class OBJToolkit { 
    public static Mesh loadOBJ(String modelLocation) throws FileNotFoundException, IOException 
    { 
     Log.d("OBJToolkit", "Location searched for model: " + modelLocation); 

     ArrayList<Float> allVertices = new ArrayList<Float>(); 
     ArrayList<Float> allTextureCoors = new ArrayList<Float>(); 
     ArrayList<Float> allNormals = new ArrayList<Float>(); 

     ArrayList<Face> faces = new ArrayList<Face>(); 

     BufferedReader reader = new BufferedReader(new FileReader(new File(modelLocation))); 

     Mesh mesh = new Mesh(); 

     Log.d("OBJToolkit", "About to read the contents of the model"); 
     while (reader.ready()) 
     { 
      String line = reader.readLine(); 

      if (line == null) 
       break; 

      if (line.startsWith("v ")) 
      { 
       allVertices.add(Float.valueOf(line.split(" ")[1])); 
       allVertices.add(Float.valueOf(line.split(" ")[2])); 
       allVertices.add(Float.valueOf(line.split(" ")[3])); 
      } 

      if (line.startsWith("vt ")) 
      { 
       allTextureCoors.add(Float.valueOf(line.split(" ")[1])); 
       allTextureCoors.add(Float.valueOf(line.split(" ")[2])); 
      } 

      if (line.startsWith("vn ")) 
      { 
       allNormals.add(Float.valueOf(line.split(" ")[1])); 
       allNormals.add(Float.valueOf(line.split(" ")[2])); 
       allNormals.add(Float.valueOf(line.split(" ")[3])); 
      } 

      if (line.startsWith("f ")) 
      { 
       Face f = new Face(); 
       String[] lineArray = line.split(" "); 

       for (int index = 1; index < lineArray.length; index++) 
       { 
        String[] valueArray = lineArray[index].split("/"); 
        f.addVertexIndex(Integer.valueOf(valueArray[0])); 
        if (valueArray.length > 1) 
         f.addTextureIndex(Integer.valueOf(valueArray[1])); 
        if (valueArray.length > 2) 
         f.addNormalIndex(Integer.valueOf(valueArray[2])); 
       } 
       faces.add(f); 
      } 
     } 
     reader.close(); 

     ArrayList<Float> verticesInOrder = new ArrayList<Float>(); 
     ArrayList<Integer> indicesInOrder = new ArrayList<Integer>(); 
     ArrayList<Float> textureCoorsInOrder = new ArrayList<Float>(); 
     ArrayList<Float> normalsInOrder = new ArrayList<Float>(); 

     int counter = 0; 
     Log.d("OBJToolkit", "About to reorganize each point of data"); 
     for (Face f : faces) 
     { 
      for (int value : f.vertexIndices) 
      { 
       verticesInOrder.add(allVertices.get(value)); 
      } 

      for (int value : f.textureIndices) 
      { 
       textureCoorsInOrder.add(allTextureCoors.get(value)); 
      } 

      for (int value : f.normalIndices) 
      { 
       normalsInOrder.add(allNormals.get(value)); 
      } 
      indicesInOrder.add(counter); 
      counter++; 
     } 

     Log.d("OBJToolkit", "Vertices"); 
     printFloatArrayList(verticesInOrder); 
     Log.d("OBJToolkit", "Indices"); 
     printIntegerArrayList(indicesInOrder); 
     Log.d("OBJToolkit", "Texture Coordinates"); 
     printFloatArrayList(textureCoorsInOrder); 
     Log.d("OBJToolkit", "Normals"); 
     printFloatArrayList(normalsInOrder); 

     Log.d("OBJToolkit", "About to create the VBOs"); 
     mesh.createBuffers(floatListToFloatArray(verticesInOrder), integerListToShortArray(indicesInOrder), null, floatListToFloatArray(textureCoorsInOrder)); 
     return mesh; 
    } 

    public static void printFloatArrayList(ArrayList<Float> list) 
    { 
     String strToPrint = ""; 
     for (float value : list) 
     { 
      strToPrint += value + ", "; 
     } 
     Log.d("OBJToolkit", strToPrint); 
    } 

    public static void printIntegerArrayList(ArrayList<Integer> list) 
    { 
     String strToPrint = ""; 
     for (float value : list) 
     { 
      strToPrint += value + ", "; 
     } 
     Log.d("OBJToolkit", strToPrint); 
    } 

    public static float[] floatListToFloatArray(ArrayList<Float> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Float"); 
     float[] returnArray = new float[list.size()]; 
     int counter = 0; 
     for (float i : list) 
     { 
      returnArray[counter] = i; 
      counter++; 
     } 
     return returnArray; 
    } 

    public static short[] integerListToShortArray(ArrayList<Integer> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Integer"); 
     short[] returnArray = new short[list.size()]; 
     int counter = 0; 
     for (int i : list) 
     { 
      returnArray[counter] = (short)i; 
      counter++; 
     } 
     return returnArray; 
    } 
} 

메쉬 클래스 :

public class Mesh { 
    Bitmap bitmap = null; 

    private FloatBuffer verticesBuffer; 
    private ShortBuffer indicesBuffer; 
    private int numOfIndices = -1; 
    private float[] rgba = new float[] {1.0f, 1.0f, 1.0f, 1.0f}; 
    private FloatBuffer colorBuffer; 
    private FloatBuffer mTextureBuffer; 
    private int mTextureId = -1; 
    private Bitmap mBitmap; 
    private boolean mShouldLoadTexture = false; 

    public float x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0; 

    public Mesh() { 

    } 

    public void draw(GL10 gl) 
    { 
     //Log.d("Mesh", "About to render mesh"); 
     gl.glFrontFace(GL10.GL_CCW); 
     gl.glEnable(GL10.GL_CULL_FACE); 
     gl.glCullFace(GL10.GL_BACK); 
     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer); 
     gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); 
     if (colorBuffer != null) 
     { 
      gl.glEnableClientState(GL10.GL_COLOR_ARRAY); 
      gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer); 
     } 

     if (mShouldLoadTexture) 
     { 
      loadGLTexture(gl); 
      mShouldLoadTexture = false; 
     } 

     if (mTextureId != -1 && mTextureBuffer != null) 
     { 
      gl.glEnable(GL10.GL_TEXTURE_2D); 
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
      gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer); 
      gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId); 
     } 

     gl.glTranslatef(x, y, z); 
     gl.glRotatef(rx, 1, 0, 0); 
     gl.glRotatef(ry, 0, 1, 0); 
     gl.glRotatef(rz, 0, 0, 1); 
     gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices, GL10.GL_UNSIGNED_SHORT, indicesBuffer); 
     gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
     if (mTextureId != -1 && mTextureBuffer != null) 
     { 
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
     } 
     gl.glDisable(GL10.GL_CULL_FACE); 
    } 

    public void setTexture(Bitmap bitmap) { 
     this.bitmap = bitmap; 
    } 

    public void createBuffers(float[] vertices, short[] indices, float[] colors, float[] textureCoords) 
    { 
     Log.d("MeshCreateBuffers", "Vertices: " + floatArrayToString(vertices)); 
     setVertices(vertices); 
     Log.d("MeshCreateBuffers", "Indices: " + shortArrayToString(indices)); 
     setIndices(indices); 
     if (colors != null) 
      setColors(colors); 
     setTextureCoordinates(textureCoords); 
     Log.d("MeshCreateBuffers", "Texture Coors: " + floatArrayToString(textureCoords)); 
    } 

    public String floatArrayToString(float[] array) 
    { 
     String returnString = ""; 
     for (int i = 0; i < array.length; i++) 
     { 
      returnString += array[i]; 
     } 
     return returnString; 
    } 

    public String shortArrayToString(short[] array) 
    { 
     String returnString = ""; 
     for (int i = 0; i < array.length; i++) 
     { 
      returnString += array[i]; 
     } 
     return returnString; 
    } 

    protected void setVertices(float[] vertices) 
    { 
     ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); 
     vbb.order(ByteOrder.nativeOrder()); 
     verticesBuffer = vbb.asFloatBuffer(); 
     verticesBuffer.put(vertices); 
     verticesBuffer.position(0); 
    } 

    protected void setIndices(short[] indices) 
    { 
     ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); 
     ibb.order(ByteOrder.nativeOrder()); 
     indicesBuffer = ibb.asShortBuffer(); 
     indicesBuffer.put(indices); 
     indicesBuffer.position(0); 
     numOfIndices = indices.length; 
    } 

    protected void setColor(float red, float green, float blue, float alpha) 
    { 
     rgba[0] = red; 
     rgba[1] = green; 
     rgba[2] = blue; 
     rgba[3] = alpha; 
    } 

    protected void setColors(float[] colors) 
    { 
     ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); 
     cbb.order(ByteOrder.nativeOrder()); 
     colorBuffer = cbb.asFloatBuffer(); 
     colorBuffer.put(colors); 
     colorBuffer.position(0); 
    } 

    protected void setTextureCoordinates(float[] textureCoords) 
    { 
     ByteBuffer byteBuf = ByteBuffer.allocateDirect(textureCoords.length * 4); 
     byteBuf.order(ByteOrder.nativeOrder()); 
     mTextureBuffer = byteBuf.asFloatBuffer(); 
     mTextureBuffer.put(textureCoords); 
     mTextureBuffer.position(0); 
    } 

    public void loadBitmap(Bitmap bitmap) 
    { 
     this.mBitmap = bitmap; 
     mShouldLoadTexture = true; 
    } 

    private void loadGLTexture(GL10 gl) 
    { 
     int[] textures = new int[1]; 
     gl.glGenTextures(1, textures, 0); 
     mTextureId = textures[0]; 
     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0); 
    } 
} 

것은 내가 노골적으로 잘못된 이상 - 복잡한 일을하고 있습니까 내가 방금 발견 할 수 없었던 것?

입력 내용을 기꺼이 제공 한 사람에게 감사드립니다.

+0

이것은 많은 코드이며, OBJ 파일 형식은 1로 시작하는 인덱스를 사용합니다 (대부분의 프로그래밍 언어 배열에서와 같이 0이 아님). 잘못된 장소에있는 삼각형에 대한 귀하의 의견은 저를 이것을 생각하게했습니다. – OEP

+0

오 이런, 내가 어떻게 그 하나를 놓칠 수 있었는지 모르겠지만, 확실히 내가 쓴 때에 대해 아는 것이 아닙니다! 고맙습니다. 그래도 문제가 완전히 해결되었는지 또는 일부인지 만 확실하지 않습니다. – jctjct3

+0

도움이되어 주어서 기쁩니다 - 색인 생성 문제로 인해 (반복적으로) 시간을 낭비했습니다. – OEP

답변

1

나는 마침내 작동하게 만들었습니다. 각 꼭지점에 대한 관련 데이터를 함께 정리하지 않아서 렌더링해야 할 때까지는 모든 순서가 잘못되었습니다. 파서는 이제 정점, 법선 및 텍스처 좌표를 지원합니다. 비록 세부적인 메시로 최대 힙 크기에 도달하고 매우 긴 가비지 콜렉션 루프에 갇히지 만 말입니다. Blender에서 suzanne 원숭이 머리를 만들고, 부드럽게 한 번 세분화하여 OBJ로 내 보냅니다. 그것은로드했지만 약 20 분이 걸렸습니다.

여기에 소스 코드가 있습니다. OBJ 파일을 읽고 VBO 형식의 표준 및 텍스처 좌표로 그래픽 카드로 보낸 코드를 찾을 수 없어 도움이 될 것이라고 확신합니다.

public class OBJToolkit { 
    private static ArrayList<String> parseOBJ(String modelLocation) throws IOException 
    { 
     BufferedReader reader = new BufferedReader(new FileReader(new File(modelLocation))); 
     ArrayList<String> lines = new ArrayList<String>(); 
     while(reader.ready()) 
     { 
      lines.add(reader.readLine()); 
     } 
     reader.close(); 
     reader = null; 
     return lines; 
    } 

    public static Mesh loadOBJ(String modelLocation) throws FileNotFoundException, IOException 
    { 
     Log.d("OBJToolkit", "Location searched for model: " + modelLocation); 

     ArrayList<Vector3f> allVertices = new ArrayList<Vector3f>(); 
     ArrayList<Vector2f> allTextureCoords = new ArrayList<Vector2f>(); 
     ArrayList<Vector3f> allNormals = new ArrayList<Vector3f>(); 

     ArrayList<Face> faces = new ArrayList<Face>(); 

     Mesh mesh = new Mesh(); 

     ArrayList<String> lines = parseOBJ(modelLocation); 

     Log.d("OBJToolkit", "About to read the contents of the model"); 
     for (String line : lines) 
     { 
      if (line == null) 
       break; 

      if (line.startsWith("v ")) 
      { 
       allVertices.add(new Vector3f(Float.valueOf(line.split(" ")[1]), Float.valueOf(line.split(" ")[2]), Float.valueOf(line.split(" ")[3]))); 
      } 

      if (line.startsWith("vt ")) 
      { 
       allTextureCoords.add(new Vector2f(Float.valueOf(line.split(" ")[1]),Float.valueOf(line.split(" ")[2]))); 
      } 

      if (line.startsWith("vn ")) 
      { 
       allNormals.add(new Vector3f(Float.valueOf(line.split(" ")[1]), Float.valueOf(line.split(" ")[2]), Float.valueOf(line.split(" ")[3]))); 
      } 

      if (line.startsWith("f ")) 
      { 
       //Log.d("OBJToolkit", line); 
       Face f = new Face(); 
       String[] faceVertexArray = line.split(" "); 

       for (int index = 1; index < faceVertexArray.length; index++) 
       { 
        String[] valueArray = faceVertexArray[index].split("/"); 

        if (allTextureCoords.size() > 0) 
         f.addVertex(new Vertex(allVertices.get(Integer.valueOf(valueArray[0]) - 1), allNormals.get(Integer.valueOf(valueArray[2]) - 1), allTextureCoords.get(Integer.valueOf(valueArray[1]) - 1))); 
        else 
         f.addVertex(new Vertex(allVertices.get(Integer.valueOf(valueArray[0]) - 1), allNormals.get(Integer.valueOf(valueArray[2]) - 1), new Vector2f(0, 0))); 
       } 
       faces.add(f); 
      } 
     } 

     Log.d("OBJToolkit", "Number of vertices: " + allVertices.size()); 
     Log.d("OBJToolkit", "Number of normals: " + allNormals.size()); 
     Log.d("OBJToolkit", "Number of texture coords: " + allTextureCoords.size()); 

     lines = null; 
     allVertices = null; 
     allNormals = null; 
     allTextureCoords = null; 

     ArrayList<Vector3f> VBOVertices = new ArrayList<Vector3f>(); 
     ArrayList<Vector2f> VBOTextureCoords = new ArrayList<Vector2f>(); 
     ArrayList<Vector3f> VBONormals = new ArrayList<Vector3f>(); 
     ArrayList<Integer> VBOIndices = new ArrayList<Integer>(); 

     Log.d("OBJToolkit", "About to reorganize each point of data"); 
     int counter = 0; 
     for (Face f : faces) 
     { 
      for (Vertex v : f.vertices) 
      { 
       VBOVertices.add(v.position); 
       VBONormals.add(v.normal); 
       VBOTextureCoords.add(v.textureCoord); 
       VBOIndices.add(counter); 
       counter++; 
      } 
     } 

     faces = null; 

     mesh.createBuffers(vector3fListToFloatArray(VBOVertices), integerListToShortArray(VBOIndices), null, vector2fListToFloatArray(VBOTextureCoords), vector3fListToFloatArray(VBONormals)); 

     VBOVertices = null; 
     VBONormals = null; 
     VBOTextureCoords = null; 
     VBOIndices = null; 
     return mesh; 
    } 

    public static void printFloatArrayList(ArrayList<Float> list) 
    { 
     String strToPrint = ""; 
     for (float value : list) 
     { 
      strToPrint += (value + ", "); 
     } 
     Log.d("OBJToolkit", strToPrint); 
    } 

    public static String floatArrayToString(ArrayList<Float> list) 
    { 
     String strToPrint = ""; 
     for (float value : list) 
     { 
      strToPrint += (value + ", "); 
     } 
     return strToPrint; 
    } 

    public static String vector3fArrayToString(ArrayList<Vector3f> list) 
    { 
     String strToPrint = ""; 
     for (Vector3f v : list) 
     { 
      strToPrint += v.x + ", "; 
      strToPrint += v.y + ", "; 
      strToPrint += v.z + ", "; 
     } 
     return strToPrint; 
    } 

    public static void printStringArray(String[] list) 
    { 
     String strToPrint = ""; 
     for (String s : list) 
     { 
      strToPrint += s + ","; 
     } 
     Log.d("OBJToolkit", strToPrint); 
    } 

    public static void printIntegerArrayList(ArrayList<Integer> list) 
    { 
     String strToPrint = ""; 
     for (float value : list) 
     { 
      strToPrint += (value + ", "); 
     } 
     Log.d("OBJToolkit", strToPrint); 
    } 

    public static float[] floatListToFloatArray(ArrayList<Float> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Float"); 
     float[] returnArray = new float[list.size()]; 
     int counter = 0; 
     for (Float i : list) 
     { 
      returnArray[counter] = i.floatValue(); 
      counter++; 
     } 
     return returnArray; 
    } 

    public static short[] integerListToShortArray(ArrayList<Integer> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Integer"); 
     short[] returnArray = new short[list.size()]; 
     int counter = 0; 
     for (int i : list) 
     { 
      returnArray[counter] = (short)i; 
      counter++; 
     } 
     return returnArray; 
    } 

    public static float[] vector3fListToFloatArray(ArrayList<Vector3f> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Vector3f"); 
     float[] returnArray = new float[list.size() * 3]; 
     int counter = 0; 
     for (Vector3f v : list) 
     { 
      returnArray[counter] = v.x; 
      counter++; 
      returnArray[counter] = v.y; 
      counter++; 
      returnArray[counter] = v.z; 
      counter++; 
     } 

     return returnArray; 
    } 

    public static float[] vector2fListToFloatArray(ArrayList<Vector2f> list) 
    { 
     Log.d("OBJToolkit", "Converting ArrayList Vector2f"); 
     float[] returnArray = new float[list.size() * 2]; 
     int counter = 0; 
     for (Vector2f v : list) 
     { 
      returnArray[counter] = v.x; 
      counter++; 
      returnArray[counter] = v.y; 
      counter++; 
     } 

     return returnArray; 
    } 

Vector3f :

public class Vector3f { 
    public float x, y, z; 

    public Vector3f() 
    { 
     setTo(0, 0, 0); 
    } 

    public Vector3f(float x, float y, float z) 
    { 
     setTo(x, y, z); 
    } 

    public void setTo(float x, float y, float z) 
    { 
     this.x = x; 
     this.y = y; 
     this.z = z; 
    } 

    public float lengthSquared() 
    { 
     return x*x + y*y + z*z; 
    } 

    public float length() 
    { 
     return (float) Math.sqrt(lengthSquared()); 
    } 

    public Vector3f add(Vector3f v) 
    { 
     return new Vector3f(x + v.x, y + v.y, z + v.z); 
    } 

    public Vector3f addAndSet(Vector3f v) 
    { 
     x += v.x; 
     y += v.y; 
     z += v.z; 
     return this; 
    } 

    public Vector3f crossProduct(Vector3f v) 
    { 
     return new Vector3f(y * v.z - z * v.y, 
       z * v.x - x * z, 
       x * v.y - y * v.x 
       ); 
    } 

    public Vector3f negate() 
    { 
     x *= -1; 
     y *= -1; 
     z *= -1; 
     return this; 
    } 

    public Vector3f normalize() 
    { 
     float l = length(); 

     return new Vector3f(x/l, y/l, z/l); 
    } 

    public float dotProduct(Vector3f v) 
    { 
     return x * v.x + y * v.y + z * v.z; 
    } 

    public float angleBetween(Vector3f v) 
    { 
     float dls = dotProduct(v)/(length() * v.length()); 
     if (dls < -1f) 
      dls = -1f; 
     else if (dls > 1.0f) 
      dls = 1.0f; 
     return (float)Math.acos(dls); 
    } 

    public Vector3f scale(float scale) 
    { 
     return new Vector3f(x * scale, y * scale, z * scale); 
    } 

    public Vector3f scaleAndSet(float scale) 
    { 
     x *= scale; 
     y *= scale; 
     z *= scale; 
     return this; 
    } 


} 

Vector2f :

public class Vector2f { 
    public float x, y; 

    public Vector2f() 
    { 
     setTo(0, 0); 
    } 

    public Vector2f(float x, float y) 
    { 
     setTo(x, y); 
    } 

    public void setTo(float x, float y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public float lengthSquared() 
    { 
     return x * x + y * y; 
    } 

    public float length() 
    { 
     return (float) Math.sqrt(lengthSquared()); 
    } 

    public Vector2f add(float x, float y) 
    { 
     return new Vector2f(this.x + x, this.y + y); 
    } 

    public Vector2f addAndSet(float x, float y) 
    { 
     this.x += x; 
     this.y += y; 
     return this; 
    } 

    public Vector2f negate() 
    { 
     x *= -1; 
     y *= -1; 
     return this; 
    } 

    public Vector2f normalize() 
    { 
     float l = length(); 
     return new Vector2f(x/l, y/l); 
    } 

    public float dotProduct(Vector2f v) 
    { 
     return x * v.x + y * v.y; 
    } 

    public float angleBetween(Vector2f v) 
    { 
     float dls = dotProduct(v)/(length() * v.length()); 
     if (dls < -1f) 
      dls = -1f; 
     else if (dls > 1.0f) 
      dls = 1.0f; 
     return (float)Math.acos(dls); 
    } 

    public Vector2f scale(float scale) 
    { 
     return new Vector2f(x * scale, y * scale); 
    } 

    public Vector2f scaleAndSet(float scale) 
    { 
     x *= scale; 
     y *= scale; 
     return this; 
    } 
} 

메쉬 :

public class Mesh { 
    Bitmap bitmap = null; 

    private FloatBuffer verticesBuffer; 
    private ShortBuffer indicesBuffer; 
    private FloatBuffer normalsBuffer; 
    private int numOfIndices = -1; 
    private float[] rgba = new float[] {1.0f, 1.0f, 1.0f, 1.0f}; 
    private FloatBuffer colorBuffer; 
    private FloatBuffer mTextureBuffer; 
    private int mTextureId = -1; 
    private Bitmap mBitmap; 
    private boolean mShouldLoadTexture = false; 

    public float x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0; 

    public Mesh() { 

    } 

    public void draw(GL10 gl) 
    { 
     //Log.d("Mesh", "About to render mesh"); 
     gl.glFrontFace(GL10.GL_CCW); 
     gl.glEnable(GL10.GL_CULL_FACE); 
     gl.glCullFace(GL10.GL_BACK); 
     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 
     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer); 
     gl.glNormalPointer(GL10.GL_FLOAT, 0, normalsBuffer); 
     gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); 
     if (colorBuffer != null) 
     { 
      gl.glEnableClientState(GL10.GL_COLOR_ARRAY); 
      gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer); 
     } 

     if (mShouldLoadTexture) 
     { 
      loadGLTexture(gl); 
      mShouldLoadTexture = false; 
     } 

     if (mTextureId != -1 && mTextureBuffer != null) 
     { 
      gl.glEnable(GL10.GL_TEXTURE_2D); 
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
      gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer); 
      gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId); 
     } 

     gl.glTranslatef(x, y, z); 
     gl.glRotatef(rx, 1, 0, 0); 
     gl.glRotatef(ry, 0, 1, 0); 
     gl.glRotatef(rz, 0, 0, 1); 
     gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices, GL10.GL_UNSIGNED_SHORT, indicesBuffer); 
     gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); 
     gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
     if (mTextureId != -1 && mTextureBuffer != null) 
     { 
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
     } 
     gl.glDisable(GL10.GL_CULL_FACE); 
    } 

    public void setTexture(Bitmap bitmap) { 
     this.bitmap = bitmap; 
    } 

    public void createBuffers(float[] vertices, short[] indices, float[] colors, float[] textureCoords, float[] normals) 
    { 
     Log.d("MeshCreateBuffers", "Vertices: " + floatArrayToString(vertices)); 
     setVertices(vertices); 
     Log.d("MeshCreateBuffers", "Indices: " + shortArrayToString(indices)); 
     setIndices(indices); 
     if (colors != null) 
      setColors(colors); 
     if (textureCoords != null) 
      setTextureCoordinates(textureCoords); 
     if (normals != null) 
      setNormals(normals); 
     Log.d("MeshCreateBuffers", "Texture Coors: " + floatArrayToString(textureCoords)); 
    } 

    public String floatArrayToString(float[] array) 
    { 
     String returnString = ""; 
     for (int i = 0; i < array.length; i++) 
     { 
      returnString += ", " + array[i]; 
     } 
     if (returnString.length() > 2) 
      return returnString.substring(2); 
     else 
      return returnString; 
    } 

    public String shortArrayToString(short[] array) 
    { 
     String returnString = ""; 
     for (int i = 0; i < array.length; i++) 
     { 
      returnString += ", " + array[i]; 
     } 
     if (returnString.length() > 2) 
      return returnString.substring(2); 
     else 
      return returnString; 
    } 

    protected void setVertices(float[] vertices) 
    { 
     ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); 
     vbb.order(ByteOrder.nativeOrder()); 
     verticesBuffer = vbb.asFloatBuffer(); 
     verticesBuffer.put(vertices); 
     verticesBuffer.position(0); 
    } 

    protected void setIndices(short[] indices) 
    { 
     ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); 
     ibb.order(ByteOrder.nativeOrder()); 
     indicesBuffer = ibb.asShortBuffer(); 
     indicesBuffer.put(indices); 
     indicesBuffer.position(0); 
     numOfIndices = indices.length; 
    } 

    protected void setColor(float red, float green, float blue, float alpha) 
    { 
     rgba[0] = red; 
     rgba[1] = green; 
     rgba[2] = blue; 
     rgba[3] = alpha; 
    } 

    protected void setColors(float[] colors) 
    { 
     ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); 
     cbb.order(ByteOrder.nativeOrder()); 
     colorBuffer = cbb.asFloatBuffer(); 
     colorBuffer.put(colors); 
     colorBuffer.position(0); 
    } 

    protected void setTextureCoordinates(float[] textureCoords) 
    { 
     ByteBuffer byteBuf = ByteBuffer.allocateDirect(textureCoords.length * 4); 
     byteBuf.order(ByteOrder.nativeOrder()); 
     mTextureBuffer = byteBuf.asFloatBuffer(); 
     mTextureBuffer.put(textureCoords); 
     mTextureBuffer.position(0); 
    } 

    protected void setNormals(float[] normals) 
    { 
     ByteBuffer byteBuf = ByteBuffer.allocateDirect(normals.length * 4); 
     byteBuf.order(ByteOrder.nativeOrder()); 
     normalsBuffer = byteBuf.asFloatBuffer(); 
     normalsBuffer.put(normals); 
     normalsBuffer.position(0); 
    } 

    public void loadBitmap(Bitmap bitmap) 
    { 
     this.mBitmap = bitmap; 
     mShouldLoadTexture = true; 
    } 

    private void loadGLTexture(GL10 gl) 
    { 
     int[] textures = new int[1]; 
     gl.glGenTextures(1, textures, 0); 
     mTextureId = textures[0]; 
     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0); 
    } 
} 

직면

public class Face { 
    ArrayList<Vertex> vertices = new ArrayList<Vertex>(); 

    public Face() 
    { 

    } 

    public void addVertex(Vertex vertex) 
    { 
     vertices.add(vertex); 
    } 
} 

정점 :

public class Vertex { 
    public Vector3f position, normal; 
    public Vector2f textureCoord; 

    public Vertex(Vector3f pos, Vector3f norm, Vector2f textCoord) 
    { 
     position = pos; 
     normal = norm; 
     textureCoord = textCoord; 
    } 
} 

MainActivity :

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
     MyGLSurfaceView view = new MyGLSurfaceView(this); 
     OpenGLRenderer renderer = new OpenGLRenderer(); 
     view.renderer = renderer; 
     //renderer.plane.loadBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 
     view.setRenderer(renderer); 
     setContentView(view); 
    } 
} 

class MyGLSurfaceView extends GLSurfaceView implements OnGestureListener, OnTouchListener 
{ 
    OpenGLRenderer renderer; 
    GestureDetector detector; 

    float lastX = 0, lastY = 0; 

    float onDown = 0, onUp = 0; 

    public MyGLSurfaceView(Context context) { 
     super(context); 
     detector = new GestureDetector(this); 
     setOnTouchListener(this); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent me) 
    { 
     detector.onTouchEvent(me); 
     //Log.d("OBJToolkit", "X: " + me.getX()); 
     //Log.d("OBJToolkit", "Y: " + me.getY()); 
     return super.onTouchEvent(me); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent me) 
    { 
     Log.d("OBJToolkit", "Registered onTouch event"); 
     Log.d("OBJToolkit", "X: " + me.getX()); 
     Log.d("OBJToolkit", "Y: " + me.getY()); 
     if (me.getAction() == MotionEvent.ACTION_DOWN) 
     { 
      lastY = me.getY(); 
     } 
     else if (me.getAction() == MotionEvent.ACTION_MOVE) 
     { 
      renderer.moveMesh(me.getY() - lastY); 
     } 
     /* 
     if (lastX == 0) 
     { 
      lastX = me.getX(); 
     } 
     if (lastY == 0) 
     { 
      lastY = me.getY(); 
     } 
     Log.d("OBJToolkit", String.valueOf((me.getY() - lastY) * 0.1f)); 
     renderer.moveMesh(me.getY() - lastY); 
     */ 
     lastY = me.getY(); 

     return true; 
    } 

    @Override 
    public boolean onDown(MotionEvent e) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onDown Event"); 
     return false; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
      float velocityY) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onFling Event"); 
     return false; 
    } 

    @Override 
    public void onLongPress(MotionEvent e) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onLongPress Event"); 

    } 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 
      float distanceY) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onScroll Event"); 
     return false; 
    } 

    @Override 
    public void onShowPress(MotionEvent e) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onShowPress Event"); 
    } 

    @Override 
    public boolean onSingleTapUp(MotionEvent e) { 
     // TODO Auto-generated method stub 
     //Log.d("OBJToolkit", "Registered onSIngleTapUp Event"); 
     return false; 
    } 

} 

OpenGLRenderer :

,536,913,632 10
public class OpenGLRenderer implements Renderer 
{ 
    //SmoothColoredSquare smoothSquare = new SmoothColoredSquare(); 
    //Cube cube = new Cube(1, 1, 1); 
    public Mesh plane; 

    public float meshMoveSpeed = .05f, planePosition = 0f; 

    float zNear = 0.01f, zFar = 1000.0f, fieldOfView = 45.0f, size; 

    @Override 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
     Log.d(getClass().getName(), "About to attempt to load model"); 
     try { 
      plane = OBJToolkit.loadOBJ(Environment.getExternalStorageDirectory().getPath() + "/testModel.obj"); 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      Log.d("FNF", "testModel.obj not found"); 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      Log.d("IOE", "testModel.obj not found IOE"); 
      e.printStackTrace(); 
     } 
     //.z = -7.7f; 
     //plane.rx = -10; 
     gl.glEnable(GL11.GL_DEPTH_TEST); 
     gl.glDepthFunc(GL10.GL_LEQUAL); 
     gl.glMatrixMode(GL11.GL_MODELVIEW); 
     gl.glShadeModel(GL11.GL_SMOOTH); 
     gl.glClearDepthf(1.0f); 
     gl.glEnable(GL11.GL_LIGHTING); 
     gl.glEnable(GL11.GL_LIGHT0); 
     float ambientColor[] = {0.2f, 0.2f, 0.2f, 1.0f}; 
     float diffuseColor[] = {0.2f, 0.2f, 0.2f, 1.0f}; 
     float lightPosition[] = {-2f, 5f, -2f, 1f}; 
     gl.glLightfv(GL11.GL_LIGHT0, GL11.GL_AMBIENT, ambientColor, 0); 
     gl.glLightfv(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, diffuseColor, 0); 
     gl.glLightfv(GL11.GL_LIGHT0, GL11.GL_POSITION, lightPosition, 0); 
     gl.glLoadIdentity(); 
     gl.glClearColor(0.8f, 0.8f, 0.8f, 1.0f); 
     gl.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); 
    } 

    @Override 
    public void onSurfaceChanged(GL10 gl, int width, int height) { 
     //Reset viewport 
     gl.glViewport(0, 0, width, height); 
     //Select projection matrix 
     gl.glMatrixMode(GL10.GL_PROJECTION); 
     size = (float) (zNear * Math.tan((fieldOfView/180.0f) * Math.PI)/2.0f); 
     gl.glFrustumf(-size, size, -size/(width/height), size/(width/height), zNear, zFar); 
     gl.glViewport(0, 0, width, height); 
     //Reset projection matrix 
     gl.glLoadIdentity(); 
     //Calculate aspect ratio of window 
     GLU.gluPerspective(gl, 45.0f, (float)width/(float)height, 0.1f, 100.0f); 
     //GLU.gluLookAt(gl, -5f, 2f, 0f, 0f, 0f, 0f, 0f, 1f, 0f); 
     //Select modelview matrix 
     gl.glMatrixMode(GL10.GL_MODELVIEW); 
     //Reset modelview matrix 
     gl.glLoadIdentity(); 
    } 

    @Override 
    public void onDrawFrame(GL10 gl) { 
     //Clear the screen before drawing 
     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 

     //plane.ry += 2f; 
     //plane.rz += 2f; 

     plane.x += meshMoveSpeed; 
     plane.z = planePosition; 
     if (plane.x > 3f) 
     { 
      meshMoveSpeed *= -1; 
     } 
     else if(plane.x < -3f) 
     { 
      meshMoveSpeed *= -1; 
     } 

     //Reset the current position held by OpenGL, otherwise the 
     //camera will be pushed farther and farther back every frame 
     gl.glLoadIdentity(); 

     //Move the camera backwards in order to actually see the face 
     gl.glTranslatef(0, 0f, -15f); 

     plane.draw(gl); 
    } 

    public void moveMesh(float distance) 
    { 
     planePosition += distance * 0.05f; 
    } 
}