diff --git a/NoclipCamera.gd b/NoclipCamera.gd index 86ba0c5..01307b5 100644 --- a/NoclipCamera.gd +++ b/NoclipCamera.gd @@ -4,7 +4,7 @@ var rot_y = 0 @onready var world = preload("res://world.tscn") -@export var PLAYER_SPEED = 1 +@export var PLAYER_SPEED = 1.0 @export var PLAYER_REACH = 1000 @export var NOCLIP = false @export_range(0.00001, 0.01) var LOOK_SENSITIVITY = 0.002 diff --git a/compute_test.gd b/compute_test.gd new file mode 100644 index 0000000..0584aa0 --- /dev/null +++ b/compute_test.gd @@ -0,0 +1,70 @@ + +var rd: RenderingDevice +var shader_file: Resource +var shader_spirv: RDShaderSPIRV +var shader: RID + +func create_device(): + rd = RenderingServer.create_local_rendering_device() + shader_file = load("res://sdf_shader.glsl") + shader_spirv = shader_file.get_spirv() + shader = rd.shader_create_from_spirv(shader_spirv) + + +func compute(world_size: int, threshold: float): + + # Prepare our data. We use floats in the shader, so we need 32 bit. + var total = world_size * world_size * world_size + var input := PackedFloat32Array() + input.resize(total) + var input_bytes := input.to_byte_array() + + # Create a storage buffer that can hold our float values. + var buffer := rd.storage_buffer_create(input_bytes.size(), input_bytes) + + # Create a uniform to assign the buffer to the rendering device + var uniform_buf := RDUniform.new() + uniform_buf.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER + uniform_buf.binding = 0 # this needs to match the "binding" in our shader file + uniform_buf.add_id(buffer) + + var peer := StreamPeerBuffer.new() + peer.put_32(world_size) + peer.put_float(threshold) + peer.put_32(0) + peer.put_32(0) + var bytes := peer.data_array + + var params_buffer := rd.uniform_buffer_create(bytes.size(), bytes) + + var uniform_params := RDUniform.new() + uniform_params.uniform_type = RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER + uniform_params.binding = 1 + uniform_params.add_id(params_buffer) + + var uniform_set := rd.uniform_set_create([uniform_params, uniform_buf], shader, 0) # the last parameter (the 0) needs to match the "set" in our shader file + + # Create a compute pipeline + var pipeline := rd.compute_pipeline_create(shader) + var compute_list := rd.compute_list_begin() + rd.compute_list_bind_compute_pipeline(compute_list, pipeline) + rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0) + var dispatch_x = int(ceil(world_size / 8.0)) + var dispatch_y = int(ceil(world_size / 8.0)) + var dispatch_z = int(ceil(world_size / 1.0)) # local_size_z = 1 + rd.compute_list_dispatch(compute_list, dispatch_x, dispatch_y, dispatch_z) + rd.compute_list_end() + + # Submit to GPU and wait for sync + rd.submit() + rd.sync() + # Read back the data from the buffer + var output_bytes := rd.buffer_get_data(buffer) + var output := output_bytes.to_float32_array() + + rd.free_rid(buffer) + + rd.free_rid(params_buffer) + return output + + diff --git a/compute_test.gd.uid b/compute_test.gd.uid new file mode 100644 index 0000000..1c49572 --- /dev/null +++ b/compute_test.gd.uid @@ -0,0 +1 @@ +uid://du1xgjbvpa6dk diff --git a/sample_point.gd b/sample_point.gd index ba20341..c117683 100644 --- a/sample_point.gd +++ b/sample_point.gd @@ -1,3 +1,2 @@ @export var distance = 0 @export var position = Vector3.ZERO -@export var visible = false diff --git a/sdf_shader.glsl b/sdf_shader.glsl new file mode 100644 index 0000000..d41dbc7 --- /dev/null +++ b/sdf_shader.glsl @@ -0,0 +1,29 @@ + +#[compute] +#version 450 + +// Workgroup size +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +// Storage buffer +layout(set = 0, binding = 0, std430) buffer DataBuffer { + float sample_points[]; +} voxels; + +layout(set = 0, binding = 1) uniform Params { + int world_size; + float threshold; +} params; + +void main() { + uvec3 id = gl_GlobalInvocationID; + if (id.x >= uint(params.world_size) || + id.y >= uint(params.world_size) || + id.z >= uint(params.world_size)) + return; + + uint index = id.x + id.y * uint(params.world_size) + id.z * uint(params.world_size) * uint(params.world_size); + vec3 p = vec3(id); + float d = length(p) - params.threshold; + voxels.sample_points[index] = d; +} diff --git a/sdf_shader.glsl.import b/sdf_shader.glsl.import new file mode 100644 index 0000000..e33881b --- /dev/null +++ b/sdf_shader.glsl.import @@ -0,0 +1,14 @@ +[remap] + +importer="glsl" +type="RDShaderFile" +uid="uid://dv4s7mmqwnsqr" +path="res://.godot/imported/sdf_shader.glsl-8a6992e3be4c1416763f59c511add1b8.res" + +[deps] + +source_file="res://sdf_shader.glsl" +dest_files=["res://.godot/imported/sdf_shader.glsl-8a6992e3be4c1416763f59c511add1b8.res"] + +[params] + diff --git a/smooth_world.gd b/smooth_world.gd index 5c2a3ac..4206fe4 100644 --- a/smooth_world.gd +++ b/smooth_world.gd @@ -1,12 +1,15 @@ -@tool +#@tool extends Node3D const CENTER := Vector3.ZERO -@export_range(0.0, 6.9999) var RADIUS: float = 5.0 +@export var RADIUS: float = 5.0 var sample_points = {} var SamplePoint = preload("res://sample_point.gd") var surface_points = {} var SurfacePoint = preload("res://surface_point.gd") +var ComputeSdf = preload("res://compute_test.gd") +var gpu_sdf + @export var world_size = 16 @export var show_sample_points = false @@ -16,6 +19,8 @@ var SurfacePoint = preload("res://surface_point.gd") @export var do_the_thing: bool = false @export var clear_the_thing: bool = false +var sdf_buffer = [] + var color = Color.CORAL var surface_point_color = Color.CRIMSON @@ -23,17 +28,21 @@ var mesh var surface_tool: SurfaceTool = SurfaceTool.new() func _ready() -> void: - initialize_sample_points() + gpu_sdf = ComputeSdf.new() + gpu_sdf.create_device() + #initialize_sample_points() func _process(_delta: float) -> void: clear() - create_surface_points() - if show_surface_points: - draw_surface_points() - if show_surface: - create_surface_mesh(world_size) - if show_sample_points: - draw_sample_points() + sdf_buffer = gpu_sdf.compute(world_size * 2, RADIUS) + if !sdf_buffer.is_empty(): + create_surface_points() + if show_surface_points: + draw_surface_points() + if show_surface: + create_surface_mesh(world_size) + if show_sample_points: + draw_sample_points() func clear(): @@ -47,28 +56,21 @@ func draw_sample_points(): for x in range(-world_size + 1, world_size): for y in range(-world_size + 1, world_size): for z in range(-world_size + 1, world_size): - DebugDraw3D.draw_square(sample_points[Vector3i(x, y, z)].position, 0.2, color) + if sample_points.has(Vector3i(x, y, z)): + DebugDraw3D.draw_square(Vector3i(x, y, z), 0.2, color) + #DebugDraw3D.draw_text(Vector3i(x, y, z), str(Vector3i(x, y, z))) func draw_surface_points(): for x in range(-world_size + 1, world_size): for y in range(-world_size + 1, world_size): for z in range(-world_size + 1, world_size): if surface_points.has(Vector3i(x, y, z)): - DebugDraw3D.draw_square(surface_points[Vector3i(x, y, z)].position, 0.3, surface_point_color) + DebugDraw3D.draw_square(Vector3i(x, y, z), 0.3, surface_point_color) -func get_sample_value(index: Vector3i) -> float: - return CENTER.distance_to(index) - RADIUS - func initialize_sample_points(): - for x in range(-world_size + 1, world_size): - for y in range(-world_size + 1, world_size): - for z in range(-world_size + 1, world_size): - var sample_point = SamplePoint.new() - sample_point.distance = get_sample_value(Vector3i(x, y, z)) - sample_point.position = Vector3(float(x), float(y), float(z)) - sample_point.visible = show_sample_points - sample_points[Vector3i(x, y, z)] = sample_point + sample_points = gpu_sdf.compute(world_size, RADIUS) + print("sample_points initialized", sample_points) func create_surface_points(): for x in range(-world_size + 1, world_size): @@ -84,19 +86,24 @@ func create_surface_point(voxel: Vector3i): var intersection_points_number = Vector3.ZERO for sample_point_to_check_index in range(SURFACE_AXIS.size()): var sample_point_to_check = voxel + SURFACE_AXIS[sample_point_to_check_index] - var sample_point_distance_from_sdf = get_sample_value(sample_point_to_check) - if previous_sign != 0 && sign(sample_point_distance_from_sdf) != previous_sign: - var intersection_point = (1-previous_sample_point_distance_from_sdf/(previous_sample_point_distance_from_sdf - sample_point_distance_from_sdf))*previous_sample_point+(previous_sample_point_distance_from_sdf/(previous_sample_point_distance_from_sdf-sample_point_distance_from_sdf)*sample_point_to_check) - intersection_points_sum += intersection_point - intersection_points_number += Vector3.ONE - previous_sign = sign(sample_point_distance_from_sdf) - previous_sample_point = sample_point_to_check - previous_sample_point_distance_from_sdf = sample_point_distance_from_sdf + var normal_x = voxel.x + world_size - 1 + var normal_y = voxel.y + world_size - 1 + var normal_z = voxel.z + world_size - 1 + var buffer_index = normal_x + normal_y * world_size + normal_z * world_size * world_size + if buffer_index < sdf_buffer.size(): + var sample_point_distance_from_sdf = sdf_buffer[buffer_index]#get_sample_value(sample_point_to_check) + sample_points[voxel] = sample_point_distance_from_sdf + if previous_sign != 0 && sign(sample_point_distance_from_sdf) != previous_sign: + var intersection_point = (1-previous_sample_point_distance_from_sdf/(previous_sample_point_distance_from_sdf - sample_point_distance_from_sdf))*previous_sample_point+(previous_sample_point_distance_from_sdf/(previous_sample_point_distance_from_sdf-sample_point_distance_from_sdf)*sample_point_to_check) + intersection_points_sum += intersection_point + intersection_points_number += Vector3.ONE + previous_sign = sign(sample_point_distance_from_sdf) + previous_sample_point = sample_point_to_check + previous_sample_point_distance_from_sdf = sample_point_distance_from_sdf if intersection_points_sum != Vector3.ZERO && intersection_points_number != Vector3.ZERO: var intersection_points_average = intersection_points_sum/intersection_points_number var surface_point = SurfacePoint.new() surface_point.position = intersection_points_average - surface_point.visible = show_surface_points surface_points[voxel] = surface_point func calculate_surface_point_position(voxel: Vector3i): @@ -109,7 +116,8 @@ func create_surface_mesh(size: int = 6): for x in range(-size, size): for y in range(-size, size): for z in range(-size, size): - create_surface_mesh_quad(Vector3i(x,y,z)); + if surface_points.has(Vector3i(x, y, z)): + create_surface_mesh_quad(Vector3i(x,y,z)); mesh = surface_tool.commit() var meshinstance = MeshInstance3D.new() meshinstance.mesh = mesh @@ -119,8 +127,8 @@ func create_surface_mesh_quad(index: Vector3i): for axis_index in range(AXIS.size()): var axis = AXIS[axis_index] - var sample_value1 = get_sample_value(index) - var sample_value2 = get_sample_value(index + axis) + var sample_value1 = sample_points[index] + var sample_value2 = sample_points[index + axis] if sample_value1 < 0 and sample_value2 >= 0: add_quad(index, axis_index) @@ -146,14 +154,6 @@ const SURFACE_AXIS := [ func add_quad(index: Vector3i, axis_index: int): var points = get_quad_points(index, axis_index) - - var normal = Vector3( - (get_sample_value(index + SURFACE_AXIS[0]) - get_sample_value(index + SURFACE_AXIS[7])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[1])) + (get_sample_value(index + SURFACE_AXIS[3]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[6]) - get_sample_value(index + SURFACE_AXIS[4])), - (get_sample_value(index + SURFACE_AXIS[1]) - get_sample_value(index + SURFACE_AXIS[7])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[0])) + (get_sample_value(index + SURFACE_AXIS[4]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[6]) - get_sample_value(index + SURFACE_AXIS[3])), - (get_sample_value(index + SURFACE_AXIS[7]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[0]) - get_sample_value(index + SURFACE_AXIS[3])) + (get_sample_value(index + SURFACE_AXIS[1]) - get_sample_value(index + SURFACE_AXIS[4])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[6])) - ) - - surface_tool.set_normal(normal) surface_tool.add_vertex(points[0]) surface_tool.add_vertex(points[1]) @@ -162,17 +162,10 @@ func add_quad(index: Vector3i, axis_index: int): surface_tool.add_vertex(points[0]) surface_tool.add_vertex(points[2]) surface_tool.add_vertex(points[3]) + surface_tool.generate_normals() func add_reversed_quad(index: Vector3i, axis_index: int): var points = get_quad_points(index, axis_index) - - var normal = Vector3( - (get_sample_value(index + SURFACE_AXIS[0]) - get_sample_value(index + SURFACE_AXIS[7])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[1])) + (get_sample_value(index + SURFACE_AXIS[3]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[6]) - get_sample_value(index + SURFACE_AXIS[4])), - (get_sample_value(index + SURFACE_AXIS[1]) - get_sample_value(index + SURFACE_AXIS[7])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[0])) + (get_sample_value(index + SURFACE_AXIS[4]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[6]) - get_sample_value(index + SURFACE_AXIS[3])), - (get_sample_value(index + SURFACE_AXIS[7]) - get_sample_value(index + SURFACE_AXIS[2])) + (get_sample_value(index + SURFACE_AXIS[0]) - get_sample_value(index + SURFACE_AXIS[3])) + (get_sample_value(index + SURFACE_AXIS[1]) - get_sample_value(index + SURFACE_AXIS[4])) + (get_sample_value(index + SURFACE_AXIS[5]) - get_sample_value(index + SURFACE_AXIS[6])) - ) - - surface_tool.set_normal(normal) surface_tool.add_vertex(points[0]) surface_tool.add_vertex(points[2]) @@ -181,6 +174,7 @@ func add_reversed_quad(index: Vector3i, axis_index: int): surface_tool.add_vertex(points[0]) surface_tool.add_vertex(points[3]) surface_tool.add_vertex(points[2]) + surface_tool.generate_normals() func get_quad_points(index: Vector3i, axis_index: int): return [ diff --git a/smooth_world.tscn b/smooth_world.tscn index 4c49bce..1925d04 100644 --- a/smooth_world.tscn +++ b/smooth_world.tscn @@ -4,8 +4,6 @@ [node name="SmoothWorld" type="Node3D"] script = ExtResource("1_4h467") -RADIUS = 3.971 -world_size = 8 +RADIUS = 2.059 show_sample_points = true show_surface_points = true -do_the_thing = true diff --git a/world.tscn b/world.tscn index 6cca861..04786f2 100644 --- a/world.tscn +++ b/world.tscn @@ -29,6 +29,7 @@ shadow_enabled = true [node name="Player" parent="." instance=ExtResource("3_036b0")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.182447, 0.6673207, 0.0726881) +PLAYER_SPEED = 0.305 NOCLIP = true [connection signal="change_world" from="." to="." method="_on_change_world"]