Add realistic cockpit surface textures

This commit is contained in:
chindit committed 2026-10-03 09:30:56 +02:00
1 parent 5455ae7928
commit 0b79bf9b82
8 files changed
+160 -23

No files matched your search

@@ -0,0 +1,22 @@
# Cockpit texture provenance
These textures were generated specifically for Ransom's Wake on 3 October 2026
with OpenAI's built-in image generation tool. No third-party image was used as
an input or reference.
## `naval_painted_steel_albedo.png`
Prompt summary: seamless, orthographic PBR-style albedo of dark blue-green
naval painted steel, with restrained salt-air oxidation, micro-scratches,
paint chips and grime; neutral illumination; no borders, rivets, text or
watermark.
## `analog_gauge_face_albedo.png`
Prompt summary: orthographic vintage naval gauge face in aged ivory enamel,
with fine crazing, soot, speckling and a faint printed arc; no bezel, needle,
hub, glass, text, numbers, logo or watermark.
Both source outputs were resized to 1024 × 1024 and stripped of metadata for
runtime use. The original generated outputs remain in the local Codex image
generation store and are not required by the game.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

@@ -12,7 +12,7 @@ var _pressure_needle: Node3D
func _init(materials: CockpitMaterialPalette) -> void:
_materials = materials
name = "AnalogGauges"
_battery_needle = _add_gauge("BatteryGauge", Vector3(-0.34, 0.48, -1.14), "V")
_battery_needle = _add_gauge("BatteryGauge", Vector3(-0.34, 0.48, -1.14), "BAT")
_pressure_needle = _add_gauge("PressureGauge", Vector3(0.34, 0.48, -1.14), "BAR")
@@ -70,10 +70,13 @@ func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3
face_mesh.height = 0.039
face_mesh.radial_segments = 32
face.mesh = face_mesh
face.material_override = _materials.ivory
face.material_override = _materials.gauge_face
face.rotation_degrees.x = 90.0
face.position.z = 0.003
gauge.add_child(face)
_add_scale_label(gauge, "0", Vector3(-0.052, -0.018, 0.028))
_add_scale_label(gauge, "50", Vector3(0.0, 0.052, 0.028))
_add_scale_label(gauge, "100", Vector3(0.052, -0.018, 0.028))
var needle_root := Node3D.new()
needle_root.name = "Needle"
needle_root.position.z = 0.027
@@ -81,9 +84,9 @@ func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3
CockpitMeshFactory.add_box(
"NeedleBlade",
needle_root,
Vector3(0.0, 0.033, 0.0),
Vector3(0.012, 0.064, 0.008),
_materials.red_emission
Vector3(0.0, 0.034, 0.0),
Vector3(0.008, 0.068, 0.006),
_materials.needle_paint
)
CockpitMeshFactory.add_cylinder(
"NeedleHub",
@@ -100,11 +103,35 @@ func _add_gauge(gauge_name: String, position: Vector3, caption: String) -> Node3
label.font_size = 12
label.pixel_size = 0.0007
label.modulate = Color(0.11, 0.12, 0.10)
label.position = Vector3(0.0, -0.045, 0.032)
label.position = Vector3(0.0, -0.044, 0.032)
gauge.add_child(label)
var glass := MeshInstance3D.new()
glass.name = "GaugeGlass"
var glass_mesh := CylinderMesh.new()
glass_mesh.top_radius = 0.081
glass_mesh.bottom_radius = 0.081
glass_mesh.height = 0.004
glass_mesh.radial_segments = 40
glass.mesh = glass_mesh
glass.material_override = _materials.gauge_glass
glass.rotation_degrees.x = 90.0
glass.position.z = 0.036
glass.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
gauge.add_child(glass)
return needle_root
func _add_scale_label(gauge: Node3D, text: String, position: Vector3) -> void:
var label := Label3D.new()
label.name = "Scale%s" % text
label.text = text
label.font_size = 9
label.pixel_size = 0.00048
label.modulate = Color(0.09, 0.085, 0.065)
label.position = position
gauge.add_child(label)
func _set_needle_ratio(needle: Node3D, ratio: float) -> void:
if needle != null:
needle.rotation_degrees.z = lerpf(125.0, -125.0, clampf(ratio, 0.0, 1.0))
+37 -12
View File
@@ -11,6 +11,7 @@ const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh
var _materials: CockpitMaterialPalette
var _painted_steel: Material
var _dark_steel: Material
var _overhead_steel: Material
var _brass: Material
var _copper: Material
var _rubber: Material
@@ -65,10 +66,19 @@ func battery_needle_degrees() -> float:
return 0.0 if _analog_gauges == null else _analog_gauges.battery_needle_degrees()
func textures_are_loaded() -> bool:
return (
_materials != null
and _materials.overhead_steel.albedo_texture != null
and _materials.gauge_face.albedo_texture != null
)
func _create_materials() -> void:
_materials = CockpitMaterialPalette.new()
_painted_steel = _materials.painted_steel
_dark_steel = _materials.dark_steel
_overhead_steel = _materials.overhead_steel
_brass = _materials.brass
_copper = _materials.copper
_rubber = _materials.rubber
@@ -89,16 +99,21 @@ func _apply_materials_to_existing_cockpit() -> void:
_apply_material_to_paths(
_dark_steel,
[
"CabinShell/Ceiling",
"CabinShell/RearBulkhead",
"PortholeAssembly/LeftBulkhead",
"PortholeAssembly/RightBulkhead",
"PortholeAssembly/TopBulkhead",
"PortholeAssembly/BottomBulkhead",
"ThrottleLever",
"VerticalLever",
]
)
_apply_material_to_paths(
_overhead_steel,
[
"CabinShell/Ceiling",
"PortholeAssembly/TopBulkhead",
]
)
_apply_material_to_paths(
_brass,
[
@@ -216,27 +231,37 @@ func _build_overhead_console() -> void:
CockpitMeshFactory.add_box(
"BreakerHousing",
root,
Vector3(0.0, 0.90, -1.08),
Vector3(0.66, 0.13, 0.27),
_painted_steel,
Vector3(0.0, 0.94, -1.06),
Vector3(0.30, 0.09, 0.12),
_overhead_steel,
Vector3(-8.0, 0.0, 0.0)
)
CockpitMeshFactory.add_box(
"WarmLightDiffuser",
root,
Vector3(0.0, 0.835, -0.89),
Vector3(0.38, 0.018, 0.065),
Vector3(0.0, 0.895, -0.985),
Vector3(0.13, 0.010, 0.026),
_warm_emission,
Vector3(-8.0, 0.0, 0.0)
)
for switch_index in 7:
var x := -0.24 + switch_index * 0.08
for guard_index in 5:
var guard_x := -0.05 + guard_index * 0.025
CockpitMeshFactory.add_box(
"LampGuard",
root,
Vector3(guard_x, 0.896, -0.968),
Vector3(0.005, 0.045, 0.008),
_dark_steel,
Vector3(-8.0, 0.0, 0.0)
)
for switch_index in 5:
var x := -0.10 + switch_index * 0.05
CockpitMeshFactory.add_cylinder(
"BreakerSwitch",
root,
Vector3(x, 0.83, -0.88),
0.006,
0.035,
Vector3(x, 0.965, -0.985),
0.004,
0.018,
_rubber,
Vector3(90.0, 0.0, 0.0)
)
@@ -1,14 +1,23 @@
class_name CockpitMaterialPalette
extends RefCounted
const NAVAL_STEEL_TEXTURE_PATH := (
"res://game/presentation/cockpit/assets/naval_painted_steel_albedo.png"
)
const GAUGE_FACE_TEXTURE_PATH := (
"res://game/presentation/cockpit/assets/analog_gauge_face_albedo.png"
)
var painted_steel: Material
var dark_steel: Material
var overhead_steel: StandardMaterial3D
var brass: Material
var copper: Material
var rubber: Material
var ivory: Material
var gauge_face: StandardMaterial3D
var gauge_glass: StandardMaterial3D
var needle_paint: StandardMaterial3D
var warm_emission: StandardMaterial3D
var red_emission: StandardMaterial3D
func _init() -> void:
@@ -26,6 +35,13 @@ func _init() -> void:
0.44,
0.08
)
overhead_steel = _textured_material(
_load_texture(NAVAL_STEEL_TEXTURE_PATH),
Color(0.64, 0.69, 0.68),
0.64,
0.56,
Vector3(1.6, 1.6, 1.6)
)
brass = _weathered_material(
Color(0.28, 0.18, 0.045),
Color(0.08, 0.16, 0.13),
@@ -41,9 +57,15 @@ func _init() -> void:
0.12
)
rubber = _plain_material(Color(0.012, 0.018, 0.018), 0.0, 0.92)
ivory = _plain_material(Color(0.72, 0.69, 0.56), 0.05, 0.63)
gauge_face = _textured_material(
_load_texture(GAUGE_FACE_TEXTURE_PATH),
Color(0.78, 0.74, 0.64),
0.02,
0.72
)
gauge_glass = _glass_material()
needle_paint = _plain_material(Color(0.68, 0.055, 0.022), 0.12, 0.44)
warm_emission = _emissive_material(Color(0.96, 0.52, 0.18), 2.4)
red_emission = _emissive_material(Color(0.92, 0.055, 0.025), 3.6)
func _weathered_material(
@@ -110,6 +132,41 @@ func _plain_material(
return material
func _textured_material(
texture: Texture2D,
tint: Color,
metallic: float,
roughness: float,
uv_scale: Vector3 = Vector3.ONE
) -> StandardMaterial3D:
var material := StandardMaterial3D.new()
material.albedo_color = tint
material.albedo_texture = texture
material.metallic = metallic
material.roughness = roughness
material.uv1_scale = uv_scale
material.texture_filter = BaseMaterial3D.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC
return material
func _load_texture(resource_path: String) -> ImageTexture:
var image := Image.load_from_file(resource_path)
if image == null or image.is_empty():
push_error("Unable to load cockpit texture: %s" % resource_path)
return null
return ImageTexture.create_from_image(image)
func _glass_material() -> StandardMaterial3D:
var material := StandardMaterial3D.new()
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
material.albedo_color = Color(0.42, 0.68, 0.66, 0.13)
material.metallic = 0.12
material.roughness = 0.08
material.cull_mode = BaseMaterial3D.CULL_DISABLED
return material
func _emissive_material(color: Color, energy: float) -> StandardMaterial3D:
var material := StandardMaterial3D.new()
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED