Edit
I've rewritten the loader to duplicate data if only one element (v, vt, vn) is different. I get a much better result, but it is still incorrect. The seams on the mesh match what they should look like, but the texture appears a bit deformed. I've checked a list of the texture coords, and there appear to be some missing, but I don't understand how this could happen.
Here is the new code:
int bytesLoaded = 0;
ArrayList<Float> vertices = new ArrayList<>();
ArrayList<Float> textureCoords = new ArrayList<>();
ArrayList<Float> normals = new ArrayList<>();
ArrayList<Float> plainVertices = new ArrayList<>();
ArrayList<Float> plainTextureCoords = new ArrayList<>();
ArrayList<Float> plainNormals = new ArrayList<>();
ArrayList<Integer> indices = new ArrayList<>();
ArrayList<String> writtenData = new ArrayList<>();
String line;
try {
InputStream stream = IO.class.getClassLoader().getResourceAsStream(filePath); //get file off classpath
BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); //create file reader
while((line = reader.readLine())!=null) { //repeat until document's end has been reached
String[] data = line.split(" "); //split line into each data point
if (line.startsWith("v ")) { //add vertices in the 3 data points, excluding the first which is the "v"
for (int i=1; i<4; i++) {
plainVertices.add(Float.parseFloat(data[i]));
}
} else if (line.startsWith("vt ")) {
for (int i=1; i<3; i++) {
plainTextureCoords.add(Float.parseFloat(data[i])); //add vertex textures in the 2 data points, excluding the first which is the "vt"
}
} else if (line.startsWith("vn ")) {
for (int i=1; i<4; i++) {
plainNormals.add(Float.parseFloat(data[i])); //add vertices in the 3 data points, excluding the first which is the "vn"
}
} else if (line.startsWith("f ")) { //indices
for (int i = 1; i<4; i++) {
String[] faceIndices = data[i].split("/"); //split each face into v indice, vt indice and vn indice
int vertexIndex = Integer.parseInt(faceIndices[0]) - 1; //get the indices, subtract 1 because OpenGL indices are 0 indexed
int textureCoordIndex = Integer.parseInt(faceIndices[1]) - 1;
int normalIndex = Integer.parseInt(faceIndices[2]) - 1;
StringBuilder tokenBuilder = new StringBuilder(); //generate a unique token to prevent repeats
tokenBuilder.append(vertexIndex);
tokenBuilder.append("+");
tokenBuilder.append(textureCoordIndex);
tokenBuilder.append("+");
tokenBuilder.append(normalIndex);
String token = tokenBuilder.toString();
System.out.println(token);
if (!writtenData.contains(token)) { //add the 3 indices' values to their list
writtenData.add(token);
vertices.add(plainVertices.get(vertexIndex * 3));
vertices.add(plainVertices.get(vertexIndex * 3 + 1));
vertices.add(plainVertices.get(vertexIndex * 3 + 2));
textureCoords.add(plainTextureCoords.get(textureCoordIndex * 2));
textureCoords.add(plainTextureCoords.get(textureCoordIndex * 2 + 1));
normals.add(plainNormals.get(normalIndex * 3));
normals.add(plainNormals.get(normalIndex * 3 + 1));
normals.add(plainNormals.get(normalIndex * 3 + 2));
}
indices.add(writtenData.indexOf(token)); //generate an index
}
}
bytesLoaded = bytesLoaded + line.getBytes().length; //keep track of bytes loaded
//System.out.println(bytesLoaded);
}
Original