0

我最近刚刚获得了一个 OBJ 加载器,并查看了 Android 应用程序在顶点、法线和纹理坐标方面正常工作,但为了正确跟踪这些数据值,我最终创建了很多单独的对象。我在网上读到的一件事是长字符串或大字符串数组/数组列表占用了大量的内存。我试图摆脱这两种单独的方法,一种将文件解析为字符串的 ArrayList,另一种通过该 ArrayList 读取,方法是将两者结合起来,同时将文件中的行存储删除到一个大的 ArrayList 中。我替换了我的代码,以便它在读取文件时解释文件,但这也没有减少模型加载时间。我使用的测试模型是 Suzanne 猴头,在 Blender 中细分一次并导出为 OBJ,大约有 2000 个顶点。我不确定还能做什么来抵御垃圾收集器。另请注意,这是为 Android 2.2 构建的,因此我无法像在 Android 3.0 及更高版本中那样指定更大的堆大小。非常感谢任何可以给出的指针,因为我想让这个加载器尽快加载,但我不完全确定如何做到这一点。

这是迄今为止的来源:

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 和 Vector2f 类并改用数组,但我不确定这是否真的会减少内存使用量,因为数组对象具有所有额外的功能我不需要。

我还尝试将不再需要的东西设置为 null,希望 GC 会自动摆脱它们,在堆中留下更多内存,但这似乎根本没有帮助。

OBJToolkit 类是这里的主类,但以防万一我将在下面包含其他相关类:

网:

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

矢量3f:

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


}

矢量2f:

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 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);
        super.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        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;
    }

}

OpenGL渲染器:

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

1 回答 1

0

字符串...太多的字符串让 GC 卡住试图清除它们。部分问题在于将文件读取到一个大的字符串数组列表中,但最大的问题在于 Mesh 类中的调试调用。它遍历传入数组中的每个对象,并通过 += 和逗号分隔符将其添加到字符串中。这导致内存中没有使用的数千个字符串。不用说,我已经重写了一些应用程序并删除了调试调用,因为它们现在无论如何都不需要了,但我想我会在某个时候重写它们以使用 StringBuilder。我真正改变的唯一代码是在 OBJToolkit 类中,所以这里是:

public class OBJToolkit {

    public static String getStringFromFile(String filePath) throws Exception
    {
        File fl = new File(filePath);
        FileInputStream fin = new FileInputStream(fl);
        String returnString = convertStreamToString(fin);
        fin.close();
        return returnString;
    }

    public static String convertStreamToString(InputStream is) throws Exception
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null)
        {
            sb.append(line).append("\n");
        }
        return sb.toString();
    }

    public static Mesh loadOBJ(String modelLocation) throws Exception
    {
        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();

        String lines = getStringFromFile(modelLocation);

        Log.d("OBJToolkit", "About to read the contents of the model");
        String[] individualLines = lines.split("\\n");

        int numberOfLines = individualLines.length;
        for (int i = 0; i < numberOfLines; i++)
        {
            String line = individualLines[i];
            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;
    }
}

我希望这可以以某种方式帮助某人。

于 2013-04-13T03:42:55.223 回答