Initial commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
extends Node3D
|
||||
## Swap only when the real Moon is about to leave the far plane.
|
||||
## At handover the disc matches the real angular size. It shrinks with distance.
|
||||
## A late boost only kicks in when the disc would become a speck (Earth).
|
||||
|
||||
@export var real_moon_path: NodePath = ^".."
|
||||
@export var surface_high_path: NodePath = ^"../SurfaceHigh"
|
||||
@export var impostor_mesh_path: NodePath = ^"ImposterSphere"
|
||||
@export var switch_distance: float = 850000.0
|
||||
@export var visual_distance: float = 280000.0
|
||||
@export var real_radius: float = 173700.0
|
||||
@export var far_boost_start: float = 2500000.0
|
||||
@export var far_boost_end: float = 20000000.0
|
||||
@export var far_boost: float = 5.0
|
||||
|
||||
var _real_moon: Node3D
|
||||
var _surface_high: Node3D
|
||||
var _surface_low: Node3D
|
||||
var _mesh: MeshInstance3D
|
||||
var _base_radius: float = 0.5
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_real_moon = get_node_or_null(real_moon_path) as Node3D
|
||||
_surface_high = get_node_or_null(surface_high_path) as Node3D
|
||||
if _surface_high == null and _real_moon:
|
||||
_surface_high = _real_moon.get_node_or_null("SurfaceHigh") as Node3D
|
||||
if _real_moon:
|
||||
_surface_low = _real_moon.get_node_or_null("SurfaceLow") as Node3D
|
||||
_mesh = get_node_or_null(impostor_mesh_path) as MeshInstance3D
|
||||
if _mesh == null:
|
||||
_mesh = find_child("ImposterSphere", true, false) as MeshInstance3D
|
||||
if _mesh:
|
||||
_mesh.top_level = true
|
||||
_mesh.visible = false
|
||||
_mesh.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
if _mesh.mesh is SphereMesh:
|
||||
var sm := _mesh.mesh as SphereMesh
|
||||
_base_radius = maxf(sm.radius, 0.5)
|
||||
sm.radial_segments = maxi(sm.radial_segments, 32)
|
||||
sm.rings = maxi(sm.rings, 16)
|
||||
var mat := _mesh.get_active_material(0)
|
||||
if mat == null:
|
||||
mat = _mesh.material_override
|
||||
if mat is StandardMaterial3D:
|
||||
var copy := (mat as StandardMaterial3D).duplicate() as StandardMaterial3D
|
||||
copy.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
_mesh.material_override = copy
|
||||
print("MoonImposter ready switch=", switch_distance, " mesh=", _mesh)
|
||||
set_process(true)
|
||||
|
||||
|
||||
func _hide_real(hide: bool) -> void:
|
||||
if _surface_high:
|
||||
_surface_high.visible = not hide
|
||||
if _surface_low:
|
||||
_surface_low.visible = not hide
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if _real_moon == null or _mesh == null:
|
||||
return
|
||||
var viewer: Node3D = FloatingOrigin.focus
|
||||
if viewer == null or not is_instance_valid(viewer):
|
||||
_mesh.visible = false
|
||||
return
|
||||
if _real_moon.has_meta("hide_crust") and bool(_real_moon.get_meta("hide_crust")):
|
||||
_mesh.visible = false
|
||||
_hide_real(true)
|
||||
return
|
||||
var to_moon: Vector3 = _real_moon.global_position - viewer.global_position
|
||||
var dist: float = to_moon.length()
|
||||
if dist < switch_distance:
|
||||
_mesh.visible = false
|
||||
_hide_real(false)
|
||||
return
|
||||
_hide_real(true)
|
||||
var dir: Vector3 = to_moon / maxf(dist, 1.0)
|
||||
_mesh.global_position = viewer.global_position + dir * visual_distance
|
||||
var exact: float = real_radius * (visual_distance / dist)
|
||||
var t: float = 0.0
|
||||
if dist > far_boost_start:
|
||||
t = clampf((dist - far_boost_start) / maxf(far_boost_end - far_boost_start, 1.0), 0.0, 1.0)
|
||||
var visual_radius: float = exact * lerpf(1.0, far_boost, t)
|
||||
visual_radius = clampf(visual_radius, 200.0, visual_distance * 0.85)
|
||||
_mesh.scale = Vector3.ONE * (visual_radius / _base_radius)
|
||||
_mesh.visible = true
|
||||
Reference in New Issue
Block a user