【问题标题】:How to load and display .obj file in Android with OpenGL-ES 2如何使用 OpenGL-ES 2 在 Android 中加载和显示 .obj 文件
【发布时间】:2017-04-22 02:47:55
【问题描述】:

我正在尝试将 .obj 文件加载到我的 Android 应用程序中并使用 OpenGL 2 显示它。

您可以在此处找到该文件:编辑:我删除了该文件,您可以使用任何包含下面提到的值的 .obj 文件进行测试。

stackoverflow上有很多类似的问题,但我没有找到不需要一些大型库的简单解决方案。

该文件仅包含以下值类型:

  • g
  • v
  • vt
  • vn
  • f

我尝试了 libgdx,它工作正常,但对于我需要的东西来说有点过头了。

我尝试了没有 LWJGL 的 oObjLoader https://github.com/seanrowens/oObjLoader。解析似乎有效,但如何在简单场景中显示值?

下一步是将图像作为纹理附加到对象。但现在我很乐意按原样显示文件。

我对不同的解决方案持开放态度,例如预转换文件,因为在应用程序中它只会是这个。

谢谢!

状态更新 基本加载和显示现在有效,如我自己的答案所示。

【问题讨论】:

  • 由于您使用的是 Android,因此您的问题很可能针对 OpenGL-ES 2 而不是 OpenGL 2。如果是这种情况,我建议您更新问题并相应地标记它。

标签: android opengl-es opengl-es-2.0


【解决方案1】:

我最终编写了一个新的解析器,可以像这样使用它来构建 FloatBuffers 以在您的渲染器中使用:

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

这是解析器:

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

【讨论】:

  • 嗨,我可以得到你的整个 ObjLoader 文件吗?我有一些问题。非常感谢
  • 您好,我对 opengles 非常陌生,您能指导我渲染缓冲区吗?感谢您的代码,我能够创建缓冲区,但未能重新渲染它。
  • 嗨,你能告诉我如何使用 GLES20 加载所有这些数据吗?
  • 你能解释一下如何使用这些位置、法线和纹理坐标来初始化对象吗?你能分享你的 draw() 方法吗?
【解决方案2】:

试试这个在 Github 上找到我的项目。 https://github.com/WenlinMao/android-3d-model-viewer

这是一个 OpenGL ES 2.0 的演示。它是一个带有 3D 引擎的 android 应用程序,可以加载 Wavefront OBJ、STL、DAE 和 glTF 文件。该应用程序基于 andresoviedo 的项目,可在此处找到,具有加载和渲染 glTF 格式的附加功能。

此应用程序的目的是学习和分享如何使用 OpenGLES 和 Android 进行绘图。由于这是我的第一个 android 应用程序,因此很可能存在错误;但我会尝试继续改进应用程序并添加更多功能。

这个项目是开源的,包含可以解决你问题的类!

【讨论】:

    【解决方案3】:

    感谢@Björn Kechel 非常优雅的实现。 我只想添加一个可能导致不良结果的案例。 因为一个面可以有超过 3 个顶点,我们应该可以处理 4 个顶点,如下所示

    【讨论】:

      【解决方案4】:

      当你有'obj'内容时试试这个代码来获取所有VerticesIndicesNormalsTexture Coords

      我希望它能提供一些帮助,这里是代码:

      void readObj(String objContents) {
              final float[] vertices;
              final float[] normals;
              final float[] textureCoords;
              final short[] indices;
      
              Vector<Float> verticesTemp = new Vector<>();
              Vector<Float> normalsTemp = new Vector<>();
              Vector<Float> textureCoordsTemp = new Vector<>();
              Vector<String> facesTemp = new Vector<>();
      
              String[] lines = objContents.split("\n");
              for (String line : lines) {
                  String[] parts = line.split(" ");
                  switch (parts[0]) {
                      case "v":
                          verticesTemp.add(Float.parseFloat(parts[1]));
                          verticesTemp.add(Float.parseFloat(parts[2]));
                          verticesTemp.add(Float.parseFloat(parts[3]));
                          break;
                      case "vn":
                          normalsTemp.add(Float.parseFloat(parts[1]));
                          normalsTemp.add(Float.parseFloat(parts[2]));
                          normalsTemp.add(Float.parseFloat(parts[3]));
                          break;
                      case "vt":
                          textureCoordsTemp.add(Float.parseFloat(parts[1]));
                          textureCoordsTemp.add(Float.parseFloat(parts[2]));
                          break;
                      case "f":
                          facesTemp.add(parts[1]);
                          facesTemp.add(parts[2]);
                          facesTemp.add(parts[3]);
                          break;
                  }
              }
      
              vertices = new float[verticesTemp.size()];
              normals = new float[normalsTemp.size()];
              textureCoords = new float[textureCoordsTemp.size()];
              indices = new short[facesTemp.size()];
      
              for (int i = 0, l = verticesTemp.size(); i < l; i++) {
                  vertices[i] = verticesTemp.get(i);
              }
              for (int i = 0, l = normalsTemp.size(); i < l; i++) {
                  normals[i] = normalsTemp.get(i);
              }
              for (int i = 0, l = textureCoordsTemp.size(); i < l; i++) {
                  textureCoords[i] = textureCoordsTemp.get(i);
              }
              for (int i = 0, l = facesTemp.size(); i < l; i++) {
                  indices[i] = (short) (Short.parseShort(facesTemp.get(i).split("/")[0]) - 1);
              }
              // now all vertices, normals, textureCoords and indices are ready
          }
      

      【讨论】:

        猜你喜欢
        • 2017-06-28
        • 1970-01-01
        • 2017-08-27
        • 1970-01-01
        • 2013-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多