How to read OBJ files in Godot

OBJ is a popular format for 3D meshes and one of the formats in which the 3D BAG is distributed. Because of this I wanted to be able to load OBJ files at runtime, just as I had previously done with ASCII lines and point clouds.

Loading OBJ

Luckily there’s a GDScript script that provides exactly this functionality. I got errors when loading a 3D BAG OBJ file and had to modify one line by adding a size check to the loaded vertices:

if (vertices_index.size() > 1):
    face["vt"].append(vertices_index[1].to_int() - 1)

The script returns a mesh that can be assigned to the mesh attribute of a MeshInstance3D and then added to the scene.

Dealing with large coordinates

Since the 3D BAG is in Dutch national coordinates, these large coordinates can cause issues. One solution is to recompile Godot for use of double-precision floating point numbers. The other is by computing and applying a global offset, which is the solution I’ve chosen for now. The offset is a Vector3 that is set to (-1,-1,-1), and gets computed upon loading the first vertex:

var n_v: Vector3 = Vector3(parts[1].to_float(), parts[2].to_float(), parts[3].to_float())
if offset.x<0:
    offset=_compute_offset(n_v)
    
vertices.append(n_v-offset)

I compute the offset by rounding to the closest multiple of 10:

static func _compute_offset(point:Vector3) -> Vector3:
    var newoffset := Vector3()
    newoffset.x = int(point.x/10)*10
    newoffset.y = int(point.y/10)*10
    newoffset.z = int(point.z/10)*10
    return newoffset

Don’t forget to somehow propagate this offset through your entire application and use it for other files that might be loaded.

Flipping coordinates

As mentioned before, Godot uses a standard computer graphics coordinate system with Z in viewing direction, whereas the 3D BAG has a standard geographic coordinate system with Z in up direction. This causes the buildings to be flipped:

I switched Y en Z coordinates during loading, but this caused issues with the normals and surfaces thus being drawn from the wrong side:

I tried to fix this by also switching the Y and Z coordinates of the normals, flipping the sign, and even recomputing the normals – without result. In the end the solution appeared to be to draw triangles the other way round – but then I saw that everything was mirrored, so something was wrong.

The Dutch coordinate system is a right-handed system with X towards east, Y towards north, and Z up. The Godot coordinate system is a right-handed system with X towards right, Y towards up, and Z towards the viewer. This means that simply switching Y and Z will not provide the desired result, as the Y coordinate will travel in the wrong direction. Instead the following convention needs to be applied:

  1. The global X (right) is the Godot Z (towards viewer).
  2. The global Y (north) is the Godot X (right).
  3. The global Z (up) is the Godot Y (up).

With this applied, I finally got proper orientation of the 3D model:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert