mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-04 15:00:09 +01:00
Fix block face checks and explicitly define normals in voxel demo (#1182)
This commit is contained in:
@@ -12,7 +12,7 @@ func _process(_delta: float) -> void:
|
|||||||
text += "\nEffective render distance: " + str(voxel_world.effective_render_distance)
|
text += "\nEffective render distance: " + str(voxel_world.effective_render_distance)
|
||||||
text += "\nLooking: " + _cardinal_string_from_radians(player.transform.basis.get_euler().y)
|
text += "\nLooking: " + _cardinal_string_from_radians(player.transform.basis.get_euler().y)
|
||||||
text += "\nMemory: " + "%3.0f" % (OS.get_static_memory_usage() / 1048576.0) + " MiB"
|
text += "\nMemory: " + "%3.0f" % (OS.get_static_memory_usage() / 1048576.0) + " MiB"
|
||||||
text += "\nFPS: " + str(Engine.get_frames_per_second())
|
text += "\nFPS: " + String.num_uint64(Engine.get_frames_per_second())
|
||||||
|
|
||||||
|
|
||||||
# Avoids the problem of showing more digits than needed or available.
|
# Avoids the problem of showing more digits than needed or available.
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ extends Control
|
|||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
render_distance_slider.value = Settings.render_distance
|
render_distance_slider.value = Settings.render_distance
|
||||||
render_distance_label.text = "Render distance: " + str(Settings.render_distance)
|
render_distance_label.text = "Render distance: " + String.num_int64(Settings.render_distance)
|
||||||
fog_checkbox.button_pressed = Settings.fog_enabled
|
fog_checkbox.button_pressed = Settings.fog_enabled
|
||||||
|
|
||||||
|
|
||||||
func _on_RenderDistanceSlider_value_changed(value: float) -> void:
|
func _on_RenderDistanceSlider_value_changed(value: float) -> void:
|
||||||
Settings.render_distance = int(value)
|
Settings.render_distance = int(value)
|
||||||
render_distance_label.text = "Render distance: " + str(value)
|
render_distance_label.text = "Render distance: " + String.num_int64(Settings.render_distance)
|
||||||
Settings.save_settings()
|
Settings.save_settings()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=6 format=3 uid="uid://1s4asqpay67m"]
|
[gd_scene load_steps=6 format=3 uid="uid://1s4asqpay67m"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://player/player.gd" id="1"]
|
[ext_resource type="Script" uid="uid://rm45k07vw817" path="res://player/player.gd" id="1"]
|
||||||
[ext_resource type="Texture2D" uid="uid://d3f34krqfgdjd" path="res://world/textures/texture_sheet.png" id="2"]
|
[ext_resource type="Texture2D" uid="uid://d3f34krqfgdjd" path="res://world/textures/texture_sheet.png" id="2"]
|
||||||
|
|
||||||
[sub_resource type="CylinderShape3D" id="1"]
|
[sub_resource type="CylinderShape3D" id="1"]
|
||||||
|
|||||||
@@ -147,7 +147,6 @@ pick_block={
|
|||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
common/physics_ticks_per_second=120
|
common/physics_ticks_per_second=120
|
||||||
3d/physics_engine="Bullet"
|
|
||||||
3d/default_gravity=20.0
|
3d/default_gravity=20.0
|
||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
var render_distance := 7
|
var render_distance: int = 7
|
||||||
var fog_enabled := true
|
var fog_enabled: bool = true
|
||||||
|
|
||||||
var fog_distance := 32.0 # Not saved, only used during runtime.
|
var fog_distance: float = 32.0 # Not saved, only used during runtime.
|
||||||
var world_type := 0 # Not saved, only used during runtime.
|
var world_type: int = 0 # Not saved, only used during runtime.
|
||||||
|
|
||||||
var _save_path := "user://settings.json"
|
var _save_path: String = "user://settings.json"
|
||||||
|
|
||||||
func _enter_tree() -> void:
|
func _enter_tree() -> void:
|
||||||
if FileAccess.file_exists(_save_path):
|
if FileAccess.file_exists(_save_path):
|
||||||
|
|||||||
@@ -9,14 +9,17 @@ const TEXTURE_SHEET_WIDTH = 8
|
|||||||
|
|
||||||
const CHUNK_LAST_INDEX = CHUNK_SIZE - 1
|
const CHUNK_LAST_INDEX = CHUNK_SIZE - 1
|
||||||
const TEXTURE_TILE_SIZE = 1.0 / TEXTURE_SHEET_WIDTH
|
const TEXTURE_TILE_SIZE = 1.0 / TEXTURE_SHEET_WIDTH
|
||||||
|
const DIRECTIONS: Array[Vector3i] = [Vector3i.LEFT, Vector3i.RIGHT, Vector3i.DOWN, Vector3i.UP, Vector3i.FORWARD, Vector3i.BACK]
|
||||||
|
|
||||||
var data := {}
|
var data := {}
|
||||||
var chunk_position := Vector3i()
|
var chunk_position := Vector3i()
|
||||||
|
var is_initial_mesh_generated: bool = false
|
||||||
|
|
||||||
var _thread: Thread
|
var _thread: Thread
|
||||||
|
|
||||||
@onready var voxel_world := get_parent()
|
@onready var voxel_world := get_parent()
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
transform.origin = Vector3(chunk_position * CHUNK_SIZE)
|
transform.origin = Vector3(chunk_position * CHUNK_SIZE)
|
||||||
name = str(chunk_position)
|
name = str(chunk_position)
|
||||||
@@ -27,7 +30,14 @@ func _ready() -> void:
|
|||||||
|
|
||||||
# We can only add colliders in the main thread due to physics limitations.
|
# We can only add colliders in the main thread due to physics limitations.
|
||||||
_generate_chunk_collider()
|
_generate_chunk_collider()
|
||||||
# However, we can use a thread for mesh generation.
|
|
||||||
|
|
||||||
|
func try_initial_generate_mesh(all_chunks: Dictionary[Vector3i, Chunk]) -> void:
|
||||||
|
# We can use a thread for mesh generation.
|
||||||
|
for dir in DIRECTIONS:
|
||||||
|
if not all_chunks.has(chunk_position + dir):
|
||||||
|
return
|
||||||
|
is_initial_mesh_generated = true
|
||||||
_thread = Thread.new()
|
_thread = Thread.new()
|
||||||
_thread.start(_generate_chunk_mesh)
|
_thread.start(_generate_chunk_mesh)
|
||||||
|
|
||||||
@@ -73,7 +83,6 @@ func _generate_chunk_mesh() -> void:
|
|||||||
_draw_block_mesh(surface_tool, block_position, block_id)
|
_draw_block_mesh(surface_tool, block_position, block_id)
|
||||||
|
|
||||||
# Create the chunk's mesh from the SurfaceTool data.
|
# Create the chunk's mesh from the SurfaceTool data.
|
||||||
surface_tool.generate_normals()
|
|
||||||
surface_tool.generate_tangents()
|
surface_tool.generate_tangents()
|
||||||
surface_tool.index()
|
surface_tool.index()
|
||||||
var array_mesh := surface_tool.commit()
|
var array_mesh := surface_tool.commit()
|
||||||
@@ -91,10 +100,10 @@ func _draw_block_mesh(surface_tool: SurfaceTool, block_sub_position: Vector3i, b
|
|||||||
|
|
||||||
# Bush blocks get drawn in their own special way.
|
# Bush blocks get drawn in their own special way.
|
||||||
if block_id == 27 or block_id == 28:
|
if block_id == 27 or block_id == 28:
|
||||||
_draw_block_face(surface_tool, [verts[2], verts[0], verts[7], verts[5]], uvs)
|
_draw_block_face(surface_tool, [verts[2], verts[0], verts[7], verts[5]], uvs, Vector3(-1, 0, 1).normalized())
|
||||||
_draw_block_face(surface_tool, [verts[7], verts[5], verts[2], verts[0]], uvs)
|
_draw_block_face(surface_tool, [verts[7], verts[5], verts[2], verts[0]], uvs, Vector3(1, 0, -1).normalized())
|
||||||
_draw_block_face(surface_tool, [verts[3], verts[1], verts[6], verts[4]], uvs)
|
_draw_block_face(surface_tool, [verts[3], verts[1], verts[6], verts[4]], uvs, Vector3(1, 0, 1).normalized())
|
||||||
_draw_block_face(surface_tool, [verts[6], verts[4], verts[3], verts[1]], uvs)
|
_draw_block_face(surface_tool, [verts[6], verts[4], verts[3], verts[1]], uvs, Vector3(-1, 0, -1).normalized())
|
||||||
return
|
return
|
||||||
|
|
||||||
# Allow some blocks to have different top/bottom textures.
|
# Allow some blocks to have different top/bottom textures.
|
||||||
@@ -112,62 +121,76 @@ func _draw_block_mesh(surface_tool: SurfaceTool, block_sub_position: Vector3i, b
|
|||||||
bottom_uvs = top_uvs
|
bottom_uvs = top_uvs
|
||||||
|
|
||||||
# Main rendering code for normal blocks.
|
# Main rendering code for normal blocks.
|
||||||
var other_block_position := block_sub_position + Vector3i.LEFT
|
#var other_block_position := block_sub_position
|
||||||
var other_block_id := 0
|
var other_block_id := 0
|
||||||
if other_block_position.x == -1:
|
if block_sub_position.x == 0:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(15, block_sub_position.y, block_sub_position.z)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.LEFT, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.LEFT
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[2], verts[0], verts[3], verts[1]], uvs)
|
_draw_block_face(surface_tool, [verts[2], verts[0], verts[3], verts[1]], uvs, Vector3.LEFT)
|
||||||
|
|
||||||
other_block_position = block_sub_position + Vector3i.RIGHT
|
|
||||||
other_block_id = 0
|
other_block_id = 0
|
||||||
if other_block_position.x == CHUNK_SIZE:
|
if block_sub_position.x == CHUNK_SIZE - 1:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(0, block_sub_position.y, block_sub_position.z)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.RIGHT, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.RIGHT
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[7], verts[5], verts[6], verts[4]], uvs)
|
_draw_block_face(surface_tool, [verts[7], verts[5], verts[6], verts[4]], uvs, Vector3.RIGHT)
|
||||||
|
|
||||||
other_block_position = block_sub_position + Vector3i.FORWARD
|
|
||||||
other_block_id = 0
|
other_block_id = 0
|
||||||
if other_block_position.z == -1:
|
if block_sub_position.z == 0:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(block_sub_position.x, block_sub_position.y, CHUNK_SIZE - 1)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.FORWARD, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.FORWARD
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[6], verts[4], verts[2], verts[0]], uvs)
|
_draw_block_face(surface_tool, [verts[6], verts[4], verts[2], verts[0]], uvs, Vector3.FORWARD)
|
||||||
|
|
||||||
other_block_position = block_sub_position + Vector3i.BACK
|
|
||||||
other_block_id = 0
|
other_block_id = 0
|
||||||
if other_block_position.z == CHUNK_SIZE:
|
if block_sub_position.z == CHUNK_SIZE - 1:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(block_sub_position.x, block_sub_position.y, 0)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.BACK, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.BACK
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[3], verts[1], verts[7], verts[5]], uvs)
|
_draw_block_face(surface_tool, [verts[3], verts[1], verts[7], verts[5]], uvs, Vector3.BACK)
|
||||||
|
|
||||||
other_block_position = block_sub_position + Vector3i.DOWN
|
|
||||||
other_block_id = 0
|
other_block_id = 0
|
||||||
if other_block_position.y == -1:
|
if block_sub_position.y == 0:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(block_sub_position.x, CHUNK_SIZE - 1, block_sub_position.z)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.DOWN, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.DOWN
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[4], verts[5], verts[0], verts[1]], bottom_uvs)
|
_draw_block_face(surface_tool, [verts[4], verts[5], verts[0], verts[1]], bottom_uvs, Vector3.DOWN)
|
||||||
|
|
||||||
other_block_position = block_sub_position + Vector3i.UP
|
|
||||||
other_block_id = 0
|
other_block_id = 0
|
||||||
if other_block_position.y == CHUNK_SIZE:
|
if block_sub_position.y == CHUNK_SIZE - 1:
|
||||||
other_block_id = voxel_world.get_block_global_position(other_block_position + chunk_position * CHUNK_SIZE)
|
var other_sub_pos: Vector3i = Vector3i(block_sub_position.x, 0, block_sub_position.z)
|
||||||
elif data.has(other_block_position):
|
other_block_id = voxel_world.get_block_in_chunk(chunk_position + Vector3i.UP, other_sub_pos)
|
||||||
other_block_id = data[other_block_position]
|
else:
|
||||||
|
var other_block_sub_pos: Vector3i = block_sub_position + Vector3i.UP
|
||||||
|
if data.has(other_block_sub_pos):
|
||||||
|
other_block_id = data[other_block_sub_pos]
|
||||||
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
if block_id != other_block_id and Chunk.is_block_transparent(other_block_id):
|
||||||
_draw_block_face(surface_tool, [verts[2], verts[3], verts[6], verts[7]], top_uvs)
|
_draw_block_face(surface_tool, [verts[2], verts[3], verts[6], verts[7]], top_uvs, Vector3.UP)
|
||||||
|
|
||||||
|
|
||||||
func _draw_block_face(surface_tool: SurfaceTool, verts: Array[Vector3], uvs: Array[Vector2]) -> void:
|
func _draw_block_face(surface_tool: SurfaceTool, verts: Array[Vector3], uvs: Array[Vector2], normal: Vector3) -> void:
|
||||||
|
surface_tool.set_normal(normal)
|
||||||
surface_tool.set_uv(uvs[1]); surface_tool.add_vertex(verts[1])
|
surface_tool.set_uv(uvs[1]); surface_tool.add_vertex(verts[1])
|
||||||
surface_tool.set_uv(uvs[2]); surface_tool.add_vertex(verts[2])
|
surface_tool.set_uv(uvs[2]); surface_tool.add_vertex(verts[2])
|
||||||
surface_tool.set_uv(uvs[3]); surface_tool.add_vertex(verts[3])
|
surface_tool.set_uv(uvs[3]); surface_tool.add_vertex(verts[3])
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ extends Node
|
|||||||
|
|
||||||
const CHUNK_MIDPOINT = Vector3(0.5, 0.5, 0.5) * Chunk.CHUNK_SIZE
|
const CHUNK_MIDPOINT = Vector3(0.5, 0.5, 0.5) * Chunk.CHUNK_SIZE
|
||||||
const CHUNK_END_SIZE = Chunk.CHUNK_SIZE - 1
|
const CHUNK_END_SIZE = Chunk.CHUNK_SIZE - 1
|
||||||
|
const DIRECTIONS: Array[Vector3i] = [Vector3i.LEFT, Vector3i.RIGHT, Vector3i.DOWN, Vector3i.UP, Vector3i.FORWARD, Vector3i.BACK]
|
||||||
|
|
||||||
var render_distance: int:
|
var render_distance: int:
|
||||||
set(value):
|
set(value):
|
||||||
@@ -16,7 +17,7 @@ var _old_player_chunk := Vector3i()
|
|||||||
var _generating := true
|
var _generating := true
|
||||||
var _deleting := false
|
var _deleting := false
|
||||||
|
|
||||||
var _chunks := {}
|
var _chunks: Dictionary[Vector3i, Chunk] = {}
|
||||||
|
|
||||||
@onready var player: CharacterBody3D = $"../Player"
|
@onready var player: CharacterBody3D = $"../Player"
|
||||||
|
|
||||||
@@ -50,6 +51,13 @@ func _process(_delta: float) -> void:
|
|||||||
chunk.chunk_position = chunk_position
|
chunk.chunk_position = chunk_position
|
||||||
_chunks[chunk_position] = chunk
|
_chunks[chunk_position] = chunk
|
||||||
add_child(chunk)
|
add_child(chunk)
|
||||||
|
chunk.try_initial_generate_mesh(_chunks)
|
||||||
|
for dir in DIRECTIONS:
|
||||||
|
var neighbor: Chunk = _chunks.get(chunk_position + dir)
|
||||||
|
if neighbor != null and not neighbor.is_initial_mesh_generated:
|
||||||
|
neighbor.try_initial_generate_mesh(_chunks)
|
||||||
|
# Generate at most one chunk per frame in terms of data/colliders.
|
||||||
|
# Mesh generation is threaded so it's ok that the above may generate multiple meshes.
|
||||||
return
|
return
|
||||||
|
|
||||||
# If we didn't generate any chunks (and therefore didn't return), what next?
|
# If we didn't generate any chunks (and therefore didn't return), what next?
|
||||||
@@ -61,14 +69,11 @@ func _process(_delta: float) -> void:
|
|||||||
_generating = false
|
_generating = false
|
||||||
|
|
||||||
|
|
||||||
func get_block_global_position(block_global_position: Vector3i) -> int:
|
func get_block_in_chunk(chunk_position: Vector3i, block_sub_position: Vector3i) -> int:
|
||||||
var chunk_position := Vector3i((block_global_position / Chunk.CHUNK_SIZE))
|
|
||||||
if _chunks.has(chunk_position):
|
if _chunks.has(chunk_position):
|
||||||
var chunk: Chunk = _chunks[chunk_position]
|
var chunk: Chunk = _chunks[chunk_position]
|
||||||
var sub_position := Vector3i(Vector3(block_global_position).posmod(Chunk.CHUNK_SIZE))
|
if chunk.data.has(block_sub_position):
|
||||||
if chunk.data.has(sub_position):
|
return chunk.data[block_sub_position]
|
||||||
return chunk.data[sub_position]
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user