【问题标题】:OBJ Loader IndexOutOfBoundsOBJ 加载程序索引OutOfBounds
【发布时间】:2017-09-28 14:18:57
【问题描述】:

我正在编写一个 3D 引擎,而我的 OBJ LoaderClass 似乎对更复杂的模型有问题。

我得到一个 IndexOutOfBoundsException 并且我不知道为什么。 索引 3522 上的 ArrayList 纹理的值似乎会导致此异常,但为什么呢?

这是我的 OBJ 加载器类

        package graphics.renderEngine;

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.util.ArrayList;
    import java.util.List;

    import org.joml.Vector2f;
    import org.joml.Vector3f;

    import graphics.models.RawModel;

    public class OBJLoader 
    {

        public static RawModel loadObjModel(String fileName, Loader loader)
        {
            FileReader fr = null;
            try 
            {
                fr = new FileReader(new File("Ressources/Models/"+fileName+".obj"));
            } 
            catch (FileNotFoundException e) 
            {
                System.err.println("Could not load File!");
                e.printStackTrace();
            }
            BufferedReader reader = new BufferedReader(fr);
            String line;
            List<Vector3f> vertices = new ArrayList<Vector3f>();
            List<Vector2f> textures = new ArrayList<Vector2f>();
            List<Vector3f> normals = new ArrayList<Vector3f>();
            List<Integer> indices = new ArrayList<Integer>();
            float[] verticesArray = null;
            float[] normalsArray = null;
            float[] texturesArray = null;
            int[] indicesArray = null;

            try
            {
                while(true)
                {
                    line = reader.readLine();
                    String[] currentLine = line.split(" ");
                    if(line.startsWith("v "))
                    {
                        Vector3f vertex = new Vector3f(Float.parseFloat(currentLine[1]),Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                        vertices.add(vertex);
                    }
                    else if(line.startsWith("vt "))
                    {
                        Vector2f texture = new Vector2f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]));
                        textures.add(texture);
                    }
                    else if(line.startsWith("vn "))
                    {
                        Vector3f normal = new Vector3f(Float.parseFloat(currentLine[1]),Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                        normals.add(normal);
                    }
                    else if(line.startsWith("f "))
                    {
                        texturesArray = new float[vertices.size()*2];
                        normalsArray = new float[vertices.size()*3];
                        break;
                    }
                }

                while(line != null)
                {
                    if(!line.startsWith("f "))
                    {
                        line = reader.readLine();
                        continue;
                    }
                    String[] currentLine = line.split(" ");
                    String[] vertex1 = currentLine[1].split("/");
                    String[] vertex2 = currentLine[2].split("/");
                    String[] vertex3 = currentLine[3].split("/");

                    processVertex(vertex1, indices, textures, normals, texturesArray, normalsArray);
                    processVertex(vertex2, indices, textures, normals, texturesArray, normalsArray);
                    processVertex(vertex3, indices, textures, normals, texturesArray, normalsArray);
                    line = reader.readLine();
                }
                reader.close();

            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

            verticesArray = new float[vertices.size()*3];
            indicesArray = new int[indices.size()];

            int vertexPointer = 0;
            for (Vector3f vertex:vertices)
            {
                verticesArray[vertexPointer++] = vertex.x;
                verticesArray[vertexPointer++] = vertex.y;
                verticesArray[vertexPointer++] = vertex.z;
            }

            for(int i=0;i<indices.size();i++)
            {
                indicesArray[i] = indices.get(i);

            }
            return 
                    loader.loadToVAO
                    (verticesArray, 
                            texturesArray, 
                            normalsArray,
                            indicesArray);

        }

        private static void processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures, List<Vector3f> normals, float[] textureArray, float[] normalsArray)
        {
            System.out.println(textures.get(3522));
            int currentvertexPointer = Integer.parseInt(vertexData[0]) -1;
            indices.add(currentvertexPointer);
            Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1])-1);
            textureArray[currentvertexPointer*2] = currentTex.x;
            textureArray[currentvertexPointer*2+1] = 1 - currentTex.y;
            Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2])-1);
            normalsArray[currentvertexPointer*3] = currentNorm.x;
            normalsArray[currentvertexPointer*3+1] = currentNorm.y;
            normalsArray[currentvertexPointer*3+2] = currentNorm.z;
        }
 }

This is the OBJFile of the Model im trying to load

当我每次通过以下方式读出纹理值时:

