surface points on gpu
This commit is contained in:
parent
0a148d9db1
commit
42ccbebb52
@ -28,6 +28,21 @@ func compute(world_size: int, threshold: float):
|
|||||||
uniform_buf.binding = 0 # this needs to match the "binding" in our shader file
|
uniform_buf.binding = 0 # this needs to match the "binding" in our shader file
|
||||||
uniform_buf.add_id(buffer)
|
uniform_buf.add_id(buffer)
|
||||||
|
|
||||||
|
# Prepare our data. We use floats in the shader, so we need 32 bit.
|
||||||
|
var surface_total = world_size * world_size * world_size * 3
|
||||||
|
var surface_input := PackedFloat32Array()
|
||||||
|
surface_input.resize(surface_total)
|
||||||
|
var surface_input_bytes := surface_input.to_byte_array()
|
||||||
|
|
||||||
|
# Create a storage buffer that can hold our float values.
|
||||||
|
var surface_buffer := rd.storage_buffer_create(surface_input_bytes.size(), surface_input_bytes)
|
||||||
|
|
||||||
|
# Create a uniform to assign the buffer to the rendering device
|
||||||
|
var surface_uniform_buf := RDUniform.new()
|
||||||
|
surface_uniform_buf.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
|
||||||
|
surface_uniform_buf.binding = 2 # this needs to match the "binding" in our shader file
|
||||||
|
surface_uniform_buf.add_id(surface_buffer)
|
||||||
|
|
||||||
var peer := StreamPeerBuffer.new()
|
var peer := StreamPeerBuffer.new()
|
||||||
peer.put_32(world_size)
|
peer.put_32(world_size)
|
||||||
peer.put_float(threshold)
|
peer.put_float(threshold)
|
||||||
@ -42,7 +57,7 @@ func compute(world_size: int, threshold: float):
|
|||||||
uniform_params.binding = 1
|
uniform_params.binding = 1
|
||||||
uniform_params.add_id(params_buffer)
|
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
|
var uniform_set := rd.uniform_set_create([uniform_params, uniform_buf, surface_uniform_buf], shader, 0) # the last parameter (the 0) needs to match the "set" in our shader file
|
||||||
|
|
||||||
# Create a compute pipeline
|
# Create a compute pipeline
|
||||||
var pipeline := rd.compute_pipeline_create(shader)
|
var pipeline := rd.compute_pipeline_create(shader)
|
||||||
@ -59,12 +74,31 @@ func compute(world_size: int, threshold: float):
|
|||||||
rd.submit()
|
rd.submit()
|
||||||
rd.sync()
|
rd.sync()
|
||||||
# Read back the data from the buffer
|
# Read back the data from the buffer
|
||||||
var output_bytes := rd.buffer_get_data(buffer)
|
var output_bytes := rd.buffer_get_data(surface_buffer)
|
||||||
var output := output_bytes.to_float32_array()
|
var output := output_bytes.to_float32_array()
|
||||||
|
|
||||||
rd.free_rid(buffer)
|
rd.free_rid(buffer)
|
||||||
|
|
||||||
rd.free_rid(params_buffer)
|
rd.free_rid(params_buffer)
|
||||||
return output
|
rd.free_rid(surface_buffer)
|
||||||
|
return build_surface_dict(world_size, output)
|
||||||
|
|
||||||
|
func build_surface_dict(world_size: int, flat_buffer: PackedFloat32Array) -> Dictionary:
|
||||||
|
var dict := {}
|
||||||
|
var total = world_size * world_size * world_size
|
||||||
|
|
||||||
|
for idx in total:
|
||||||
|
var base = idx * 3
|
||||||
|
var x = flat_buffer[base]
|
||||||
|
var y = flat_buffer[base + 1]
|
||||||
|
var z = flat_buffer[base + 2]
|
||||||
|
|
||||||
|
var voxel_x = idx % world_size
|
||||||
|
var voxel_y = (idx / world_size) % world_size
|
||||||
|
var voxel_z = idx / (world_size * world_size)
|
||||||
|
|
||||||
|
var voxel_id = Vector3i(voxel_x, voxel_y, voxel_z)
|
||||||
|
var surface_pos = Vector3(x, y, z)
|
||||||
|
|
||||||
|
dict[voxel_id] = surface_pos
|
||||||
|
|
||||||
|
return dict
|
||||||
|
|||||||
@ -15,10 +15,21 @@ layout(set = 0, binding = 1) uniform Params {
|
|||||||
float threshold;
|
float threshold;
|
||||||
} params;
|
} params;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 2) buffer SurfaceBuffer {
|
||||||
|
float surface_points[];
|
||||||
|
} surface;
|
||||||
|
|
||||||
uint index3(uint x, uint y, uint z) {
|
uint index3(uint x, uint y, uint z) {
|
||||||
return x + y * params.world_size + z * params.world_size * params.world_size;
|
return x + y * params.world_size + z * params.world_size * params.world_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void store_surface_point(uint idx, vec3 pos) {
|
||||||
|
uint base = idx * 3u;
|
||||||
|
surface.surface_points[base + 0u] = pos.x;
|
||||||
|
surface.surface_points[base + 1u] = pos.y;
|
||||||
|
surface.surface_points[base + 2u] = pos.z;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
uvec3 id = gl_GlobalInvocationID;
|
uvec3 id = gl_GlobalInvocationID;
|
||||||
if (id.x >= uint(params.world_size) ||
|
if (id.x >= uint(params.world_size) ||
|
||||||
@ -26,7 +37,56 @@ void main() {
|
|||||||
id.z >= uint(params.world_size))
|
id.z >= uint(params.world_size))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const ivec3 SURFACE_AXIS[8] = ivec3[](
|
||||||
|
ivec3(1,0,0),
|
||||||
|
ivec3(0,1,0),
|
||||||
|
ivec3(0,0,1),
|
||||||
|
ivec3(1,0,1),
|
||||||
|
ivec3(0,1,1),
|
||||||
|
ivec3(1,1,0),
|
||||||
|
ivec3(1,1,1),
|
||||||
|
ivec3(0,0,0)
|
||||||
|
);
|
||||||
|
|
||||||
vec3 p = vec3(id) - params.world_size / 2 + 1;
|
vec3 p = vec3(id) - params.world_size / 2 + 1;
|
||||||
float d = length(p) - params.threshold;
|
float d = length(p) - params.threshold;
|
||||||
voxels.sample_points[index3(id.x, id.y, id.z)] = d;
|
uint idx = index3(id.x, id.y, id.z);
|
||||||
|
voxels.sample_points[idx] = d;
|
||||||
|
|
||||||
|
int previous_sign = 0;
|
||||||
|
vec3 previous_sample_point_coords = vec3(id.x, id.y, id.z);
|
||||||
|
float previous_sample_point_distance = 0.0;
|
||||||
|
vec3 intersection_points_sum = vec3(0.0, 0.0, 0.0);
|
||||||
|
uint intersection_points_count = 0u;
|
||||||
|
for (int sample_point_to_check_index = 0; sample_point_to_check_index < 8; sample_point_to_check_index++){
|
||||||
|
ivec3 sample_point_to_check = ivec3(id) + SURFACE_AXIS[sample_point_to_check_index];
|
||||||
|
|
||||||
|
// bounds check
|
||||||
|
if (sample_point_to_check.x < 0 || sample_point_to_check.y < 0 || sample_point_to_check.z < 0) continue;
|
||||||
|
if (uint(sample_point_to_check.x) >= params.world_size || uint(sample_point_to_check.y) >= params.world_size || uint(sample_point_to_check.z) >= params.world_size) continue;
|
||||||
|
|
||||||
|
uint buffer_index = index3(uint(sample_point_to_check.x), uint(sample_point_to_check.y), uint(sample_point_to_check.z));
|
||||||
|
float sample_point_distance_from_sdf = voxels.sample_points[buffer_index];
|
||||||
|
|
||||||
|
int current_sign = (sample_point_distance_from_sdf >= 0.0 ? 1 : -1);
|
||||||
|
|
||||||
|
if (previous_sign != 0 && current_sign != previous_sign) {
|
||||||
|
float t = previous_sample_point_distance / (previous_sample_point_distance - sample_point_distance_from_sdf);
|
||||||
|
vec3 intersect = mix(vec3(previous_sample_point_coords), vec3(sample_point_to_check), t);
|
||||||
|
intersection_points_sum += intersect;
|
||||||
|
intersection_points_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_sign = current_sign;
|
||||||
|
previous_sample_point_distance = sample_point_distance_from_sdf;
|
||||||
|
previous_sample_point_coords = sample_point_to_check;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersection_points_count > 0u) {
|
||||||
|
vec3 avg = intersection_points_sum / float(intersection_points_count);
|
||||||
|
store_surface_point(idx, avg);
|
||||||
|
} else {
|
||||||
|
store_surface_point(idx, vec3(0.0)); // no surface
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ var gpu_sdf
|
|||||||
@export var clear_the_thing: bool = false
|
@export var clear_the_thing: bool = false
|
||||||
|
|
||||||
var sdf_buffer = []
|
var sdf_buffer = []
|
||||||
|
var surface_points_buffer = []
|
||||||
|
|
||||||
var color = Color.CORAL
|
var color = Color.CORAL
|
||||||
var surface_point_color = Color.CRIMSON
|
var surface_point_color = Color.CRIMSON
|
||||||
@ -33,9 +34,10 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
clear()
|
clear()
|
||||||
sdf_buffer = gpu_sdf.compute(world_size, RADIUS)
|
surface_points = gpu_sdf.compute(world_size, RADIUS)
|
||||||
if !sdf_buffer.is_empty():
|
if !surface_points.is_empty():
|
||||||
create_surface_points()
|
#create_surface_points_gpu()
|
||||||
|
#create_surface_points()
|
||||||
if show_surface_points:
|
if show_surface_points:
|
||||||
draw_surface_points()
|
draw_surface_points()
|
||||||
if show_surface:
|
if show_surface:
|
||||||
@ -51,6 +53,9 @@ func clear():
|
|||||||
if child is MeshInstance3D:
|
if child is MeshInstance3D:
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
|
|
||||||
|
func get_index_from_coords(coords: Vector3i):
|
||||||
|
return coords.x + coords.y * world_size + coords.z * world_size * world_size
|
||||||
|
|
||||||
func draw_sample_points():
|
func draw_sample_points():
|
||||||
for x in range(world_size):
|
for x in range(world_size):
|
||||||
for y in range(world_size):
|
for y in range(world_size):
|
||||||
@ -60,12 +65,10 @@ func draw_sample_points():
|
|||||||
#DebugDraw3D.draw_text(Vector3i(x, y, z), str(Vector3i(x, y, z)))
|
#DebugDraw3D.draw_text(Vector3i(x, y, z), str(Vector3i(x, y, z)))
|
||||||
|
|
||||||
func draw_surface_points():
|
func draw_surface_points():
|
||||||
for x in range(world_size):
|
for surface_point in surface_points:
|
||||||
for y in range(world_size):
|
if surface_points[surface_point] != Vector3(0, 0, 0):
|
||||||
for z in range(world_size):
|
DebugDraw3D.draw_square(surface_points[surface_point] , 0.3, surface_point_color)
|
||||||
if surface_points.has(Vector3i(x, y, z)):
|
#DebugDraw3D.draw_text(surface_points[Vector3i(x, y, z)], str(surface_points[Vector3i(x, y, z)]))
|
||||||
DebugDraw3D.draw_square(surface_points[Vector3i(x, y, z)].position , 0.3, surface_point_color)
|
|
||||||
DebugDraw3D.draw_text(surface_points[Vector3i(x, y, z)].position, str(surface_points[Vector3i(x, y, z)].position))
|
|
||||||
|
|
||||||
func create_surface_points():
|
func create_surface_points():
|
||||||
for x in range(world_size):
|
for x in range(world_size):
|
||||||
|
|||||||
@ -5,3 +5,4 @@
|
|||||||
[node name="SmoothWorld" type="Node3D"]
|
[node name="SmoothWorld" type="Node3D"]
|
||||||
script = ExtResource("1_4h467")
|
script = ExtResource("1_4h467")
|
||||||
RADIUS = 6.789
|
RADIUS = 6.789
|
||||||
|
show_surface_points = true
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user