web-dev-qa-db-fra.com

Comment charger et afficher un fichier .obj dans Android avec OpenGL-ES 2

J'essaie de charger un fichier .obj dans mon application Android et de l'afficher à l'aide d'OpenGL 2.

Vous pouvez trouver le fichier ici: EDIT: J'ai supprimé le fichier, vous pouvez utiliser n'importe quel fichier .obj contenant les valeurs mentionnées ci-dessous à des fins de test.

Il y a beaucoup de questions similaires sur stackoverflow mais je n'ai pas trouvé de solution simple qui ne nécessite pas de grande bibliothèque.

Le fichier ne contient que les types de valeur suivants:

  • g
  • v
  • vermont
  • vn
  • f

J'ai essayé libgdx, qui a bien fonctionné, mais c'est un peu exagéré pour ce dont j'ai besoin.

J'ai essayé le oObjLoader https://github.com/seanrowens/oObjLoader sans le LWJGL. L'analyse semble fonctionner, mais comment puis-je afficher les valeurs dans une scène simple?

L'étape suivante consiste à attacher une image sous forme de texture à l'objet. Mais pour l'instant, je serais heureux d'afficher le fichier tel qu'il est.

Je suis ouvert à différentes solutions telles que la pré-conversion du fichier, car ce ne sera que celui-ci au sein de l'application.

Merci!

Mise à jour du statut Le chargement et l'affichage de base fonctionnent maintenant, comme indiqué dans ma propre réponse. 

17
Björn Kechel

J'ai fini par écrire un nouvel analyseur, il peut être utilisé comme ceci pour construire FloatBuffers à utiliser dans votre moteur de rendu:

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

et voici l'analyseur:

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);
        }
    }
}
7
Björn Kechel

Comme vous pouvez analyser les fichiers obj, référez-vous à ceci post may vous aidera beaucoup.

Il existe un moyen plus simple, utilisez le three.js objloader . Utilisez XWalkView pour ajouter la page Web dans votre application Android. XWalkView est quelque chose qui ressemble à webview, ici workview peut ne pas fonctionner pour le rendu de scènes complexes, alors que XWalkView dispose de . Si vous ne rendez pas la page Web distante, vous pouvez la rendre locale.

0
Kris Roofe