diff --git a/.gitignore b/.gitignore index f6fd9b2..302eaf4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # Godot 4+ specific ignores .godot/* -*.ply \ No newline at end of file +*.ply +point_cloud.ply.import \ No newline at end of file diff --git a/addons/point_cloud_importer/PointCloudData.gd b/addons/point_cloud_importer/PointCloudData.gd new file mode 100644 index 0000000..e8213f7 --- /dev/null +++ b/addons/point_cloud_importer/PointCloudData.gd @@ -0,0 +1,129 @@ +class_name PointCloudData extends Resource + +static var num_coeffs = 45 +static var num_coeffs_per_color = num_coeffs / 3 +static var sh_degree = sqrt(num_coeffs_per_color + 1) - 1 + +@export var positions = PackedFloat32Array() +@export var normals = PackedFloat32Array() +@export var opacities = PackedFloat32Array() +@export var scales = PackedFloat32Array() +@export var rotations = PackedFloat32Array() +@export var sh_coeffs = PackedFloat32Array() +@export var depths = PackedFloat32Array() +@export var depth_index = PackedInt32Array() +@export var num_vertex: int + +func _init(): + num_coeffs = 45 + num_coeffs_per_color = num_coeffs / 3 + sh_degree = sqrt(num_coeffs_per_color + 1) - 1 + + +static func load_ply_file(filename: String) -> PointCloudData: + var point_cloud_data = PointCloudData.new() + var file = FileAccess.open(filename, FileAccess.READ) + + if not file: + print("Failed to open file: " + filename) + return point_cloud_data + + var num_vertex = 0 +#num_vertex = 0 + + # Read header + var line = file.get_line() + while not file.eof_reached(): + if line.begins_with("element vertex"): + num_vertex = int(line.split(" ")[2]) + if line.begins_with("end_header"): + break + line = file.get_line() + + var coeffs = [] + + for i in range(num_vertex): + var vertex = { + "x": file.get_float(), + "y": file.get_float(), + "z": file.get_float(), + "nx": file.get_float(), + "ny": file.get_float(), + "nz": file.get_float(), + "f_dc_0": file.get_float(), + "f_dc_1": file.get_float(), + "f_dc_2": file.get_float(), + "f_rest_0": file.get_float(), + "f_rest_1": file.get_float(), + "f_rest_2": file.get_float(), + "f_rest_3": file.get_float(), + "f_rest_4": file.get_float(), + "f_rest_5": file.get_float(), + "f_rest_6": file.get_float(), + "f_rest_7": file.get_float(), + "f_rest_8": file.get_float(), + "f_rest_9": file.get_float(), + "f_rest_10": file.get_float(), + "f_rest_11": file.get_float(), + "f_rest_12": file.get_float(), + "f_rest_13": file.get_float(), + "f_rest_14": file.get_float(), + "f_rest_15": file.get_float(), + "f_rest_16": file.get_float(), + "f_rest_17": file.get_float(), + "f_rest_18": file.get_float(), + "f_rest_19": file.get_float(), + "f_rest_20": file.get_float(), + "f_rest_21": file.get_float(), + "f_rest_22": file.get_float(), + "f_rest_23": file.get_float(), + "f_rest_24": file.get_float(), + "f_rest_25": file.get_float(), + "f_rest_26": file.get_float(), + "f_rest_27": file.get_float(), + "f_rest_28": file.get_float(), + "f_rest_29": file.get_float(), + "f_rest_30": file.get_float(), + "f_rest_31": file.get_float(), + "f_rest_32": file.get_float(), + "f_rest_33": file.get_float(), + "f_rest_34": file.get_float(), + "f_rest_35": file.get_float(), + "f_rest_36": file.get_float(), + "f_rest_37": file.get_float(), + "f_rest_38": file.get_float(), + "f_rest_39": file.get_float(), + "f_rest_40": file.get_float(), + "f_rest_41": file.get_float(), + "f_rest_42": file.get_float(), + "f_rest_43": file.get_float(), + "f_rest_44": file.get_float(), + "opacity": file.get_float(), + "scale_0": file.get_float(), + "scale_1": file.get_float(), + "scale_2": file.get_float(), + "rot_0": file.get_float(), + "rot_1": file.get_float(), + "rot_2": file.get_float(), + "rot_3": file.get_float() + } + + point_cloud_data.positions.append_array([vertex["x"], vertex["y"], vertex["z"], 0]) + point_cloud_data.opacities.append(vertex["opacity"]) + point_cloud_data.scales.append_array([vertex["scale_0"], vertex["scale_1"], vertex["scale_2"], 0]) + point_cloud_data.rotations.append_array([vertex["rot_0"], vertex["rot_1"], vertex["rot_2"], vertex["rot_3"]]) + point_cloud_data.depth_index.append(i) + point_cloud_data.depths.append(0) + + var coeff = [vertex["f_dc_0"], vertex["f_dc_1"], vertex["f_dc_2"]] + for j in range(num_coeffs_per_color): + coeff.append_array([ + vertex["f_rest_%d" % (0 * num_coeffs_per_color + j)], + vertex["f_rest_%d" % (1 * num_coeffs_per_color + j)], + vertex["f_rest_%d" % (2 * num_coeffs_per_color + j)] + ]) + point_cloud_data.sh_coeffs.append_array(coeff) + + file.close() + point_cloud_data.num_vertex = num_vertex + return point_cloud_data diff --git a/addons/point_cloud_importer/editor_plugin.gd b/addons/point_cloud_importer/editor_plugin.gd new file mode 100644 index 0000000..36f72cf --- /dev/null +++ b/addons/point_cloud_importer/editor_plugin.gd @@ -0,0 +1,15 @@ +@tool +extends EditorPlugin + + +var point_cloud_importer + + +func _enter_tree(): + point_cloud_importer = preload("point_cloud_importer.gd").new() + add_import_plugin(point_cloud_importer) + + +func _exit_tree(): + remove_import_plugin(point_cloud_importer) + point_cloud_importer = null diff --git a/addons/point_cloud_importer/plugin.cfg b/addons/point_cloud_importer/plugin.cfg new file mode 100644 index 0000000..db84a69 --- /dev/null +++ b/addons/point_cloud_importer/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Point cloud importer" +description="" +author="SrColoma" +version="" +script="editor_plugin.gd" diff --git a/addons/point_cloud_importer/point_cloud_importer.gd b/addons/point_cloud_importer/point_cloud_importer.gd new file mode 100644 index 0000000..56dde90 --- /dev/null +++ b/addons/point_cloud_importer/point_cloud_importer.gd @@ -0,0 +1,55 @@ +# DefiniciĆ³n del plugin de importaciĆ³n +@tool +extends EditorImportPlugin + +func _get_import_options(path, preset_index: int) -> Array: + return [ + { + "name": "Generate Normals", + "default_value": false + } + ] + +func _get_importer_name() -> String: + return "point_cloud_importer" + +func _get_visible_name() -> String: + return "Point Cloud Importer" + +func _get_recognized_extensions() -> PackedStringArray: + return ["ply"] + +func _get_save_extension() -> String: + return "tres" + +func _get_priority() -> float: + return 1.0 + +func _get_import_order() -> int: + return 0 + +func _get_resource_type() -> String: + return "Resource" + +func _get_preset_count() -> int: + return 1 + +func _get_preset_name(preset: int) -> String: + return "Default" + +func _import( + source_file: String, + save_path: String, + options: Dictionary, + platform_variants: Array, + gen_files: Array +) -> int: + var point_cloud_data = PointCloudData.load_ply_file(source_file) + + var save_result = ResourceSaver.save(point_cloud_data, save_path + ".tres") + if save_result != OK: + push_error("Failed to save PointCloudData resource") + return ERR_CANT_CREATE + + return OK + diff --git a/main.gd b/main.gd index a7b52b5..3bd6134 100644 --- a/main.gd +++ b/main.gd @@ -2,7 +2,8 @@ extends Node3D @onready var camera = get_node("Camera") @onready var screen_texture = get_node("TextureRect") -@export var splat_filename: String = "point_cloud3.ply" +#@export var splat_filename: String = "point_cloud3.ply" +@export var splatResource: PointCloudData #= preload("res://point_cloud.ply") var rd = RenderingServer.create_local_rendering_device() var pipeline: RID @@ -81,110 +82,18 @@ func _set_screen_texture_data(data: PackedByteArray): screen_texture.texture.update(image) + # terrible loading func _load_ply_file(): - var file = FileAccess.open(splat_filename, FileAccess.READ) - - if not file: - print("Failed to open file: " + splat_filename) - return - - num_vertex = 0 - - # Read header - var line = file.get_line() - while not file.eof_reached(): - if line.begins_with("element vertex"): - num_vertex = int(line.split(" ")[2]) - if line.begins_with("end_header"): - break - line = file.get_line() - - var coeffs = [] - - for i in range(num_vertex): - var vertex = { - "x": file.get_float(), - "y": file.get_float(), - "z": file.get_float(), - "nx": file.get_float(), - "ny": file.get_float(), - "nz": file.get_float(), - "f_dc_0": file.get_float(), - "f_dc_1": file.get_float(), - "f_dc_2": file.get_float(), - "f_rest_0": file.get_float(), - "f_rest_1": file.get_float(), - "f_rest_2": file.get_float(), - "f_rest_3": file.get_float(), - "f_rest_4": file.get_float(), - "f_rest_5": file.get_float(), - "f_rest_6": file.get_float(), - "f_rest_7": file.get_float(), - "f_rest_8": file.get_float(), - "f_rest_9": file.get_float(), - "f_rest_10": file.get_float(), - "f_rest_11": file.get_float(), - "f_rest_12": file.get_float(), - "f_rest_13": file.get_float(), - "f_rest_14": file.get_float(), - "f_rest_15": file.get_float(), - "f_rest_16": file.get_float(), - "f_rest_17": file.get_float(), - "f_rest_18": file.get_float(), - "f_rest_19": file.get_float(), - "f_rest_20": file.get_float(), - "f_rest_21": file.get_float(), - "f_rest_22": file.get_float(), - "f_rest_23": file.get_float(), - "f_rest_24": file.get_float(), - "f_rest_25": file.get_float(), - "f_rest_26": file.get_float(), - "f_rest_27": file.get_float(), - "f_rest_28": file.get_float(), - "f_rest_29": file.get_float(), - "f_rest_30": file.get_float(), - "f_rest_31": file.get_float(), - "f_rest_32": file.get_float(), - "f_rest_33": file.get_float(), - "f_rest_34": file.get_float(), - "f_rest_35": file.get_float(), - "f_rest_36": file.get_float(), - "f_rest_37": file.get_float(), - "f_rest_38": file.get_float(), - "f_rest_39": file.get_float(), - "f_rest_40": file.get_float(), - "f_rest_41": file.get_float(), - "f_rest_42": file.get_float(), - "f_rest_43": file.get_float(), - "f_rest_44": file.get_float(), - "opacity": file.get_float(), - "scale_0": file.get_float(), - "scale_1": file.get_float(), - "scale_2": file.get_float(), - "rot_0": file.get_float(), - "rot_1": file.get_float(), - "rot_2": file.get_float(), - "rot_3": file.get_float() - } - - positions.append_array([vertex["x"], vertex["y"], vertex["z"], 0]) - opacities.append(vertex["opacity"]) - scales.append_array([vertex["scale_0"], vertex["scale_1"], vertex["scale_2"], 0]) - rotations.append_array([vertex["rot_0"], vertex["rot_1"], vertex["rot_2"], vertex["rot_3"]]) - depth_index.append(i) - depths.append(0) - - var coeff = [vertex["f_dc_0"], vertex["f_dc_1"], vertex["f_dc_2"]] - for j in range(num_coeffs_per_color): - coeff.append_array([ - vertex["f_rest_%d" % (0 * num_coeffs_per_color + j)], - vertex["f_rest_%d" % (1 * num_coeffs_per_color + j)], - vertex["f_rest_%d" % (2 * num_coeffs_per_color + j)] - ]) - sh_coeffs.append_array(coeff) - - file.close() + + depths = splatResource.depths + depth_index = splatResource.depth_index + positions = splatResource.positions + opacities = splatResource.opacities + scales = splatResource.scales + rotations = splatResource.rotations + sh_coeffs = splatResource.sh_coeffs + num_vertex = splatResource.num_vertex func _initialise_framebuffer_format(): @@ -491,7 +400,7 @@ func render(): _set_screen_texture_data(byte_data) -func _process(delta): +func _process(_delta): update() render() @@ -514,4 +423,3 @@ func _sort_splats_by_depth(): if angle > 0.6: bitonic_sort() last_direction = direction - diff --git a/main.tscn b/main.tscn index 9c1e73f..7758dba 100644 --- a/main.tscn +++ b/main.tscn @@ -1,11 +1,15 @@ -[gd_scene load_steps=3 format=3 uid="uid://c27tc42js165g"] +[gd_scene load_steps=5 format=3 uid="uid://c27tc42js165g"] [ext_resource type="Script" path="res://main.gd" id="1_j5eux"] +[ext_resource type="Resource" uid="uid://brxq4dkwnfyke" path="res://point_cloud.ply" id="2_7olva"] [ext_resource type="Script" path="res://Camera.gd" id="2_ppc5i"] +[sub_resource type="PrismMesh" id="PrismMesh_r3wk8"] + [node name="main" type="Node3D"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4.56234) script = ExtResource("1_j5eux") +splatResource = ExtResource("2_7olva") [node name="Camera" type="Camera3D" parent="."] current = true @@ -15,3 +19,7 @@ script = ExtResource("2_ppc5i") [node name="TextureRect" type="TextureRect" parent="."] offset_right = 40.0 offset_bottom = 40.0 + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4.60119) +mesh = SubResource("PrismMesh_r3wk8") diff --git a/project.godot b/project.godot index 6e6f1ab..761ccd5 100644 --- a/project.godot +++ b/project.godot @@ -15,6 +15,10 @@ run/main_scene="res://main.tscn" config/features=PackedStringArray("4.2", "Forward Plus") config/icon="res://icon.svg" +[editor_plugins] + +enabled=PackedStringArray("res://addons/point_cloud_importer/plugin.cfg") + [input] move_left={