Загрузка OBJ - странные нормали / увы
Итак, я пытаюсь загрузить (Wavefront) OBJ-модели в Java. В настоящее время он правильно загружает позиции вершин, но текстурные координаты испорчены:
Вот что я вижу в двигателе:
Вот что я вижу в блендере:
Мой текущий код загрузки здесь:
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 ответа
Ваш код неправильно генерирует данные вершин, подходящие для GL. Как вы знаете, в формате obj существует отдельный массив для положения вершины, нормали, текстовых координат и так далее. И лица формируются путем независимой индексации в них. В GL вершина - это набор всех ее атрибутов, и вы не можете использовать отдельные индексы для каждого атрибута (по крайней мере, не напрямую; современный GL достаточно гибок, чтобы позволить вам реализовать этот уровень косвенности в вершинном шейдере, но это была бы другая история).
Возможно, ваш код пытается это исправить, но решение неверное. Вы просто используете индекс вершины из файла OBJ в качестве глобального индекса и пишете свою вершину, содержащую все атрибуты, используя другие индексы, независимо от того, если тот же индекс вершин может использоваться с другой комбинацией нормалей или текстовых координат - вы просто перезаписать его последней такой комбинацией.
При правильном подходе создается отдельная вершина для каждой уникальной комбинации (вершина, нормаль, текстовая координата). В результате число вершин, конечно, увеличится, и значение индекса также нельзя будет повторно использовать непосредственно для массива элементов.
Код выглядит хорошо.
Это может быть проблема экспорта. Возможно, система координат текстуры перевернута. Попробуйте перевернуть это:
ты = ты
v = 1 - v