System.out.println(textures.get(Integer.parseInt(vertexData[1])-1));

在例外之前我得到的最后一个向量是:

( 4.260E-1  1.275E-1)
( 4.650E-1  1.664E-1)
( 4.706E-1  1.621E-1)
( 4.650E-1  1.664E-1)
( 4.925E-1  2.140E-1)
( 1.340E-1  8.170E-2)
( 1.947E-1  4.650E-2)
( 1.902E-1  3.560E-2)

查看OBJ FIle后,除了最后两个,我无法按顺序找到。

这是我得到的异常

java.lang.IndexOutOfBoundsException: Index: 3522, Size: 3522
    at java.util.ArrayList.rangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at graphics.renderEngine.OBJLoader.processVertex(OBJLoader.java:122)
    at graphics.renderEngine.OBJLoader.loadObjModel(OBJLoader.java:82)
    at main.Main.init(Main.java:150)
    at main.Main.<init>(Main.java:82)
    at main.Main.main(Main.java:75)

我只是感到困惑,我不知道为什么会出现这个异常,提前感谢任何线索

【问题讨论】:

  • 如果有兴趣,here 我们有一个 assimp 的 jvm 端口,obj 已经支持

标签: java 3d lwjgl 3d-model


【解决方案1】:

列表的大小是 3522,其索引值在 0 到 3521 的范围内。但是您试图使用不存在的索引 3522 来访问列表中的元素,因此出现异常。在访问列表元素之前,您需要有条件检查索引是否小于大小。

【讨论】:

  • 像这样: if(textures.size() > Integer.parseInt(vertexData[1])-1) { currentTex = textures.get(Integer.parseInt(vertexData[1])-1) ; } ?
  • 我试过这个,然后我从以下所有数组中得到了多个其他 OutOfBounds 异常。假设我应该对所有这些异常都这样做,我做到了,但最终得到了一个甚至没有加载一半的模型
  • 好的,但是逻辑应该确保您正在访问大小限制内的元素。
【解决方案2】:

实际的问题是,一旦您看到第一个“f”(face)声明,您就会停止阅读“v”、“vt”和“vn”声明。您不能这样做,因为 Wavefront OBJ 规范没有规定“v*”声明必须位于“f”声明之前。事实上,在您的示例文件中,它们是混合在一起的。 这意味着,当您在第一个循环中停止阅读“v*”声明时,您最终会发现“f”声明引用了您未阅读的其他“v*”声明,因此您将获得 IndexOutOfBounds 异常。 您应该重新构建循环,以便随时可以读取“v*”和“f”声明。

【讨论】:

    【解决方案3】:

    看来你正在学习https://www.youtube.com/user/ThinMatrix的教程

    教程很好;它完美地工作。 (我以前用过)

    问题

    问题在于他的 OBJLoader 是特定于他选择的 OBJ 文件格式的,而不是“万能”的 OBJ-loader。

    他的格式如下: v/vt/vn/f/EOF

    而您的更像是: v/vt/vn/f/v/vt/vn/f/.../EOF

    您发布的代码假设找到第一行带有'f'的行后,将不再有顶点数据,之后将只有面部数据。

    因此,代码并未接收所有顶点数据,因此当您尝试索引该数据时,它不存在。

    修复

    对此有两种可能的解决方案:

    1. 通过允许代码接受文件中的所有数据,然后将其加载到缓冲区中,重新配置代码以在更一般的意义上工作。
    2. 重新构建您的 OBJ 文件,使其正确位于 ThinMatrix 概述的格式内。最简单的方法可能是复制/粘贴,尽管您可以创建一个为您执行此操作的程序。

    我猜由于您正在学习有关该主题的教程,因此您没有太多经验,最简单的方法是解决方案 2。

    【讨论】:

      【解决方案4】:

      检查
      return loader.loadToVAO(verticesArray,textureArray,indicesArray);

      这里有一些小的拼写错误,请参见 textureArray 的拼写 你定义了 texturesArray 有一个 s 。

      【讨论】:

      • 请在回答之前考虑格式化您的代码。此外,如果评论可以完成工作,请仅提供评论,而不是发布答案请参阅How do I write a good answer?
      猜你喜欢
      • 2023-03-27
      • 2012-08-15
      • 1970-01-01
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 2019-05-24
      • 2017-03-24
      • 1970-01-01
      相关资源
      最近更新 更多