2017-05-01 55 views
0

我正在编写一个3D引擎,我的OBJ LoaderClass似乎在更复杂的模型中遇到了问题。OBJ Loader IndexOutOfBounds

我得到一个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文件后,除了最后两个,我无法顺序查找。

这里是例外即时得到

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) 

我只是困惑,我不知道为什么我得到这个例外,在此先感谢任何线索

+0

如果有兴趣,[点击这里](https://github.com/java-graphics/assimp)我们有一个jimm端口的assimp,obj已经被支持了 – elect

回答

1

列表的大小是3522和索引值的范围为0到3521.但是,您尝试使用不存在的索引(即3522)来访问列表中的元素,因此是例外。在访问列表元素之前,您需要具备检查索引是否小于size的条件。

+0

像这样: \t \t if(textures.size()> Integer.parseInt(vertexData [1 ]) - 1) \t \t { \t \t \t currentTex = textures.get(Integer.parseInt(vertexData [1]) - 1); \t \t}? – Spytrycer

+0

是的,这是正确的。 – OTM

+0

我试过了,然后我从所有下面的数组中获得了多个其他OutOfBounds异常。假设我应该对所有这些例外做到这一点,那么,我做了,但最终没有一半加载模型 – Spytrycer

1

实际的问题是,一旦看到第一个'f'(脸部)声明,就停止阅读'v','vt'和'vn'声明。你不能这样做,因为Wavefront OBJ规范没有声明'v *'声明需要在'f'声明之前出现。事实上,在你的示例文件中,它们混合在一起。 这意味着,当您停止阅读第一个循环中的'v *'声明时,最终会找到引用其他未读取的'v *'声明的'f'声明,因此您将得到IndexOutOfBounds异常。 您应该重构您的循环,以便随时阅读'v *'以及'f'声明。

0

它看起来像你以下https://www.youtube.com/user/ThinMatrix

本教程是好的教程;它完美地工作。 (我以前使用过它)

的问题

的问题是,他的OBJLoader是针对他选择,而不是一个“万能” OBJ装载机OBJ文件的格式。

他的格式如下: V/VT/VN/F/EOF

而你更喜欢: V/VT/VN/F/V/VT/VN/F/.../EOF

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

因此,代码没有收到所有的顶点数据,所以当您尝试索引到该数据时,它不在那里。

的修复

有两种可能的解决方案是:

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

我猜,因为你是下面关于这个问题的教程,你没有与它太多的经验和最简单的路径,你将是解决数字2。