Browse Source

Merge pull request #894 from Calinou/add-large-world-coordinates-demo

Add a large world coordinates demo
Aaron Franke 2 years ago
parent
commit
f4d146d0ec

+ 29 - 0
misc/large_world_coordinates/README.md

@@ -0,0 +1,29 @@
+# Large World Coordinates
+
+This project showcases optional support for double-precision rendering
+and physics in action.
+
+When using a *single-precision* build, precision errors can be noticeable as soon
+as you're more than a few thousand units away from the world origin.
+
+When using a *double-precision* build, meshes will remain stable even when very
+far away from the world origin (billions of units away or more).
+
+See the
+[Large world coordinates documentation](https://docs.godotengine.org/en/latest/tutorials/physics/large_world_coordinates.html)
+for more information.
+
+> **Warning**
+>
+> Official Godot builds do **not** have double-precision support enabled for performance reasons.
+> You need to compile a custom engine build to use double precision support.
+
+Languages: GDScript
+
+Renderer: Forward Mobile
+
+## Screenshots
+
+![Large World Coordinates without double-precision engine build](screenshots/large_world_coordinates_single_precision_build.webp)
+
+![Large World Coordinates with double-precision engine build](screenshots/large_world_coordinates_double_precision_build.webp)

+ 62 - 0
misc/large_world_coordinates/controls.gd

@@ -0,0 +1,62 @@
+extends VBoxContainer
+
+const ROT_SPEED = 0.003
+const ZOOM_SPEED = 0.5
+const MAIN_BUTTONS = MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_MIDDLE | MOUSE_BUTTON_MASK_RIGHT
+
+@export var camera: Camera3D
+@export var camera_holder: Node3D
+@export var rotation_x: Node3D
+@export var node_to_move: Node3D
+@export var rigid_body: RigidBody3D
+
+@onready var zoom := camera.position.z
+var base_height: int = ProjectSettings.get_setting("display/window/size/viewport_height")
+
+@onready var rot_x := rotation_x.rotation.x
+@onready var rot_y := camera_holder.rotation.y
+
+func _ready() -> void:
+	if OS.has_feature("double"):
+		%HelpLabel.text = "Double precision is enabled in this engine build.\nNo shaking should occur at high coordinate levels\n(±65,536 or more on any axis)."
+		%HelpLabel.add_theme_color_override("font_color", Color(0.667, 1, 0.667))
+
+func _process(delta: float) -> void:
+	%Coordinates.text = "X: [color=#fb9]%f[/color]\nY: [color=#bfa]%f[/color]\nZ: [color=#9cf]%f[/color]" % [node_to_move.position.x, node_to_move.position.y, node_to_move.position.z]
+	if %IncrementX.button_pressed:
+		node_to_move.position.x += 10_000 * delta
+	if %IncrementY.button_pressed:
+		node_to_move.position.y += 100_000 * delta
+	if %IncrementZ.button_pressed:
+		node_to_move.position.z += 1_000_000 * delta
+
+
+func _input(event: InputEvent) -> void:
+	if event is InputEventMouseButton:
+		if event.button_index == MOUSE_BUTTON_WHEEL_UP:
+			zoom -= ZOOM_SPEED
+		if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
+			zoom += ZOOM_SPEED
+		zoom = clampf(zoom, 4, 15)
+		camera.position.z = zoom
+
+	if event is InputEventMouseMotion and event.button_mask & MAIN_BUTTONS:
+		# Compensate motion speed to be resolution-independent (based on the window height).
+		var relative_motion: Vector2 = event.relative * DisplayServer.window_get_size().y / base_height
+		rot_y -= relative_motion.x * ROT_SPEED
+		rot_x -= relative_motion.y * ROT_SPEED
+		rot_x = clampf(rot_x, -1.4, 0.16)
+		camera_holder.transform.basis = Basis.from_euler(Vector3(0, rot_y, 0))
+		rotation_x.transform.basis = Basis.from_euler(Vector3(rot_x, 0, 0))
+
+
+func _on_go_to_button_pressed(x_position: int) -> void:
+	if x_position == 0:
+		# Reset all coordinates, not just X.
+		node_to_move.position = Vector3.ZERO
+	else:
+		node_to_move.position.x = x_position
+
+
+func _on_open_documentation_pressed() -> void:
+	OS.shell_open("https://docs.godotengine.org/en/latest/tutorials/physics/large_world_coordinates.html")

BIN
misc/large_world_coordinates/icon.webp


+ 34 - 0
misc/large_world_coordinates/icon.webp.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dendp8h6s03od"
+path="res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.webp"
+dest_files=["res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 38 - 0
misc/large_world_coordinates/project.godot

@@ -0,0 +1,38 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Large World Coordinates"
+config/description="This project showcases optional support for double-precision rendering
+and physics in action."
+run/main_scene="res://test.tscn"
+config/features=PackedStringArray("4.0")
+run/low_processor_mode=true
+config/icon="res://icon.webp"
+
+[display]
+
+window/stretch/mode="canvas_items"
+window/stretch/aspect="expand"
+
+[physics]
+
+common/physics_ticks_per_second=120
+
+[rendering]
+
+renderer/rendering_method="mobile"
+lights_and_shadows/directional_shadow/size=2048
+lights_and_shadows/directional_shadow/size.mobile=1024
+textures/default_filters/anisotropic_filtering_level=4
+anti_aliasing/quality/msaa_3d=2
+lights_and_shadows/positional_shadow/atlas_size=2048
+lights_and_shadows/positional_shadow/atlas_size.mobile=1024

+ 0 - 0
misc/large_world_coordinates/screenshots/.gdignore


BIN
misc/large_world_coordinates/screenshots/large_world_coordinates_double_precision_build.webp


BIN
misc/large_world_coordinates/screenshots/large_world_coordinates_single_precision_build.webp


+ 379 - 0
misc/large_world_coordinates/test.tscn

@@ -0,0 +1,379 @@
+[gd_scene load_steps=23 format=3 uid="uid://37j1wgn5e8e"]
+
+[ext_resource type="Script" path="res://controls.gd" id="1_ojycn"]
+
+[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_i2lbx"]
+ground_color = Color(1, 1, 1, 1)
+
+[sub_resource type="Sky" id="Sky_rtoqf"]
+sky_material = SubResource("PhysicalSkyMaterial_i2lbx")
+
+[sub_resource type="Environment" id="Environment_ixbrf"]
+background_mode = 2
+sky = SubResource("Sky_rtoqf")
+ambient_light_source = 2
+ambient_light_color = Color(1, 1, 1, 1)
+ambient_light_energy = 0.3
+tonemap_mode = 2
+tonemap_white = 6.0
+
+[sub_resource type="BoxMesh" id="BoxMesh_rpkrt"]
+size = Vector3(16, 16, 16)
+
+[sub_resource type="Gradient" id="Gradient_bk8jh"]
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_p8y4k"]
+fractal_octaves = 10
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_hdp3i"]
+seamless = true
+color_ramp = SubResource("Gradient_bk8jh")
+noise = SubResource("FastNoiseLite_p8y4k")
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_eicib"]
+albedo_color = Color(0.317647, 0.317647, 0.317647, 1)
+albedo_texture = SubResource("NoiseTexture2D_hdp3i")
+roughness_texture = SubResource("NoiseTexture2D_hdp3i")
+uv1_scale = Vector3(12, 8, 1)
+texture_filter = 5
+
+[sub_resource type="BoxMesh" id="BoxMesh_1f2ne"]
+size = Vector3(15, 1, 2)
+
+[sub_resource type="SphereMesh" id="SphereMesh_q0pwk"]
+radius = 2.0
+height = 4.0
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ekrgh"]
+albedo_color = Color(0.266667, 0.666667, 1, 1)
+
+[sub_resource type="TextMesh" id="TextMesh_oxha3"]
+text = "Billboard!"
+font_size = 72
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wvbit"]
+metallic = 0.91
+roughness = 0.14
+emission_enabled = true
+emission = Color(0.733333, 0.733333, 0.733333, 1)
+clearcoat_enabled = true
+clearcoat_roughness = 1.0
+backlight = Color(0.74902, 0.976471, 0, 1)
+disable_receive_shadows = true
+billboard_mode = 1
+billboard_keep_scale = true
+grow_amount = 4.497
+
+[sub_resource type="TorusMesh" id="TorusMesh_44mpc"]
+inner_radius = 2.5
+outer_radius = 3.5
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_i8ybo"]
+transparency = 1
+blend_mode = 1
+albedo_color = Color(0.0666667, 0.313726, 0.768627, 1)
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_r08do"]
+emission_shape = 3
+emission_box_extents = Vector3(8, 0, 8)
+sub_emitter_mode = 3
+sub_emitter_amount_at_collision = 1
+collision_mode = 1
+collision_friction = 0.0
+collision_bounce = 0.2
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_jmbue"]
+shading_mode = 0
+
+[sub_resource type="SphereMesh" id="SphereMesh_f1qcl"]
+material = SubResource("StandardMaterial3D_jmbue")
+radius = 0.05
+height = 0.1
+radial_segments = 4
+rings = 1
+
+[sub_resource type="Animation" id="Animation_c3rry"]
+length = 0.001
+tracks/0/type = "bezier"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Move/Text:position:x")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"handle_modes": PackedInt32Array(0),
+"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0)
+}
+tracks/1/type = "bezier"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Move/Text:position:y")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"handle_modes": PackedInt32Array(0),
+"points": PackedFloat32Array(3.70893, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0)
+}
+tracks/2/type = "bezier"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Move/Text:position:z")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"handle_modes": PackedInt32Array(0),
+"points": PackedFloat32Array(2, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0)
+}
+
+[sub_resource type="Animation" id="Animation_ww6nu"]
+resource_name = "move_text_around"
+length = 2.0
+loop_mode = 1
+tracks/0/type = "position_3d"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Move/Text")
+tracks/0/interp = 2
+tracks/0/loop_wrap = true
+tracks/0/keys = PackedFloat32Array()
+tracks/1/type = "bezier"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Move/Text:position:x")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"handle_modes": PackedInt32Array(0, 0, 0),
+"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0, 1, 2)
+}
+tracks/2/type = "bezier"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Move/Text:position:y")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"handle_modes": PackedInt32Array(0, 0, 0),
+"points": PackedFloat32Array(3.70893, -0.25, 0, 0.25, 0, 3.70893, -0.25, 0, 0.25, 0, 3.70893, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0, 1, 2)
+}
+tracks/3/type = "bezier"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Move/Text:position:z")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"handle_modes": PackedInt32Array(0, 0, 0),
+"points": PackedFloat32Array(-2, -0.25, 0, 0.25, 0, 2, -0.25, 0, 0.25, 0, -2, -0.25, 0, 0.25, 0),
+"times": PackedFloat32Array(0, 1, 2)
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_2gye4"]
+_data = {
+"RESET": SubResource("Animation_c3rry"),
+"move_text_around": SubResource("Animation_ww6nu")
+}
+
+[node name="Node3D" type="Node3D"]
+
+[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
+transform = Transform3D(-0.98244, -0.0593698, 0.176879, 0.0241111, 0.899674, 0.435897, -0.185013, 0.432507, -0.882444, 0.181812, 3.12655, 5.93493)
+shadow_enabled = true
+shadow_bias = 0.04
+shadow_blur = 2.0
+directional_shadow_fade_start = 1.0
+directional_shadow_max_distance = 35.0
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+environment = SubResource("Environment_ixbrf")
+
+[node name="Move" type="Node3D" parent="."]
+
+[node name="Ground" type="MeshInstance3D" parent="Move"]
+transform = Transform3D(-1, 0, -3.82137e-15, 0, 1, -8.74228e-08, 3.82137e-15, -8.74228e-08, -1, -7.45058e-09, -8, 0)
+mesh = SubResource("BoxMesh_rpkrt")
+skeleton = NodePath("../..")
+surface_material_override/0 = SubResource("StandardMaterial3D_eicib")
+
+[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="Move/Ground"]
+transform = Transform3D(-7.37408e-15, 4.37114e-08, -1, 8.74228e-08, 1, 4.37114e-08, 1, -8.74228e-08, -1.31061e-14, -7.45058e-09, 9.53674e-07, 9.53674e-07)
+size = Vector3(16, 16, 16)
+
+[node name="Flat" type="MeshInstance3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 0.996195, -0.0871557, 0, 0.0871557, 0.996195, 0, -0.5, 4.9)
+mesh = SubResource("BoxMesh_1f2ne")
+
+[node name="Sphere" type="MeshInstance3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
+mesh = SubResource("SphereMesh_q0pwk")
+skeleton = NodePath("../..")
+surface_material_override/0 = SubResource("StandardMaterial3D_ekrgh")
+
+[node name="GPUParticlesCollisionSphere3D" type="GPUParticlesCollisionSphere3D" parent="Move/Sphere"]
+radius = 2.0
+
+[node name="Text" type="MeshInstance3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.70893, 2)
+cast_shadow = 0
+mesh = SubResource("TextMesh_oxha3")
+surface_material_override/0 = SubResource("StandardMaterial3D_wvbit")
+
+[node name="Torus" type="MeshInstance3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
+mesh = SubResource("TorusMesh_44mpc")
+skeleton = NodePath("../..")
+surface_material_override/0 = SubResource("StandardMaterial3D_i8ybo")
+
+[node name="CameraHolder" type="Node3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
+
+[node name="RotationX" type="Node3D" parent="Move/CameraHolder"]
+
+[node name="Camera3D" type="Camera3D" parent="Move/CameraHolder/RotationX"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 7)
+
+[node name="GPUParticles3D" type="GPUParticles3D" parent="Move"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 13, 0)
+amount = 1000
+lifetime = 3.0
+fixed_fps = 0
+interpolate = false
+collision_base_size = 0.05
+visibility_aabb = AABB(-15.9834, -43.9765, -15.9858, 31.982, 43.9765, 31.9815)
+local_coords = true
+process_material = SubResource("ParticleProcessMaterial_r08do")
+draw_pass_1 = SubResource("SphereMesh_f1qcl")
+
+[node name="Controls" type="VBoxContainer" parent="." node_paths=PackedStringArray("camera", "camera_holder", "rotation_x", "node_to_move", "rigid_body")]
+offset_left = 16.0
+offset_top = 16.0
+offset_right = 350.0
+offset_bottom = 399.0
+theme_override_constants/separation = 10
+script = ExtResource("1_ojycn")
+camera = NodePath("../Move/CameraHolder/RotationX/Camera3D")
+camera_holder = NodePath("../Move/CameraHolder")
+rotation_x = NodePath("../Move/CameraHolder/RotationX")
+node_to_move = NodePath("../Move")
+rigid_body = NodePath("")
+
+[node name="HelpLabel" type="Label" parent="Controls"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_override_colors/font_color = Color(1, 0.666667, 0.666667, 1)
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+text = "Double precision is not enabled in this engine build.
+Visible shaking is expected at high coordinate levels
+(±65,536 or more on any axis)."
+
+[node name="Button" type="Button" parent="Controls"]
+layout_mode = 2
+text = "Open Documentation"
+
+[node name="HSeparator" type="HSeparator" parent="Controls"]
+layout_mode = 2
+
+[node name="Coordinates" type="RichTextLabel" parent="Controls"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(0, 70)
+layout_mode = 2
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+bbcode_enabled = true
+text = "Object coordinates:"
+
+[node name="IncrementX" type="CheckButton" parent="Controls"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(320, 0)
+layout_mode = 2
+size_flags_horizontal = 0
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+button_pressed = true
+text = "Increment X (10,000 per second)"
+
+[node name="IncrementY" type="CheckButton" parent="Controls"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(320, 0)
+layout_mode = 2
+size_flags_horizontal = 0
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+text = "Increment Y (100,000 per second)"
+
+[node name="IncrementZ" type="CheckButton" parent="Controls"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(320, 0)
+layout_mode = 2
+size_flags_horizontal = 0
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+text = "Increment Z (1,000,000 per second)"
+
+[node name="GoTo" type="Label" parent="Controls"]
+layout_mode = 2
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+text = "Go to X coordinate:"
+
+[node name="HFlowContainer" type="HFlowContainer" parent="Controls"]
+layout_mode = 2
+
+[node name="Button" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "0 (Reset All)"
+
+[node name="Button2" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "10,000"
+
+[node name="Button3" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "100,000"
+
+[node name="Button4" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "1,000,000"
+
+[node name="Button5" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "10,000,000"
+
+[node name="Button6" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "100,000,000"
+
+[node name="Button7" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "1,000,000,000"
+
+[node name="Button8" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "1,000,000,000,000"
+
+[node name="Button9" type="Button" parent="Controls/HFlowContainer"]
+layout_mode = 2
+text = "10,000,000,000,000"
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+autoplay = "move_text_around"
+libraries = {
+"": SubResource("AnimationLibrary_2gye4")
+}
+
+[connection signal="pressed" from="Controls/Button" to="Controls" method="_on_open_documentation_pressed"]
+[connection signal="pressed" from="Controls/HFlowContainer/Button" to="Controls" method="_on_go_to_button_pressed" binds= [0]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button2" to="Controls" method="_on_go_to_button_pressed" binds= [10000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button3" to="Controls" method="_on_go_to_button_pressed" binds= [100000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button4" to="Controls" method="_on_go_to_button_pressed" binds= [1000000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button5" to="Controls" method="_on_go_to_button_pressed" binds= [10000000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button6" to="Controls" method="_on_go_to_button_pressed" binds= [100000000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button7" to="Controls" method="_on_go_to_button_pressed" binds= [1000000000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button8" to="Controls" method="_on_go_to_button_pressed" binds= [1000000000000]]
+[connection signal="pressed" from="Controls/HFlowContainer/Button9" to="Controls" method="_on_go_to_button_pressed" binds= [10000000000000]]