feat(cockpit): replace procedural cockpit with twelve scripted models
Quality Gate / Quality Gate (pull_request) Successful in 9m4s
Quality Gate / Quality Gate (pull_request) Successful in 9m4s
Instance twelve Blender-scripted glTF models in the cockpit scene and rebuild the cabin around them: gauge panel, sonar, switch panel, alert box, speaker, porthole, hull wall, caged lamps, gas bottle, handrails and side consoles. Presentation only; no domain, application or world rule changes beyond enabling glow in the test environment. - Needles, alert lamps and sonar screen are driven by the existing snapshots; the alert box now carries SYS/ATTN/ALRM. - Depth dial reads percent of certified depth. - Sonar display restyled as a turquoise holographic relief with a shader grid and height scale; SubViewport matches the glass (960x604). - Cabin lighting retuned: warm pooled lamp light, cool porthole rim, lamp shadows, dial backlight. - Procedural stand-ins removed (bulkhead, tanks, consoles, levers, indicator columns, placeholder pipe run, dial face PNGs). - Tests adapted where nodes disappeared; one assertion removed (pipe_segment_count) until the pipe kit is placed. - Model .glb files are committed without LFS; textures Godot extracts next to them at import are ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
912123087f
commit
2f9b7c0894
45 files changed
+1353
-1603
No files matched your search
@@ -9,6 +9,28 @@ const CockpitMeshFactory = preload(
|
||||
"res://game/presentation/cockpit/cockpit_mesh_factory.gd"
|
||||
)
|
||||
|
||||
const CAGE_LAMP_SCENE = preload("res://game/presentation/cockpit/assets/models/cage_lamp.glb")
|
||||
|
||||
## Flange centre of the right-hand lamp, on the flat end cap of the pressure
|
||||
## hull beside the porthole (the left lamp mirrors x). The cap is flat there, so
|
||||
## the lamp is seated square to it, facing the cabin.
|
||||
const LAMP_MOUNT_OFFSET := Vector3(0.636, 1.106, -1.3)
|
||||
## Centre of the glass globe in the lamp model: where the light is emitted.
|
||||
const LAMP_GLOBE_CENTRE := Vector3(0.0, 0.0, 0.064)
|
||||
## Globe emission (1.5 as exported): lower, so the globe does not bloom into a blob.
|
||||
const LAMP_GLASS_ENERGY := 1.0
|
||||
## Tungsten-like caged lamps: the cabin's main light.
|
||||
const WARM_LAMP_COLOR := Color(1.0, 0.66, 0.4)
|
||||
const WARM_LAMP_ENERGY := 0.5
|
||||
## Same dimming ratio as before when the red emergency light takes over.
|
||||
const WARM_LAMP_CRITICAL_ENERGY := 0.23
|
||||
## Short range and a steep falloff: each lamp makes a pool on the wall around
|
||||
## it and leaves the lower and outer hull dark.
|
||||
const WARM_LAMP_RANGE_M := 1.6
|
||||
const WARM_LAMP_ATTENUATION := 2.0
|
||||
## Cabin parts are centimetre-scale: the default bias detaches their shadows.
|
||||
const WARM_LAMP_SHADOW_BIAS := 0.03
|
||||
|
||||
var _materials: CockpitMaterialPalette
|
||||
var _warm_lights: Array[OmniLight3D] = []
|
||||
var _emergency_light: OmniLight3D
|
||||
@@ -17,8 +39,8 @@ var _emergency_light: OmniLight3D
|
||||
func _init(materials: CockpitMaterialPalette) -> void:
|
||||
_materials = materials
|
||||
name = "PracticalLighting"
|
||||
_add_caged_lamp(-0.76, -8.0)
|
||||
_add_caged_lamp(0.76, 8.0)
|
||||
_add_caged_lamp(-1.0)
|
||||
_add_caged_lamp(1.0)
|
||||
_add_fill_light()
|
||||
_add_emergency_light()
|
||||
|
||||
@@ -26,75 +48,69 @@ func _init(materials: CockpitMaterialPalette) -> void:
|
||||
func present(alert_level: DiveAlertLevel.Value) -> void:
|
||||
_emergency_light.visible = alert_level >= DiveAlertLevel.Value.CRITICAL
|
||||
for light: OmniLight3D in _warm_lights:
|
||||
light.light_energy = 0.22 if alert_level >= DiveAlertLevel.Value.CRITICAL else 0.48
|
||||
light.light_energy = (
|
||||
WARM_LAMP_CRITICAL_ENERGY
|
||||
if alert_level >= DiveAlertLevel.Value.CRITICAL
|
||||
else WARM_LAMP_ENERGY
|
||||
)
|
||||
|
||||
|
||||
func practical_light_count() -> int:
|
||||
return _warm_lights.size()
|
||||
|
||||
|
||||
func _add_caged_lamp(x: float, roll_degrees: float) -> void:
|
||||
func _add_caged_lamp(side: float) -> void:
|
||||
var root := Node3D.new()
|
||||
root.name = "CagedLamp"
|
||||
root.position = Vector3(x, 0.88, -1.16)
|
||||
root.rotation_degrees.z = roll_degrees
|
||||
root.position = Vector3(
|
||||
side * LAMP_MOUNT_OFFSET.x,
|
||||
LAMP_MOUNT_OFFSET.y,
|
||||
LAMP_MOUNT_OFFSET.z
|
||||
)
|
||||
add_child(root)
|
||||
CockpitMeshFactory.add_box(
|
||||
"LampHousing",
|
||||
root,
|
||||
Vector3(0.0, 0.0, -0.025),
|
||||
Vector3(0.14, 0.11, 0.055),
|
||||
_materials.dark_steel
|
||||
var model := CAGE_LAMP_SCENE.instantiate() as Node3D
|
||||
model.name = "CageLampModel"
|
||||
root.add_child(model)
|
||||
# The light sits inside the cage, 3 cm from its bars: casting, the lamp's
|
||||
# own body would swallow it.
|
||||
CockpitMeshFactory.disable_shadow_casting(model)
|
||||
var glass := CockpitMeshFactory.own_surface_material(
|
||||
model.find_child("CageLamp_Glass", true, false) as MeshInstance3D
|
||||
)
|
||||
CockpitMeshFactory.add_sphere(
|
||||
"WarmBulb",
|
||||
root,
|
||||
Vector3(0.0, 0.0, 0.04),
|
||||
0.038,
|
||||
_materials.warm_glass
|
||||
)
|
||||
for x_offset: float in [-0.048, -0.024, 0.0, 0.024, 0.048]:
|
||||
CockpitMeshFactory.add_box(
|
||||
"LampGuard",
|
||||
root,
|
||||
Vector3(x_offset, 0.0, 0.095),
|
||||
Vector3(0.007, 0.10, 0.007),
|
||||
_materials.brushed_steel
|
||||
)
|
||||
for y_offset: float in [-0.04, 0.04]:
|
||||
CockpitMeshFactory.add_box(
|
||||
"LampGuardRail",
|
||||
root,
|
||||
Vector3(0.0, y_offset, 0.095),
|
||||
Vector3(0.115, 0.007, 0.007),
|
||||
_materials.brushed_steel
|
||||
)
|
||||
if glass != null:
|
||||
glass.emission_energy_multiplier = LAMP_GLASS_ENERGY
|
||||
var light := OmniLight3D.new()
|
||||
light.name = "WarmPracticalLight"
|
||||
light.position = Vector3(0.0, -0.03, 0.16)
|
||||
light.light_color = Color(1.0, 0.55, 0.26)
|
||||
light.light_energy = 0.48
|
||||
light.omni_range = 1.75
|
||||
light.shadow_enabled = false
|
||||
light.position = LAMP_GLOBE_CENTRE
|
||||
light.light_color = WARM_LAMP_COLOR
|
||||
light.light_energy = WARM_LAMP_ENERGY
|
||||
light.omni_range = WARM_LAMP_RANGE_M
|
||||
light.omni_attenuation = WARM_LAMP_ATTENUATION
|
||||
light.shadow_enabled = true
|
||||
light.shadow_bias = WARM_LAMP_SHADOW_BIAS
|
||||
root.add_child(light)
|
||||
_warm_lights.append(light)
|
||||
|
||||
|
||||
func _add_fill_light() -> void:
|
||||
var cool_fill := OmniLight3D.new()
|
||||
cool_fill.name = "CoolRearFill"
|
||||
cool_fill.position = Vector3(0.0, 0.42, 0.35)
|
||||
cool_fill.light_color = Color(0.24, 0.46, 0.47)
|
||||
cool_fill.light_energy = 0.36
|
||||
cool_fill.omni_range = 3.0
|
||||
cool_fill.shadow_enabled = false
|
||||
add_child(cool_fill)
|
||||
# The only cool light in the cabin: sea light entering through the porthole,
|
||||
# placed just inside the glass so it rims the ring, its bolts and the first
|
||||
# band of wall, and reaches the dashboard only from behind.
|
||||
var porthole_fill := OmniLight3D.new()
|
||||
porthole_fill.name = "PortholeFill"
|
||||
porthole_fill.position = Vector3(0.0, 0.47, -1.2)
|
||||
porthole_fill.light_color = Color(0.30, 0.56, 0.78)
|
||||
porthole_fill.light_energy = 1.0
|
||||
porthole_fill.omni_range = 1.1
|
||||
porthole_fill.shadow_enabled = false
|
||||
add_child(porthole_fill)
|
||||
|
||||
|
||||
func _add_emergency_light() -> void:
|
||||
_emergency_light = OmniLight3D.new()
|
||||
_emergency_light.name = "EmergencyLight"
|
||||
_emergency_light.position = Vector3(-0.58, 0.44, -0.83)
|
||||
# High and central, so no single dial sits right under it and washes out.
|
||||
_emergency_light.position = Vector3(0.0, 1.1, -0.95)
|
||||
_emergency_light.light_color = Color(1.0, 0.04, 0.015)
|
||||
_emergency_light.light_energy = 1.4
|
||||
_emergency_light.omni_range = 2.4
|
||||
|
||||
Reference in new issue
Block a user