7

我正在使用 OpenGl Es 库来渲染 3D 对象。我收到异常 OutofMemoryError 我尝试在谷歌上搜索但无法成功

请帮我解决这个问题。

package com.amplimesh.models;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;

import com.amplimesh.util.Point3;

public class ObjModel {

    public void bindTextures(Context context, GL10 gl) {
        Bitmap bitmap;
        try {
            InputStream is = context.getAssets().open("textures/"+mTextureName);
            bitmap = BitmapFactory.decodeStream(is);
            if (bitmap == null) {
                Log.v("ObjModel", "err loading bitmap!");
            }
        } catch (java.io.IOException e) {
            Log.v("ObjModel", "err loading tex: "+e.toString());
            return;
        }

        mTextures = new int[1];
        gl.glGenTextures(1, mTextures, 0);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]);
        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_CLAMP_TO_EDGE);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();
    }

    public void draw(GL10 gl) {
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        for (Model model : mModels) {

            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.v);
            if (model.vt != null && mTextures != null) {
                gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]);
                gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, model.vt);
            }

            if (model.vn != null) {
                gl.glNormalPointer(GL10.GL_FLOAT, 0, model.vn);
            }
            gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.v_size);

        }

        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }

    public static ObjModel loadFromStream(InputStream is, String texture_name) throws IOException {
        ObjModel obj = ObjLoader.loadFromStream(is);
        obj.mTextureName = texture_name;
        return obj;
    }

    private Model mModels[];
    private int mTextures[];
    private String mTextureName;

    /**
     * It help to load the obj.
     * @author Ajay
     */
    private static class ObjLoader {

        public static ObjModel loadFromStream(InputStream is) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            ObjModel obj = new ObjModel();
            ArrayList<Point3> v = new ArrayList<Point3>();
            ArrayList<Point3> vt = new ArrayList<Point3>();
            ArrayList<Point3> vn = new ArrayList<Point3>();
            ArrayList<Face> f = new ArrayList<Face>();

            ArrayList<Model> o = new ArrayList<Model>();

            boolean o_pending=false;

            while(reader.ready()) {
                String line = reader.readLine();
                if (line == null) 
                    break;

                StringTokenizer tok = new StringTokenizer(line);
                String cmd = tok.nextToken();

                if (cmd.equals("o")) {
                    if (o_pending) {
                        Model model = new Model();
                        model.fill(f, vt.size() > 0, vn.size() > 0);
                        o.add(model);
                    }
                    else {
                        o_pending=true;
                    }
                }
                else
                    if (cmd.equals("v")) {
                        v.add(read_point(tok));
                    }
                    else
                        if (cmd.equals("vn")) {
                            vn.add(read_point(tok));
                        }
                        else
                            if (cmd.equals("vt")) {
                                vt.add(read_point(tok));
                            }
                            else
                                if (cmd.equals("f")) {
                                    if (tok.countTokens() != 3)
                                        continue;

                                    Face face = new Face(3);
                                    while (tok.hasMoreTokens()) {
                                        StringTokenizer face_tok = new StringTokenizer(tok.nextToken(), "/");

                                        int v_idx = -1;
                                        int vt_idx = -1;
                                        int vn_idx = -1;
                                        v_idx = Integer.parseInt(face_tok.nextToken());
                                        if (face_tok.hasMoreTokens()) vt_idx = Integer.parseInt(face_tok.nextToken());
                                        if (face_tok.hasMoreTokens()) vn_idx = Integer.parseInt(face_tok.nextToken());

                                        //Log.v("objmodel", "face: "+v_idx+"/"+vt_idx+"/"+vn_idx);

                                        face.addVertex(
                                                v.get(v_idx-1),
                                                vt_idx == -1 ? null : vt.get(vt_idx-1),
                                                        vn_idx == -1 ? null : vn.get(vn_idx-1)
                                                );
                                    }
                                    f.add(face);
                                }
            }

            if (o_pending) {
                Model model = new Model();
                model.fill(f, vt.size() > 0, vn.size() > 0);
                o.add(model);
            }

            obj.mModels = new Model[o.size()];
            o.toArray(obj.mModels);
            return obj;
        }



        private static Point3 read_point(StringTokenizer tok) {
            Point3 ret = new Point3();
            if (tok.hasMoreTokens()) {
                ret.x = Float.parseFloat(tok.nextToken());
                if (tok.hasMoreTokens()) {
                    ret.y = Float.parseFloat(tok.nextToken());
                    if (tok.hasMoreTokens()) {
                        ret.z = Float.parseFloat(tok.nextToken());
                    }
                }
            }
            return ret;
        }

    }

    private static class Face {
        Point3 v[];
        Point3 vt[];
        Point3 vn[];
        int size;
        int count;

        public Face(int size) {
            this.size = size;
            this.count = 0;
            this.v = new Point3[size];
            this.vt = new Point3[size];
            this.vn = new Point3[size];
        }

        public boolean addVertex(Point3 v, Point3 vt, Point3 vn) {
            if (count >= size)
                return false;
            this.v[count] = v;
            this.vt[count] = vt;
            this.vn[count] = vn;
            count++;
            return true;
        }

        public void pushOnto(FloatBuffer v_buffer, FloatBuffer vt_buffer, FloatBuffer vn_buffer) {
            int i;
            for (i=0; i<size; i++) {
                v_buffer.put(v[i].x); v_buffer.put(v[i].y); v_buffer.put(v[i].z);

                if (vt_buffer != null && vt[i] != null) {
                    vt_buffer.put(vt[i].x); vt_buffer.put(vt[i].y);
                }

                if (vn_buffer != null && vn[i] != null) {
                    vn_buffer.put(vn[i].x); vn_buffer.put(vn[i].y); vn_buffer.put(vn[i].z);
                }
            }
        }
    }


    private static class Model {
        public FloatBuffer v;
        public FloatBuffer vt;
        public FloatBuffer vn;
        public int v_size;

        public void fill(ArrayList<Face> faces, boolean has_tex, boolean has_normals) {
            int f_len = faces.size();

            this.v_size = f_len * 3;

            ByteBuffer tBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4);
            tBuf.order(ByteOrder.nativeOrder());
            this.v = tBuf.asFloatBuffer();

            if (has_tex) {
                ByteBuffer vtBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4);
                vtBuf.order(ByteOrder.nativeOrder());
                this.vt = vtBuf.asFloatBuffer();
            }

            if (has_normals) {
                ByteBuffer vnBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4);
                vnBuf.order(ByteOrder.nativeOrder());
                this.vn = vnBuf.asFloatBuffer();
            }

            int i;
            for (i=0; i < f_len; i++) {
                Face face = faces.get(i);
                face.pushOnto(this.v, this.vt, this.vn);
            }

            this.v.rewind();
            if (this.vt != null)
                this.vt.rewind();
            if (this.vn != null)
                this.vn.rewind();
        }
    }
}

