OBJ加载 - 奇怪的法线/ uvs

时间:2015-07-07 12:07:14

标签: java opengl lwjgl wavefront

所以,我试图用Java加载(Wavefront)OBJ模型。目前它正确加载顶点位置但纹理坐标混乱:

这就是我在引擎中看到的:

enter image description here

这是我在搅拌机中看到的:

enter image description here

我目前的加载代码在这里:

 private void loadOBJ(String filename)
    {
    ArrayList<Vector3f> verts = new ArrayList<Vector3f>();
    ArrayList<Vector3f> norms = new ArrayList<Vector3f>();
    ArrayList<Vector2f> uvs = new ArrayList<Vector2f>();
    ArrayList<Integer> ints = new ArrayList<Integer>(); //Indices
    ArrayList<Integer> nints = new ArrayList<Integer>(); //Normal indices
    ArrayList<Integer> tints = new ArrayList<Integer>(); //Texture coord indices


    try {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        String line;

        while ((line = reader.readLine()) != null) {
            String[] tokens = line.split(" ");


            if(tokens[0].startsWith("vn"))
            {
                norms.add(new Vector3f(Float.parseFloat(tokens[1]), 
                                       Float.parseFloat(tokens[2]), 
                                       Float.parseFloat(tokens[3])));   
            }
            else if(tokens[0].startsWith("vt"))
            {
                uvs.add(new Vector2f(Float.parseFloat(tokens[1]), 
                                     Float.parseFloat(tokens[2])));
            }
            else if(tokens[0].startsWith("v")) 
            {
                verts.add(new Vector3f(Float.parseFloat(tokens[1]), 
                                       Float.parseFloat(tokens[2]), 
                                       Float.parseFloat(tokens[3])));
            }
            else if(tokens[0].startsWith("f"))
            {
                ints.add(Integer.parseInt(tokens[1].split("/")[0]) - 1);
                ints.add(Integer.parseInt(tokens[2].split("/")[0]) - 1);
                ints.add(Integer.parseInt(tokens[3].split("/")[0]) - 1);

                tints.add(Integer.parseInt(tokens[1].split("/")[1]) - 1);
                tints.add(Integer.parseInt(tokens[2].split("/")[1]) - 1);
                tints.add(Integer.parseInt(tokens[3].split("/")[1]) - 1);

                nints.add(Integer.parseInt(tokens[1].split("/")[2]) - 1);
                nints.add(Integer.parseInt(tokens[2].split("/")[2]) - 1);
                nints.add(Integer.parseInt(tokens[3].split("/")[2]) - 1);

                if(tokens.length > 4) //For quads
                {
                    ints.add(Integer.parseInt(tokens[1].split("/")[0]) - 1);
                    ints.add(Integer.parseInt(tokens[4].split("/")[0]) - 1);
                    ints.add(Integer.parseInt(tokens[2].split("/")[0]) - 1);

                    tints.add(Integer.parseInt(tokens[1].split("/")[1]) - 1);
                    tints.add(Integer.parseInt(tokens[4].split("/")[1]) - 1);
                    tints.add(Integer.parseInt(tokens[2].split("/")[1]) - 1);

                    nints.add(Integer.parseInt(tokens[1].split("/")[2]) - 1);
                    nints.add(Integer.parseInt(tokens[4].split("/")[2]) - 1);
                    nints.add(Integer.parseInt(tokens[2].split("/")[2]) - 1);
                }
            }

        }
        reader.close();


    } catch (IOException e) {
        System.err.println("Could not read file.");
        e.printStackTrace();
        System.exit(-1);
    }

    //Now convert the loaded data to internal format: VertexData[] that con tains positions, uvs, and normals, and int[] that has indices

    vertices = new VertexData[verts.size()];
    indices = new int[ints.size()];

    for(int i = 0; i < ints.size(); i++)
    {
        indices[i] = ints.get(i);
        int j = ints.get(i);
        int k = tints.get(i);
        int q = nints.get(i);

        vertices[j] = new VertexData();

        vertices[j].setXYZ(verts.get(j).x, verts.get(j).y, verts.get(j).z);
        vertices[j].setST(uvs.get(k).x, uvs.get(k).y);
        vertices[j].setNormal(norms.get(q).x, norms.get(q).y, norms.get(q).z);
    }

}

正如你从图片中看到的那样,当前的代码很容易正确加载uvs,但我无法弄清楚什么是错误的。帮助

2 个答案:

答案 0 :(得分:0)

代码看起来很好。

这可能是一个出口问题。也许纹理坐标系还原。 尝试翻转它:

  

u = u

     

v = 1 - v

答案 1 :(得分:0)

您的代码无法正确生成适合GL的顶点数据。如您所知,在obj格式中,顶点位置,法线,texcoords等都有一个单独的数组。面孔是通过独立索引形成的。在GL中,顶点是其所有属性的集合,并且您不能对每个属性使用单独的索引(至少不能直接使用;现代GL足够灵活,允许您在顶点着色器中实现该间接级别,但这将是另一个故事。)

您的代码可能会尝试解决此问题,但解决方案是错误的。您只需使用OBJ文件中的顶点索引作为全局索引,并使用其他索引编写包含所有属性的顶点,无论如何,如果相同的顶点索引可能与法线或texcoords的不同组合一起使用 - 你只需用最后一个这样的组合覆盖它。

coorect方法将为发生的每个唯一(顶点,法线,texcoord)组合创建单独的顶点。因此,顶点的数量当然会增加,并且索引值也不能直接重用于元素数组。