我的obj-parser有什么问题? [英] What could be wrong with my obj-parser?

查看:97
本文介绍了我的obj-parser有什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下渲染对象(具有完全白色纹理的龙)并使用基本纹理进行停顿.可能是什么错误?我的索引有误吗?有些顶点或面不对吗?

Given the following rendered objects (dragon with completely white texture) and stall with a basic texture. What might be the error? Are my indices wrong? Are some vertices or faces wrong?

:

我的obj-renderer类可能出什么问题了?我遵循了一个教程,但是不幸的是我的模型看起来不像所需的模型.龙应该是完全白色的,没有任何黑线,并且失速纹理看起来不对(白线不应该在那里).

What could possibly be wrong in my obj-renderer class? I followed a tutorial and unfortunately my model does not look like the desired model. The dragon should be completely white without any black lines and the stall texture looks wrong (white lines which shouldn't be there).

这是源代码(基本的.obj渲染,带有"v","vt","vn","f"):

This is the source-code (basic .obj-rendering with "v ", "vt ", "vn ", "f "):

try {
  while ((line = reader.readLine()) != null && !line.startsWith("f ")) {
    String[] currentLine = line.split(" ");
    if (line.startsWith("v ")) {
      Vector3f vertex =
          new Vector3f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]),
              Float.parseFloat(currentLine[3]));
      vertices.add(vertex);
    } else if (line.startsWith("vt ")) {
      Vector2f texture =
          new Vector2f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]));
      textures.add(texture);
    } else if (line.startsWith("vn ")) {
      Vector3f normal =
          new Vector3f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]),
              Float.parseFloat(currentLine[3]));
      normals.add(normal);
    }
  }

  textureArray = new float[vertices.size() * 2];
  normalsArray = new float[vertices.size() * 3];
  do {
    if (line == null || !line.startsWith("f ")) {
      continue;
    }
    String[] currentLine = line.split(" ");
    String[] vertex1 = currentLine[1].split("/");
    String[] vertex2 = currentLine[2].split("/");
    String[] vertex3 = currentLine[3].split("/");

    processVertex(vertex1, indices, textures, normals, textureArray, normalsArray);
    processVertex(vertex2, indices, textures, normals, textureArray, normalsArray);
    processVertex(vertex3, indices, textures, normals, textureArray, normalsArray);
  } while ((line = reader.readLine()) != null);

  reader.close();
} catch (Exception e) {
  e.printStackTrace();
}

verticesArray = new float[vertices.size() * 3];
indicesArray = new int[indices.size()];

int vertexPointer = 0;
for (Vector3f vertex : vertices) {
  verticesArray[vertexPointer++] = vertex.x;
  verticesArray[vertexPointer++] = vertex.y;
  verticesArray[vertexPointer++] = vertex.z;
}
for (int i = 0; i < indices.size(); i++) {
  indicesArray[i] = indices.get(i);
}
return loader.loadToVao(verticesArray, textureArray, normalsArray, indicesArray);
}

private static void processVertex(final String[] vertexData, final List<Integer> indices,
  final List<Vector2f> textures, final List<Vector3f> normals, final float[] textureArray,
  final 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;
}

推荐答案

用于组合顶点坐标,纹理坐标和法线的逻辑看起来有缺陷.为何无法正常工作的最明显迹象是在这里:

The logic used for combining vertex coordinates, texture coordinates, and normals looks flawed. The clearest sign of why this cannot work is here:

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;

想象一下,如果有多个顶点具有相同的坐标,但纹理坐标不同,则会发生什么情况.假设您将以下索引三元组作为不同面孔的一部分:

Picture what happens if there are multiple vertices with the same coordinates, but different texture coordinates. Say you have the following index triplets as part of different faces:

f ... 4/7/13 ...
f ... 4/9/13 ...

这是两个具有相同顶点坐标但具有不同纹理坐标的顶点.由于第一个索引相同,因此即使在这两个需要不同纹理坐标的不同顶点上,在textureArray中分配值时,也会使用相同的currentVertexPointer索引.

