编写加载在维也纳各组织的数据我自己的OBJ解析器,如何重新订单数据来匹配单个索引列表?维也纳、自己的、据我、索引

2023-09-07 03:57:48 作者:烟╰ゝ刺痛了眼伤了心

我一直在尝试转换的OBJ解析器,我写了previously所使用的显示列表使用维也纳组织代替,并试图看看能不能找出问题我自己没有任何外界的帮助,但现在我想我一直在寻找的code太长,我无法找到任何错误。

I've been trying to convert an OBJ parser that I wrote previously that used display lists to use VBOs instead, and have attempted to see if I could figure out the issue myself without any outside help, but now I think I have been looking at the code too long and am unable to find any errors.

这是一个Android应用程序,通过OpenGLES 2.0和我结束了一些三角形在屏幕上,而不是在正确的地方都没有。我有一种感觉,我试图让所有基于索引的一个列表上的每个面的要素是不正确的,我刚刚结束了扔一切失灵,但我无法找到我的错误。

This is an Android App, through OpenGLES 2.0, and I end up with some triangles up on the screen, but not in the correct places at all. I have a feeling that my attempt to get all of the elements of each face based on a single list of indices is incorrect and I just end up throwing everything out of order, but I am unable to find my error.

从本质上讲,由于OBJ格式给出了顶点的独立指数,纹理坐标以及法线,我最终数据的3列出了完全出于相互顺序,但VBO引用基于各部分对指数的一个列表。

Essentially, since the OBJ format gives a separate index for the vertex, the texture coordinate and the normal vector, I end up with 3 lists of data that are completely out of order from each other, but the VBO references each part based on a single list of indices.

下面是我的code,以帮助别人帮助我:

Here is my code, in order to help someone help me:

OBJToolkit:

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

我做得不对公然或过于复杂,我刚才已经无法察觉?

Am I doing something blatantly wrong or over-complicated that I have just been unable to spot?

我要感谢的人是愿意提供他们的意见。

I thank anyone that is willing to offer their input.

推荐答案

我终于得到它的工作,大部分。我没有保持相关的数据为每个顶点起来不够好,所以它所需要的时间进行渲染,一切都失灵了。解析器截至目前支持顶点,法线和纹理坐标,虽然轻度详细网格它击中的最大堆大小并卡在很长的垃圾收集循环。我创建了苏珊娜猴子头搅拌机,与平滑细分一次,并出口,作为一个OBJ。它确实负荷,但花了约20分钟。

I finally got it to work, for the most part. I wasn't keeping the related data for each vertex together well enough so by the time it needed to be rendered, it was all out of order. The parser as of now supports vertices, normals and texture coordinates, although with mildly detailed meshes it hits the maximum heap size and gets stuck in a very long garbage collection loop. I created the suzanne monkey head in Blender, subdivided it once with smoothing and exported that as an OBJ. It did load, but it took about 20 minutes.

下面是源,我相信这将帮助别人,因为我无法设法找到code,上面写着一个OBJ文件,并将其发送给维也纳各组织形式的独立显卡,拥有法线和纹理坐标工作:

Here is the source, I'm sure it will help someone as I could not manage to find code that read an OBJ file and sent it to the graphics card in the form of VBOs, WITH normals and texture coordinates working:

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:

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:

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:

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:

OpenGLRenderer:

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