|
| 1 | +extends MeshInstance3D |
| 2 | + |
| 3 | +@export |
| 4 | +var material: ShaderMaterial |
| 5 | + |
| 6 | +@onready var camera = $"../TrackballCamera" |
| 7 | + |
| 8 | +func _ready() -> void: |
| 9 | + var test_path := "res://assets/Archicrop.obj" |
| 10 | + var imported_mesh = load_obj_at_runtime(test_path) |
| 11 | + if imported_mesh: |
| 12 | + self.mesh = imported_mesh |
| 13 | + self.mesh.surface_set_material(0, material) |
| 14 | + update_camera_position() |
| 15 | + else: |
| 16 | + print("Error reading OBJ file") |
| 17 | + |
| 18 | +func update_camera_position(): |
| 19 | + var max_position = self.mesh.get_aabb().get_longest_axis_size() |
| 20 | + var initial_position = camera.position |
| 21 | + camera.position = Vector3(initial_position.x,initial_position.y,max_position) |
| 22 | + |
| 23 | +func load_obj_at_runtime(file_path: String) -> ArrayMesh: |
| 24 | + var file = FileAccess.open(file_path, FileAccess.READ) |
| 25 | + if not file: return |
| 26 | + var text = file.get_as_text() |
| 27 | + file.close() |
| 28 | + |
| 29 | + var vertices: PackedVector3Array = [] |
| 30 | + var uvs: PackedVector2Array = [] |
| 31 | + var normals: PackedVector3Array = [] |
| 32 | + |
| 33 | + var st = SurfaceTool.new() |
| 34 | + st.begin(Mesh.PRIMITIVE_TRIANGLES) |
| 35 | + |
| 36 | + var lines = text.split("\n") |
| 37 | + for line in lines: |
| 38 | + line = line.strip_edges() |
| 39 | + if line.is_empty() or line.begins_with("#"): |
| 40 | + continue |
| 41 | + |
| 42 | + var parts = line.split(" ", false) |
| 43 | + var line_type = parts[0] |
| 44 | + |
| 45 | + match line_type: |
| 46 | + "v": # Position |
| 47 | + vertices.append(Vector3(float(parts[1]), float(parts[2]), float(parts[3]))) |
| 48 | + "vt": # UVs |
| 49 | + # OBJ Y-axis for UVs is inverted compared to Godot |
| 50 | + uvs.append(Vector2(float(parts[1]), 1.0 - float(parts[2]))) |
| 51 | + "vn": # Normal |
| 52 | + normals.append(Vector3(float(parts[1]), float(parts[2]), float(parts[3]))) |
| 53 | + "f": # Faces |
| 54 | + if parts.size() == 4: |
| 55 | + _add_face_vertex(parts[1], vertices, uvs, normals, st) |
| 56 | + _add_face_vertex(parts[2], vertices, uvs, normals, st) |
| 57 | + _add_face_vertex(parts[3], vertices, uvs, normals, st) |
| 58 | + elif parts.size() == 5: |
| 59 | + _add_face_vertex(parts[1], vertices, uvs, normals, st) |
| 60 | + _add_face_vertex(parts[2], vertices, uvs, normals, st) |
| 61 | + _add_face_vertex(parts[3], vertices, uvs, normals, st) |
| 62 | + |
| 63 | + _add_face_vertex(parts[1], vertices, uvs, normals, st) |
| 64 | + _add_face_vertex(parts[3], vertices, uvs, normals, st) |
| 65 | + _add_face_vertex(parts[4], vertices, uvs, normals, st) |
| 66 | + |
| 67 | + if normals.is_empty(): |
| 68 | + st.generate_normals() |
| 69 | + if not uvs.is_empty(): |
| 70 | + st.generate_tangents() |
| 71 | + |
| 72 | + return st.commit() |
| 73 | + |
| 74 | +func _add_face_vertex(token: String, vertices: PackedVector3Array, uvs: PackedVector2Array, normals: PackedVector3Array, st: SurfaceTool) -> void: |
| 75 | + var indices = token.split("/") |
| 76 | + if indices.size() > 1 and not indices[1].is_empty(): |
| 77 | + var uv_index = int(indices[1]) - 1 |
| 78 | + if uv_index < uvs.size(): |
| 79 | + st.set_uv(uvs[uv_index]) |
| 80 | + |
| 81 | + if indices.size() > 2 and not indices[2].is_empty(): |
| 82 | + var normal_index = int(indices[2]) - 1 |
| 83 | + if normal_index < normals.size(): |
| 84 | + st.set_normal(normals[normal_index]) |
| 85 | + |
| 86 | + var vertex_index = int(indices[0]) - 1 |
| 87 | + if vertex_index < vertices.size(): |
| 88 | + st.add_vertex(vertices[vertex_index]) |
0 commit comments