These are two vertices with the same vertex coordinates, but different texture coordinates. Since the first index is the same, you would be using the same currentVertexPointer index when you assign values in textureArray, even though these are two different vertices that need different texture coordinates.

要理解的关键点是,由于OpenGL对所有顶点属性使用相同的索引,因此需要一个顶点来顶点坐标,纹理坐标和法线的每个唯一组合.

The key point to understand is that since OpenGL uses the same indices for all vertex attributes, you need a vertex for each unique combination of vertex coordinates, texture coordinates, and normals.

一种解释方式是v记录不给您顶点.它们为您提供顶点位置.您为每个顶点提取3个属性,对它们的处理方式相同:

One way of interpreting this is that the v records do not give you vertices. They give you vertex postitions. You extract 3 attributes for each vertex, which are all treated the same:

  • v记录:职位.
  • vt记录:纹理坐标.
  • vn记录:常态.
  • v records: positions.
  • vt records: texture coordinates.
  • vn records: normals.

您可以通过组合这3个属性来构建顶点. f记录告诉您如何组合它们.

You build vertices by combining these 3 attributes. The f records tell you how to combine them.

构建OpenGL顶点的最简单方法是为您在解析面孔时遇到的每个索引三元组生成一个新顶点.如果您想以相对较小的更改来运行代码,则可以将verticesArray更像是textureArraynormalsArray.您的processVertex()函数将如下所示:

The easiest way to build OpenGL vertices is to generate a new vertex for each index triplet you encounter while parsing the faces. If you wanted to get your code running with relatively minimal changes, you could treat your verticesArray much more like the textureArray and normalsArray. Your processVertex() function would then look something like this:

Vector3f currentVertex = vertices.get(Integer.parseInt(vertexData[0]) - 1);
verticesArray[currentVertexPointer * 3] = currentVertex.x;
verticesArray[currentVertexPointer * 3 + 1] = currentVertex.y;
verticesArray[currentVertexPointer * 3 + 2] = currentVertex.z;
Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
textureArray[currentVertexPointer * 2] = currentTex.x;
textureArray[currentVertexPointer * 2 + 1] = 1 - currentTex.y;

这将需要更多相关的更改.代替重写整个代码,这里至少有一些指针:

This will require more related changes. In place of rewriting your whole code, here are at least some pointers:

  • 到现在为止,每个顶点的currentVertexPointer都需要增加.
  • 您没有提前设置verticesArraytextureArraynormalsArray的上限,因为大小取决于面孔的数量.您需要动态调整这些数组的大小,或使用一个可以为您处理此问题的容器.
  • 不再需要用于构建verticesArray的更高版本的代码,因为它现在是与其他数组一起构建的.
  • 您实际上不需要此方法的索引.您可以使用glDrawArrays()进行绘制.
  • As used now, currentVertexPointer will need to be incremented for each vertex.
  • You don't have an upper limit for verticesArray, textureArray and normalsArray ahead of time, since the size depends on the number of faces. You'll need to size these arrays dynamically, or use a container that handles this for you.
  • The later code for building verticesArray is not needed anymore, since it is now built with the other arrays.
  • You don't really need indices for this approach. You can draw with glDrawArrays().

一种更有效的解决方案是为位置/纹理/法线的每个唯一组合共享顶点.查看我的答案为什么我的OBJ分析器呈现网格 OpenGL-索引缓冲困难该怎么做.

A more efficient solution is to share vertices for each unique combination of position/texture/normal. See my answers Why is my OBJ parser rendering meshes like this? and OpenGL - Index buffers difficulties for directions on how to do that.

除此之外,您的解析器也非常有限. OBJ并不是真正的标准化格式,这完全取决于您要如何处理各种来源的文件.您的代码无法处理的方面包括:

Beyond this, your parser is also very limited. OBJ is not really a standardized format, and it all depends on how well you want to handle files from various sources. Aspects that your code is not handling include:

  • Face records that are intermixed with other records. Your code assumes that they are all at the end, which is not required.
  • Negative indices.
  • Faces with more than 3 vertices (see Converting quadriladerals in an OBJ file into triangles?).

这篇关于我的obj-parser有什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