我的obj-parser可能有什么问题?

时间:2015-02-06 16:54:59

标签: java opengl .obj

给定以下渲染对象(具有完全白色纹理的龙)并使用基本纹理停止。可能是什么错误?我的指数错了吗?是否有一些顶点或面错了?

Stall with textureDragon should be completely white

我的obj-renderer课程可能出现什么问题?我按照教程进行操作,不幸的是我的模型看起来不像所需的模型。龙应该是完全白色的,没有任何黑线,并且失速纹理看起来不对(白线不应该在那里)。

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

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;
}

1 个答案:

答案 0 :(得分:2)

用于组合顶点坐标,纹理坐标和法线的逻辑看起来有缺陷。这里无法解决的最明显迹象是:

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;

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

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

这两个顶点具有相同的顶点坐标,但纹理坐标不同。由于第一个索引是相同的,因此当您在currentVertexPointer中指定值时,将使用相同的textureArray索引,即使这些是需要不同纹理坐标的两个不同顶点。

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

解释这一点的一种方法是v记录不会给你顶点。它们为您提供了顶点帖子。您为每个顶点提取3个属性,这些属性的处理方式相同:

  • v记录:职位。
  • vt记录:纹理坐标。
  • vn记录:normals。

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

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

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;

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

  • 现在使用,currentVertexPointer需要为每个顶点递增。
  • 由于尺寸取决于面部的数量,因此您不会提前verticesArraytextureArraynormalsArray设置上限。您需要动态调整这些数组的大小,或者使用为您处理此数组的容器。
  • 不再需要构建verticesArray的后续代码,因为它现在与其他数组一起构建。
  • 你真的不需要这种方法的指数。您可以使用glDrawArrays()
  • 进行绘制

更有效的解决方案是为位置/纹理/法线的每个唯一组合共享顶点。请参阅我的答案Why is my OBJ parser rendering meshes like this?OpenGL - Index buffers difficulties,了解如何执行此操作。

除此之外,你的解析器也非常有限。 OBJ实际上不是一种标准化的格式,它取决于你想要处理来自各种来源的文件的程度。您的代码未处理的方面包括: