Skip to main content
edited tags
Link
edited title
Link

OBJ file loader texture coordinates not loading correctly‘scrambled’

added 3859 characters in body
Source Link

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

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

Source Link
Loading