How to load and display .obj file in Android with OpenGL-ES 2

前端 未结 3 1992
无人及你
无人及你 2020-12-29 05:49

I am trying to load an .obj file into my Android application and display it using OpenGL 2.

You can find the file here: EDIT: I removed the file, yo

相关标签:
3条回答
  • 2020-12-29 06:23

    I ended up writing a new parser, it can be used like this to build FloatBuffers to use in your Renderer:

    ObjLoader objLoader = new ObjLoader(context, "Mug.obj");
    
    numFaces = objLoader.numFaces;
    
    // Initialize the buffers.
    positions = ByteBuffer.allocateDirect(objLoader.positions.length * mBytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
    positions.put(objLoader.positions).position(0);
    
    normals = ByteBuffer.allocateDirect(objLoader.normals.length * mBytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
    normals.put(objLoader.normals).position(0);
    
    textureCoordinates = ByteBuffer.allocateDirect(objLoader.textureCoordinates.length * mBytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
    textureCoordinates.put(objLoader.textureCoordinates).position(0);
    

    and here's the parser:

    public final class ObjLoader {
    
        public final int numFaces;
    
        public final float[] normals;
        public final float[] textureCoordinates;
        public final float[] positions;
    
        public ObjLoader(Context context, String file) {
    
            Vector<Float> vertices = new Vector<>();
            Vector<Float> normals = new Vector<>();
            Vector<Float> textures = new Vector<>();
            Vector<String> faces = new Vector<>();
    
            BufferedReader reader = null;
            try {
                InputStreamReader in = new InputStreamReader(context.getAssets().open(file));
                reader = new BufferedReader(in);
    
                // read file until EOF
                String line;
                while ((line = reader.readLine()) != null) {
                    String[] parts = line.split(" ");
                    switch (parts[0]) {
                        case "v":
                            // vertices
                            vertices.add(Float.valueOf(parts[1]));
                            vertices.add(Float.valueOf(parts[2]));
                            vertices.add(Float.valueOf(parts[3]));
                            break;
                        case "vt":
                            // textures
                            textures.add(Float.valueOf(parts[1]));
                            textures.add(Float.valueOf(parts[2]));
                            break;
                        case "vn":
                            // normals
                            normals.add(Float.valueOf(parts[1]));
                            normals.add(Float.valueOf(parts[2]));
                            normals.add(Float.valueOf(parts[3]));
                            break;
                        case "f":
                            // faces: vertex/texture/normal
                            faces.add(parts[1]);
                            faces.add(parts[2]);
                            faces.add(parts[3]);
                            break;
                    }
                }
            } catch (IOException e) {
                // cannot load or read file
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        //log the exception
                    }
                }
            }
    
            numFaces = faces.size();
            this.normals = new float[numFaces * 3];
            textureCoordinates = new float[numFaces * 2];
            positions = new float[numFaces * 3];
            int positionIndex = 0;
            int normalIndex = 0;
            int textureIndex = 0;
            for (String face : faces) {
                String[] parts = face.split("/");
    
                int index = 3 * (Short.valueOf(parts[0]) - 1);
                positions[positionIndex++] = vertices.get(index++);
                positions[positionIndex++] = vertices.get(index++);
                positions[positionIndex++] = vertices.get(index);
    
                index = 2 * (Short.valueOf(parts[1]) - 1);
                textureCoordinates[normalIndex++] = textures.get(index++);
                // NOTE: Bitmap gets y-inverted
                textureCoordinates[normalIndex++] = 1 - textures.get(index);
    
                index = 3 * (Short.valueOf(parts[2]) - 1);
                this.normals[textureIndex++] = normals.get(index++);
                this.normals[textureIndex++] = normals.get(index++);
                this.normals[textureIndex++] = normals.get(index);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-29 06:23

    Try with this project that found me on Github. https://github.com/WenlinMao/android-3d-model-viewer

    This is a demo of OpenGL ES 2.0. It is an android application with a 3D engine that can load Wavefront OBJ, STL, DAE & glTF files. The application is based on andresoviedo's project which can be found here with an additional function of loading and rendering glTF format.

    The purpose of this application is to learn and share how to draw using OpenGLES and Android. As this is my first android app, it is highly probable that there are bugs; but I will try to continue improving the app and adding more features.

    This project is open source, and contain classes that can solve your problem!

    0 讨论(0)
  • 2020-12-29 06:42

    Thank @Björn Kechel for very elegant implementation. I just want to add a case that may cause an undesirable result. Because a face can have more than 3 vertices, we should be able to deal with 4 vertices, likes below

    0 讨论(0)
提交回复
热议问题