world can be edited
This commit is contained in:
parent
bc58e13a61
commit
f4438c7ad0
@ -18,7 +18,6 @@ var delta_speed = 0
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
@ -50,22 +49,22 @@ func _input(event):
|
||||
camera.rotate_object_local(Vector3(-1, 0, 0), rot_y) # then rotate in X
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(_delta):
|
||||
delta_speed = PLAYER_SPEED * _delta * 500
|
||||
delta_speed = PLAYER_SPEED * _delta * 500000
|
||||
if NOCLIP:
|
||||
process_noclip()
|
||||
else:
|
||||
process_physics_movements()
|
||||
|
||||
#for hit_pos in ray_hit_positions:
|
||||
#DebugDraw3D.draw_sphere(hit_pos)
|
||||
for hit_pos in ray_hit_positions:
|
||||
DebugDraw3D.draw_sphere(hit_pos)
|
||||
|
||||
|
||||
|
||||
func process_physics_movements():
|
||||
if Input.is_action_pressed("MoveCamUp"):
|
||||
move_y = 1
|
||||
move_y = 5
|
||||
if Input.is_action_pressed("MoveCamDown"):
|
||||
pass
|
||||
move_y = -1
|
||||
if Input.is_action_pressed("MoveCamLeft"):
|
||||
move_x = -1
|
||||
if Input.is_action_pressed("MoveCamRight"):
|
||||
@ -102,10 +101,12 @@ func raycast_from_center():
|
||||
var raycast_result = space.intersect_ray(ray_query)
|
||||
|
||||
if len(raycast_result) > 0:
|
||||
var hit_pos = raycast_result.position - (raycast_result.normal * 0.5)
|
||||
hit_pos = Vector3i(round(hit_pos.x), round(hit_pos.y), round(hit_pos.z))
|
||||
var hit_pos: Vector3 = raycast_result.position - (raycast_result.normal * 0.5)
|
||||
hit_pos = Vector3(hit_pos.x, hit_pos.y, hit_pos.z)
|
||||
ray_hit_positions.append(hit_pos)
|
||||
world.SetBlockAtPosition(hit_pos, Block.BlockType.Air)
|
||||
print("ray hit at pos:", hit_pos)
|
||||
signals_service.add_matter.emit(hit_pos, 0.2)
|
||||
#world.SetBlockAtPosition(hit_pos, Block.BlockType.Air)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ const CENTER := Vector3.ZERO
|
||||
|
||||
var generate_mesh_shader = preload("res://SurfaceNetsWorld/generate_mesh.tres")
|
||||
|
||||
@export var regenerate_mesh = false
|
||||
var regenerate_mesh = true
|
||||
|
||||
|
||||
@export var chunk_size = 16
|
||||
@ -12,7 +12,7 @@ var generate_mesh_shader = preload("res://SurfaceNetsWorld/generate_mesh.tres")
|
||||
@export var show_surface_points = false
|
||||
@export var show_surface = true
|
||||
|
||||
var mesh
|
||||
var mesh: ArrayMesh
|
||||
|
||||
var color = Color.RED
|
||||
|
||||
@ -21,25 +21,33 @@ var material = ShaderMaterial.new()
|
||||
|
||||
var gpu_sdf
|
||||
|
||||
var staticBody: StaticBody3D = StaticBody3D.new()
|
||||
var collisionShape3D: CollisionShape3D = CollisionShape3D.new()
|
||||
|
||||
|
||||
func generate_chunk(pgpu_sdf) -> void:
|
||||
signals_service.regenerate_mesh_sig.connect(_on_regenerate_mesh_sig)
|
||||
signals_service.add_matter.connect(_on_player_add_matter)
|
||||
gpu_sdf = pgpu_sdf
|
||||
material.shader = generate_mesh_shader
|
||||
meshinstance.material_override = material
|
||||
add_child(meshinstance)
|
||||
meshinstance.mesh = gpu_sdf.compute_mesh(chunk_size, threshold, self.position)
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventKey and event.is_action_released("RegenerateMesh"):
|
||||
if regenerate_mesh:
|
||||
regenerate_mesh = false
|
||||
else:
|
||||
regenerate_mesh = true
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if show_surface && regenerate_mesh:
|
||||
if regenerate_mesh:
|
||||
regenerate_mesh = false
|
||||
clear()
|
||||
meshinstance.mesh = gpu_sdf.compute_mesh(chunk_size, threshold, self.position)
|
||||
var array_mesh = gpu_sdf.compute_mesh(chunk_size, threshold, self.position)
|
||||
var trimesh_collision = array_mesh.create_trimesh_shape()
|
||||
collisionShape3D.set_shape(trimesh_collision)
|
||||
staticBody = StaticBody3D.new()
|
||||
staticBody.add_child(collisionShape3D)
|
||||
add_child(staticBody)
|
||||
meshinstance.mesh = array_mesh
|
||||
if show_surface_points:
|
||||
var idx = 0
|
||||
var text_id = 0
|
||||
@ -56,8 +64,50 @@ func _process(_delta: float) -> void:
|
||||
|
||||
|
||||
func clear():
|
||||
if staticBody.get_children().has(collisionShape3D):
|
||||
staticBody.remove_child(collisionShape3D)
|
||||
mesh = ArrayMesh.new()
|
||||
|
||||
|
||||
func get_index_from_coords(coords: Vector3i):
|
||||
return coords.x + coords.y * chunk_size + coords.z * chunk_size * chunk_size
|
||||
|
||||
var chunks_to_regenerate = [
|
||||
Vector3i(0,0,0),
|
||||
Vector3i(0,1,0),
|
||||
Vector3i(0,0,1),
|
||||
Vector3i(0,1,1),
|
||||
Vector3i(0,-1,0),
|
||||
Vector3i(0,0,-1),
|
||||
Vector3i(0,-1,-1),
|
||||
Vector3i(0,-1,1),
|
||||
Vector3i(0,1,-1),
|
||||
|
||||
Vector3i(1,0,0),
|
||||
Vector3i(1,0,1),
|
||||
Vector3i(-1,0,0),
|
||||
Vector3i(-1,0,-1),
|
||||
Vector3i(-1,0,1),
|
||||
Vector3i(1,0,-1),
|
||||
|
||||
Vector3i(1,1,0),
|
||||
Vector3i(-1,-1,0),
|
||||
Vector3i(-1,1,0),
|
||||
Vector3i(1,-1,0),
|
||||
Vector3i(1,1,1),
|
||||
Vector3i(-1,-1,-1),
|
||||
]
|
||||
|
||||
func _on_regenerate_mesh_sig(pposition: Vector3i):
|
||||
if Vector3i(self.global_position) == pposition:
|
||||
regenerate_mesh = true
|
||||
|
||||
func _on_player_add_matter(pposition: Vector3, size: float) -> void:
|
||||
var intpposition = Vector3i(pposition.x - int(pposition.x) % chunk_size, pposition.y - int(pposition.y) % chunk_size, pposition.z - int(pposition.z) % chunk_size)
|
||||
var intposition = Vector3i(self.global_position)
|
||||
if intpposition.x == intposition.x && intpposition.y == intposition.y && intpposition.z == intposition.z:
|
||||
for chunk_pos_to_regenerate in chunks_to_regenerate:
|
||||
chunk_pos_to_regenerate = Vector3i(intpposition.x + chunk_pos_to_regenerate.x * chunk_size, intpposition.y + chunk_pos_to_regenerate.y * chunk_size, intpposition.z + chunk_pos_to_regenerate.z * chunk_size)
|
||||
signals_service.regenerate_mesh_sig.emit(chunk_pos_to_regenerate)
|
||||
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ var shader_pass2: RID
|
||||
var start_time := Time.get_ticks_msec() / 1000.0
|
||||
var color = Color.CORAL
|
||||
@export var iout_surface_points = []
|
||||
var player_edits = PackedFloat32Array()
|
||||
|
||||
var pipeline1
|
||||
var pipeline2
|
||||
@ -20,9 +21,11 @@ var idx_buffer
|
||||
var counter_buffer
|
||||
var chunk_position_buffer
|
||||
var params_buffer
|
||||
var player_edits_buffer
|
||||
|
||||
|
||||
func create_device(world_size: int):
|
||||
|
||||
signals_service.add_matter.connect(_on_player_add_matter)
|
||||
rd = RenderingServer.create_local_rendering_device()
|
||||
|
||||
# 1. Load Shaders
|
||||
@ -36,7 +39,7 @@ func create_device(world_size: int):
|
||||
pipeline2 = rd.compute_pipeline_create(shader_pass2)
|
||||
|
||||
# 3. Pre-allocate Buffers (assuming world_size is constant)
|
||||
# add 1 to look at adjacent voxels for chunk boundaries
|
||||
# add 2 to look at adjacent voxels for chunk boundaries
|
||||
var total = (world_size + 2) ** 3
|
||||
|
||||
# We create them once with empty/zero data of the correct size
|
||||
@ -48,6 +51,7 @@ func create_device(world_size: int):
|
||||
counter_buffer = rd.storage_buffer_create(4)
|
||||
chunk_position_buffer = rd.storage_buffer_create(16) # vec4
|
||||
params_buffer = rd.uniform_buffer_create(16) # world_size, threshold, time, etc
|
||||
player_edits_buffer = rd.storage_buffer_create(256)
|
||||
|
||||
func compute_mesh(world_size: int, threshold: float, chunk_pos: Vector3) -> ArrayMesh:
|
||||
world_size += 2
|
||||
@ -70,6 +74,11 @@ func compute_mesh(world_size: int, threshold: float, chunk_pos: Vector3) -> Arra
|
||||
var chunk_position_bytes := chunk_position_peer.to_byte_array()
|
||||
rd.buffer_update(chunk_position_buffer, 0, chunk_position_bytes.size(), chunk_position_bytes)
|
||||
|
||||
var player_edits_bytes = player_edits.to_byte_array()
|
||||
if player_edits_bytes.size() > 0:
|
||||
player_edits_buffer = rd.storage_buffer_create(player_edits_bytes.size())
|
||||
rd.buffer_update(player_edits_buffer, 0, player_edits_bytes.size(), player_edits_bytes)
|
||||
|
||||
var u_time := Time.get_ticks_msec() / 1000.0 - start_time
|
||||
var peer := StreamPeerBuffer.new()
|
||||
peer.put_32(world_size)
|
||||
@ -116,20 +125,23 @@ func compute_mesh(world_size: int, threshold: float, chunk_pos: Vector3) -> Arra
|
||||
chunk_position_uniform.binding = 7
|
||||
chunk_position_uniform.add_id(chunk_position_buffer)
|
||||
|
||||
|
||||
var player_edits_uniform := RDUniform.new()
|
||||
player_edits_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
|
||||
player_edits_uniform.binding = 8
|
||||
player_edits_uniform.add_id(player_edits_buffer)
|
||||
|
||||
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_set1 := rd.uniform_set_create([uniform_buf, uniform_params, surface_uniform_buf, normal_uniform, uv_uniform, idx_uniform, counter_uniform, chunk_position_uniform], shader_pass1, 0) # the last parameter (the 0) needs to match the "set" in our shader file
|
||||
var uniform_set1 := rd.uniform_set_create([uniform_buf, uniform_params, surface_uniform_buf, normal_uniform, uv_uniform, idx_uniform, counter_uniform, chunk_position_uniform, player_edits_uniform], shader_pass1, 0) # the last parameter (the 0) needs to match the "set" in our shader file
|
||||
var uniform_set2 := rd.uniform_set_create([uniform_buf, uniform_params, surface_uniform_buf, normal_uniform, uv_uniform, idx_uniform, counter_uniform], shader_pass2, 0)
|
||||
|
||||
var dispatch_count = int(ceil(world_size / 4.0))
|
||||
|
||||
# 1. Dispatch PASS 1 (Calculate Points)
|
||||
var pipeline1 := rd.compute_pipeline_create(shader_pass1) # Points only
|
||||
pipeline1 = rd.compute_pipeline_create(shader_pass1) # Points only
|
||||
var compute_list = rd.compute_list_begin()
|
||||
rd.compute_list_bind_compute_pipeline(compute_list, pipeline1)
|
||||
rd.compute_list_bind_uniform_set(compute_list, uniform_set1, 0)
|
||||
@ -137,7 +149,7 @@ func compute_mesh(world_size: int, threshold: float, chunk_pos: Vector3) -> Arra
|
||||
rd.compute_list_end()
|
||||
|
||||
# 2. Dispatch PASS 2 (Generate Indices)
|
||||
var pipeline2 := rd.compute_pipeline_create(shader_pass2) # Indices only
|
||||
pipeline2 = rd.compute_pipeline_create(shader_pass2) # Indices only
|
||||
compute_list = rd.compute_list_begin()
|
||||
rd.compute_list_bind_compute_pipeline(compute_list, pipeline2)
|
||||
rd.compute_list_bind_uniform_set(compute_list, uniform_set2, 0)
|
||||
@ -159,9 +171,6 @@ func compute_mesh(world_size: int, threshold: float, chunk_pos: Vector3) -> Arra
|
||||
var arrays = []
|
||||
arrays.resize(Mesh.ARRAY_MAX)
|
||||
|
||||
# We need to reshape the flat float array into Vector3s
|
||||
var verts := PackedVector3Array()
|
||||
var normals := PackedVector3Array()
|
||||
# Instead of blindly appending every voxel, we check if the voxel was "active"
|
||||
# Or, even better, map the original voxel indices to new packed indices
|
||||
var active_map = {}
|
||||
@ -234,6 +243,12 @@ func build_surface_dict(world_size: int, flat_buffer: PackedFloat32Array) -> Dic
|
||||
|
||||
return dict
|
||||
|
||||
func _on_player_add_matter(pposition: Vector3, size: float) -> void:
|
||||
player_edits.append(pposition.x)
|
||||
player_edits.append(pposition.y)
|
||||
player_edits.append(pposition.z)
|
||||
player_edits.append(size)
|
||||
|
||||
func _exit_tree():
|
||||
# If the rendering device wasn't initialized, we have nothing to free
|
||||
if not rd:
|
||||
|
||||
@ -39,6 +39,11 @@ layout(set = 0, binding = 7, std430) buffer ChunkPos {
|
||||
float position_array[];
|
||||
} chunk;
|
||||
|
||||
layout(set = 0, binding = 8, std430) buffer PlayerEdits {
|
||||
float position_size_array[];
|
||||
} edits;
|
||||
|
||||
|
||||
uint index3(uint x, uint y, uint z) {
|
||||
return x + y * params.world_size + z * params.world_size * params.world_size;
|
||||
}
|
||||
@ -79,6 +84,10 @@ vec4 taylorInvSqrt(vec4 r)
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
float sdsphere(vec3 p, float radius) {
|
||||
return length(p) - radius;
|
||||
}
|
||||
|
||||
float snoise(vec3 v)
|
||||
{
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
|
||||
@ -185,13 +194,21 @@ const ivec3 CORNERS[8] = ivec3[](
|
||||
);
|
||||
|
||||
float get_noise_at(vec3 p) {
|
||||
|
||||
float chunk_x = chunk.position_array[0] * -.5;
|
||||
float chunk_y = chunk.position_array[1] * -.5;
|
||||
float chunk_z = chunk.position_array[2] * -.5;
|
||||
p = p - vec3(chunk_x, chunk_y, chunk_z);
|
||||
p = p / 20.0;
|
||||
return snoise(p);
|
||||
|
||||
float return_value = 10000.0;
|
||||
|
||||
for (int i = 0; i < edits.position_size_array.length(); i += 4){
|
||||
return_value = min(return_value, sdsphere(p + vec3(edits.position_size_array[i] * -0.025, edits.position_size_array[i + 1] * -0.025, edits.position_size_array[i + 2] * -0.025), edits.position_size_array[i + 3]));
|
||||
}
|
||||
|
||||
return_value = min(return_value, snoise(p));
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Calculate normal using central difference
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
constant = Color(0.30202293, 0.6060653, 0.9109474, 1)
|
||||
|
||||
[resource]
|
||||
modes/cull = 2
|
||||
nodes/vertex/0/position = Vector2(360, 220)
|
||||
nodes/fragment/0/position = Vector2(660, 140)
|
||||
nodes/fragment/2/node = SubResource("VisualShaderNodeColorConstant_sxi40")
|
||||
|
||||
@ -4,6 +4,5 @@
|
||||
|
||||
[node name="SmoothWorld" type="Node3D" unique_id=113243680]
|
||||
script = ExtResource("1_4h467")
|
||||
chunk_size = 64
|
||||
world_size = 4
|
||||
threshold = 0.045
|
||||
world_size = 8
|
||||
threshold = 0.46
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://da568t2u1olhb"]
|
||||
[gd_scene format=3 uid="uid://da568t2u1olhb"]
|
||||
|
||||
[ext_resource type="Material" uid="uid://d2eg0eaiyrt6p" path="res://grass/grass_material.tres" id="1_eat54"]
|
||||
[ext_resource type="Script" uid="uid://civdn1k6g4dhy" path="res://chunk.gd" id="1_kdh3y"]
|
||||
|
||||
[node name="Chunk" type="MeshInstance3D"]
|
||||
[node name="Chunk" type="MeshInstance3D" unique_id=1056588591]
|
||||
material_override = ExtResource("1_eat54")
|
||||
script = ExtResource("1_kdh3y")
|
||||
backface_culling = true
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="."]
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=1003201572]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=232522921]
|
||||
|
||||
11
player.tscn
11
player.tscn
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://chbs3naovk63w"]
|
||||
[gd_scene format=3 uid="uid://chbs3naovk63w"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c1jlypyykqvfl" path="res://NoclipCamera.gd" id="1_4flbx"]
|
||||
|
||||
@ -8,17 +8,18 @@
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_tlwt5"]
|
||||
|
||||
[node name="Player" type="RigidBody3D"]
|
||||
[node name="Player" type="RigidBody3D" unique_id=50574317]
|
||||
physics_material_override = SubResource("PhysicsMaterial_fj7yv")
|
||||
gravity_scale = 0.0
|
||||
lock_rotation = true
|
||||
linear_damp = 1.0
|
||||
script = ExtResource("1_4flbx")
|
||||
|
||||
[node name="PlayerCamera" type="Camera3D" parent="."]
|
||||
[node name="PlayerCamera" type="Camera3D" parent="." unique_id=703597908]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1223998, 0)
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1204761983]
|
||||
mesh = SubResource("SphereMesh_fj7yv")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=703714189]
|
||||
shape = SubResource("SphereShape3D_tlwt5")
|
||||
|
||||
@ -19,6 +19,10 @@ run/main_scene="res://world.tscn"
|
||||
config/features=PackedStringArray("4.6")
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
signals_service="*uid://c7m0o52cbtdb4"
|
||||
|
||||
[debug]
|
||||
|
||||
settings/stdout/print_fps=true
|
||||
|
||||
13
signals_service.gd
Normal file
13
signals_service.gd
Normal file
@ -0,0 +1,13 @@
|
||||
extends Node
|
||||
|
||||
signal add_matter(position: Vector3, size: float)
|
||||
signal regenerate_mesh_sig(position: Vector3i)
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
pass
|
||||
1
signals_service.gd.uid
Normal file
1
signals_service.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c7m0o52cbtdb4
|
||||
@ -29,7 +29,7 @@ shadow_enabled = true
|
||||
|
||||
[node name="Player" parent="." unique_id=1950519856 instance=ExtResource("3_036b0")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.182447, 0.6673207, 0.0726881)
|
||||
gravity_scale = 2.0
|
||||
PLAYER_SPEED = 0.035
|
||||
NOCLIP = true
|
||||
|
||||
[connection signal="change_world" from="." to="." method="_on_change_world"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user