Я написал простой анализ волнового фронта для Java, который отображается в следующем разделе кода:
Исходный код
public class OBJLoader {
public static GameEntity loadObjModel(String fileName, String texturePath) throws Exception {
double start = System.nanoTime();
List<Vector3f> vertices = null;
List<Vector2f> textures = null;
List<Vector3f> normals = null;
List<Integer> indices = null;
String line;
float[] vertexPosArray = null;
float[] texturesArray = null;
float[] normalsArray = null;
int[] indicesArray = null;
try {
FileReader fr = new FileReader(new File("resources/models/" + fileName + ".obj"));
BufferedReader br = new BufferedReader(fr);
vertices = new ArrayList<>();
textures = new ArrayList<>();
normals = new ArrayList<>();
indices = new ArrayList<>();
//read v, vt and vn
while((line = br.readLine()) != null) {
line = br.readLine();
if (line != null || !line.equals("") || !line.startsWith("#")) {
String[] splitLine = line.split(" ");
switch(splitLine[0]) {
case "v":
Vector3f vertex = new Vector3f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]), Float.parseFloat(splitLine[3]));
vertices.add(vertex);
System.out.println("[OBJLoader.loadObjModel]: Vertex " + vertex.toString() + " has been added to vertices from " + fileName);
break;
case "vt":
Vector2f texture = new Vector2f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]));
textures.add(texture);
System.out.println("[OBJLoader.loadObjModel]: Texture coordinate [" + texture.x + ", " + texture.y + "] has been added to textures from " + fileName);
break;
case "vn":
Vector3f normal = new Vector3f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]), Float.parseFloat(splitLine[3]));
normals.add(normal);
System.out.println("OBJLoader.loadObjModel]: Normal " + normal + " has been added to normals from " + fileName);
break;
}
}
}
int numVertices = vertices.size();
texturesArray = new float[numVertices*2];
normalsArray = new float[numVertices*3];
//read f
while((line = br.readLine()) != null && line.startsWith("f")) {
String[] split = line.split(" ");
String[] v1 = split[1].split("/");
String[] v2 = split[2].split("/");
String[] v3 = split[3].split("/");
processVertex(v1, indices, textures, normals, texturesArray, normalsArray);
processVertex(v2, indices, textures, normals, texturesArray, normalsArray);
processVertex(v3, indices, textures, normals, texturesArray, normalsArray);
line = br.readLine();
}
br.close();
} catch (Exception e) {
System.err.print("[OBJLoader.loadObjModel]: Error loading obj model!");
e.printStackTrace();
}
vertexPosArray = new float[vertices.size()*3];
indicesArray = new int[indices.size()];
int i = 0;
for(Vector3f vertex : vertices) {
vertexPosArray[i++] = vertex.x;
vertexPosArray[i++] = vertex.y;
vertexPosArray[i++] = vertex.z;
}
for(int j = 0; j<indices.size(); j++) {
indicesArray[i] = indices.get(i);
}
double end = System.nanoTime();
double delta = (end - start) / 1000_000;
System.out.println("[OBJLoader.loadObjModel]: Vertices array of " + fileName + ": ");
ArrayUtils.displayFloatArray(vertexPosArray);
System.out.println("[OBJLoader.loadObjModel]: It took " + delta + " milliseconds to load " + fileName);
return new GameEntity(vertexPosArray, indicesArray, texturesArray, texturePath);
}
/**
* The input to this method is vertex data as a String array, which is used to determine how to
* arrange texture coordinate and normal vector data (this data is associated with each vertex position)
* into the correct order in the texture and normals array
* @param vertexData
* @param indices
* @param textrues
* @param normals
* @param textureArray
* @param normalsArray
*/
private static void processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures,
List<Vector3f> normals, float[] textureArray, float[] normalsArray) {
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;
}
}
Это волновой фронтФайл obj, который я пытаюсь прочитать (он представляет куб):
# Blender v2.78 (sub 0) OBJ File: 'cube.blend'
# www.blender.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.2766 0.2633
vt 0.5000 0.4867
vt 0.2766 0.4867
vt 0.7234 0.4867
vt 0.9467 0.2633
vt 0.9467 0.4867
vt 0.0533 0.4867
vt 0.0533 0.2633
vt 0.2766 0.0400
vt 0.5000 0.2633
vt 0.0533 0.7100
vt 0.7234 0.2633
vt 0.0533 0.0400
vt 0.2766 0.7100
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
s off
f 2/1/1 4/2/1 1/3/1
f 8/4/2 6/5/2 5/6/2
f 5/7/3 2/1/3 1/3/3
f 6/8/4 3/9/4 2/1/4
f 3/10/5 8/4/5 4/2/5
f 1/3/6 8/11/6 5/7/6
f 2/1/1 3/10/1 4/2/1
f 8/4/2 7/12/2 6/5/2
f 5/7/3 6/8/3 2/1/3
f 6/8/4 7/13/4 3/9/4
f 3/10/5 7/12/5 8/4/5
f 1/3/6 4/14/6 8/11/6
Как это должно было работать
Этот синтаксический анализатор obj должен читать содержимое файла obj,к которому получают доступ путь к файлу resources / models / MODELFILENAME.obj.
Сначала создается новый FileReader на основе пути к файлу, а затем используется этот экземпляр FileReader для создания Экземпляр BufferedReader , который используется для чтения каждой строки указанного файла.
Затем следует цикл while.Если достигнут конец файла, то цикл while завершен (строка переменной String, которая читается экземпляром BufferedReader, получает значение null в конце файла).
Цикл while выглядит следующим образом:это:
- читать новую строку
line = br.readLine();
- проверить, не является ли строка нулевой, не пустой или не начинается с хэштега:
if (line != null || !line.equals("") || !line.startsWith("#"))
- разбить строку чтения, где есть пробелы:
String[] splitLine = line.split(" ");
- выполнить соответствующий код на основе первой строки в
splitLine
(которая может быть v
, vt
, vn
или f
): switch(splitLine[0])
Если строка начинается с v
, то создайте новый объект Vector3f (трехмерный вектор, его конструктор - Vector3f(float x, float y, float z)
) из чиселкоторые стоят за v
.Эти числа доступны как первый, второй и третий индексы в массиве splitLine String из-за того, как символы пробела определены в файле .obj.Перед отправкой в конструктор они анализируются из строк в число с плавающей точкой.Затем в конце выведите строковое представление Vector3f на консоль
Аналогично, процесс повторяется для координат текстуры (только вместо создания Vector3f, создается Vector2f) и нормальных векторов.
Нет смысла объяснять оставшийся исходный код, так как проблема здесь уже возникает.
Проблема
Кажется, вышеупомянутый анализатор файлов читает только половину данных (it "«перебрасывает» каждую вторую строку и не может ее обработать).
Это вывод, который показывает, какие строки, начиная с v
, были обработаны (т.е. Vector3f сделаны из их данных):
[OBJLoader.loadObjModel]: Vertex 1.0 -1.0 -1.0 has been added to vertices from cube
[OBJLoader.loadObjModel]: Vertex -1.0 -1.0 1.0 has been added to vertices from cube
[OBJLoader.loadObjModel]: Vertex 1.0 1.0 -0.999999 has been added to vertices from cube
[OBJLoader.loadObjModel]: Vertex -1.0 1.0 1.0 has been added to vertices from cube
Это данные для v
в файле obj:
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
Если вы сравните данные, вскоре станет очевидно, что обрабатываются только 4 строки вместо 8. Перваястрока прочитана, вторая пропущена.Третья строка читается, четвертая пропускается.И так продолжается.Почему возникает проблема?Есть ли ошибки в операторе switch, из-за которых пропускаются строки?
Спасибо за потраченное время.