I am new to OpenGL. I am using JOGL.
I downloaded this model. It has a bunch of textures. I'm trying to apply "truck_color-blue.jpg" here, but I'm not sure I'm doing it right. This is what I'm seeing:
Essentially, what I am doing is recording all the vt
, v
, and vn
entries, then using the f
lines to index into them. This is the code that makes the glTexCoord*()
call:
if (facePoint.textureIndex != null) {
Vector2f texCoords = getTexture(facePoint.textureIndex);
gl.glTexCoord2f(texCoords.x, texCoords.y);
}
// ...
Point3f vertex = getVertex(facePoint.vertexIndex);
gl.glVertex3f(vertex.x, vertex.y, vertex.z);
I suspect that I'm not correctly matching up the texture coords to the vertices. The model says that it is UV mapped. Does that mean I need to do textures differently?
My code to read .obj files:
public class ObjModel extends WorldEntity {
// ...
@Override
protected void buildDrawList() {
startDrawList();
for (Polygon poly : polygons) {
if (poly.getFaces().size() == 4) {
gl.glBegin(GL2.GL_QUADS);
} else {
gl.glBegin(GL2.GL_POLYGON);
}
for (FacePoint facePoint : poly.getFaces()) {
if (facePoint.vertexIndex == null) {
throw new RuntimeException("Why was there a face with no vertex?");
}
if (facePoint.textureIndex != null) {
Vector2f texCoords = getTexture(facePoint.textureIndex);
gl.glTexCoord2f(texCoords.x, texCoords.y);
}
if (facePoint.normalIndex != null) {
// why use both Vector3f and Point3f?
Vector3f normal = getNormal(facePoint.normalIndex);
gl.glNormal3f(normal.x, normal.y, normal.z);
}
Point3f vertex = getVertex(facePoint.vertexIndex);
gl.glVertex3f(vertex.x, vertex.y, vertex.z);
}
gl.glEnd();
}
endDrawList();
}
private Point3f getVertex(int index) {
if (index >= 0) {
// -1 is necessary b/c .obj is 1 indexed, but vertices is 0 indexed.
return vertices.get(index - 1);
} else {
return vertices.get(vertices.size() + index);
}
}
private Vector3f getNormal(int index) {
if (index >= 0) {
return normals.get(index - 1);
} else {
return normals.get(normals.size() + index);
}
}
private Vector2f getTexture(int index) {
if (index >= 0) {
return textures.get(index - 1);
} else {
return textures.get(textures.size() + index);
}
}
private void readFile(String fileName) {
try {
BufferedReader input = new BufferedReader(new FileReader(fileName));
try {
String currLine = null;
while ((currLine = input.readLine()) != null) {
int indVn = currLine.indexOf("vn ");
if (indVn != -1) {
readNormal(currLine);
continue;
}
int indV = currLine.indexOf("v ");
if (indV != -1) {
readVertex(currLine);
continue;
}
int indF = currLine.indexOf("f ");
if (indF != -1) {
readPolygon(currLine);
continue;
}
int indVt = currLine.indexOf("vt ");
if (indVt != -1) {
readTexture(currLine);
continue;
}
}
} finally {
input.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void readVertex(String newLine) {
String pieces[] = newLine.split("\\s+");
Point3f vertex = new Point3f(Float.parseFloat(pieces[1]), Float.parseFloat(pieces[2]), Float.parseFloat(pieces[3]));
vertices.add(vertex);
}
private void readNormal(String newLine) {
String pieces[] = newLine.split("\\s+");
Vector3f norm = new Vector3f(Float.parseFloat(pieces[1]), Float.parseFloat(pieces[2]), Float.parseFloat(pieces[3]));
normals.add(norm);
}
private void readTexture(String newLine) {
String pieces[] = newLine.split("\\s+");
Vector2f tex = new Vector2f(Float.parseFloat(pieces[1]), Float.parseFloat(pieces[2]));
textures.add(tex);
}
private void readPolygon(String newLine) {
polygons.add(new Polygon(newLine));
}
}
class Polygon represents a line like f 1/2/3 4/5/6 7/8/9
.
public class Polygon { private List faces = new ArrayList();
public Polygon(String line) {
if (line.charAt(0) != 'f') {
throw new IllegalArgumentException(String.format("Line must be a face definition, but was: '%s'", line));
}
String[] facePointDefs = line.split("\\s+");
// ignore the first piece - it will be "f ".
for (int i = 1; i < facePointDefs.length; i++) {
faces.add(new FacePoint(facePointDefs[i]));
}
}
public List<FacePoint> getFaces() {
return Collections.unmodifiableList(faces);
}
}
class FacePoint represents a face point, like 21/342/231
.
public class FacePoint {
private static final String FACE_POINT_REGEX = "^(\\d+)\\/(\\d+)?(\\/(\\d+))?$";
public Integer vertexIndex;
public Integer textureIndex;
public Integer normalIndex;
public FacePoint(String facePointDef) {
Matcher matcher = Pattern.compile(FACE_POINT_REGEX).matcher(facePointDef);
if (!matcher.find()) {
throw new IllegalArgumentException(String.format("facePointDef is invalid: '%s'", facePointDef));
}
String vertexMatch = matcher.group(1);
if (vertexMatch == null) {
throw new IllegalArgumentException(String.format("The face point definition didn't contain a vertex: '%s'",
facePointDef));
}
vertexIndex = Integer.parseInt(vertexMatch);
String texMatch = matcher.group(2);
if (texMatch != null) {
textureIndex = Integer.parseInt(texMatch);
}
String normalMatch = matcher.group(4);
if (normalMatch != null) {
normalIndex = Integer.parseInt(normalMatch);
}
}
}