堆栈跟踪

08-03 16:22:31.794: E/AndroidRuntime(18878): FATAL EXCEPTION: AsyncTask #3
08-03 16:22:31.794: E/AndroidRuntime(18878): java.lang.RuntimeException: An error occured while executing doInBackground()
08-03 16:22:31.794: E/AndroidRuntime(18878):    at android.os.AsyncTask$3.done(AsyncTask.java:278)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.lang.Thread.run(Thread.java:856)
08-03 16:22:31.794: E/AndroidRuntime(18878): Caused by: java.lang.OutOfMemoryError
08-03 16:22:31.794: E/AndroidRuntime(18878):    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.nio.MemoryBlock.allocate(MemoryBlock.java:126)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.nio.ReadWriteDirectByteBuffer.<init>(ReadWriteDirectByteBuffer.java:46)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:68)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at com.amplimesh.models.ObjModel$Model.fill(ObjModel.java:241)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at com.amplimesh.models.ObjModel$ObjLoader.loadFromStream(ObjModel.java:161)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at com.amplimesh.models.ObjModel.loadFromStream(ObjModel.java:74)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at com.amplimesh.renderer.RendererView$ObjLoaderAsync.doInBackground(RendererView.java:443)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at com.amplimesh.renderer.RendererView$ObjLoaderAsync.doInBackground(RendererView.java:1)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
08-03 16:22:31.794: E/AndroidRuntime(18878):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-03 16:22:31.794: E/AndroidRuntime(18878):    ... 5 more
4

2 回答 2

23

尝试通过将其添加到您的 AndroidManifest.xml 文件来启用大堆支持:

<application android:largeHeap="true"

此外,您可以通过使用 Bitmap.Config 类型 RGB_565 而不是 ARGB_8888 来减少位图所需的内存。

于 2013-08-03T16:00:40.577 回答
-2

只需在 drawable 或 mipmap 的 xhdpi 中添加图像文件。这对我有用。

于 2016-11-09T21:44:06.977 回答