2017-05-01 78 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。