feat: replace ship and ball placeholder meshes with Blender-modeled assets

Ship gets a greebled hull, tapered nose, swept canopy, twin engine nacelles,
and tail fin (built via the vendored Blender MCP, generator committed at
tools/blender/gen_ship.py) in place of the 5 flat primitives. The ball is
fully remodeled as a smooth round sphere with a crossed emissive accent
pattern (gen_ball.py), replacing the old flat-shaded gold_ball rather than
just tweaking its material.

Node names (Nose/TailFin) are preserved for Ship._apply_team_color(), and
the RigidBody3D/CollisionShape3D physics on both ship.tscn and ball.tscn are
untouched so RL-trained bots and flight feel stay valid. Each part's mesh is
extracted to a standalone .res (tools/blender/extract_meshes.gd) rather than
referenced via glb::ArrayMesh_xxx sub-paths, which don't reliably resolve
across scene files and were silently rendering both models invisible.
This commit is contained in:
Josh Creek
2026-08-03 22:39:46 +01:00
parent 50c2014361
commit 1eb5a3188d
34 changed files with 881 additions and 91 deletions
Binary file not shown.
@@ -3,13 +3,13 @@
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://85qbs3rignos"
path="res://.godot/imported/gold_ball.blend-c2b8b4e1fb4c47cd0c20f77e5daf34c2.scn"
uid="uid://ckohaa5ebxym2"
path="res://.godot/imported/ball.blend-22aebbee9e0a3f479241b5a042aee325.scn"
[deps]
source_file="res://assets/blender_models/gold_ball.blend"
dest_files=["res://.godot/imported/gold_ball.blend-c2b8b4e1fb4c47cd0c20f77e5daf34c2.scn"]
source_file="res://assets/blender_models/ball.blend"
dest_files=["res://.godot/imported/ball.blend-22aebbee9e0a3f479241b5a042aee325.scn"]
[params]
@@ -46,7 +46,7 @@ blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/vertex_colors=2
blender/meshes/vertex_colors=1
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/export_geometry_nodes_instances=false
@@ -60,4 +60,4 @@ blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true
gltf/naming_version=2
gltf/texture_map_mode=0
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,63 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bp2eqsu8o3082"
path="res://.godot/imported/ship.blend-1bdca1ba6b72cf6be2f2eb32002cf7c8.scn"
[deps]
source_file="res://assets/blender_models/ship.blend"
dest_files=["res://.godot/imported/ship.blend-1bdca1ba6b72cf6be2f2eb32002cf7c8.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
blender/nodes/visible=0
blender/nodes/active_collection_only=false
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/vertex_colors=1
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/export_geometry_nodes_instances=false
blender/meshes/gpu_instances=false
blender/meshes/tangents=true
blender/meshes/skins=2
blender/meshes/export_bones_deforming_mesh_only=false
blender/materials/unpack_enabled=true
blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true
gltf/naming_version=2
gltf/texture_map_mode=1
Binary file not shown.
@@ -3,18 +3,18 @@
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://cpawiqbrjyip5"
path="res://.godot/imported/gold_ball.glb-704aa0b9ad2b63d580121e20c4482485.scn"
uid="uid://dj4x6k2phqsas"
path="res://.godot/imported/ball.glb-54e57a8d163cfef28e5e007118be03c5.scn"
[deps]
source_file="res://assets/models/gold_ball.glb"
dest_files=["res://.godot/imported/gold_ball.glb-704aa0b9ad2b63d580121e20c4482485.scn"]
source_file="res://assets/models/ball.glb"
dest_files=["res://.godot/imported/ball.glb-54e57a8d163cfef28e5e007118be03c5.scn"]
[params]
nodes/root_type="Node3D"
nodes/root_name="Scene Root"
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
@@ -39,21 +39,7 @@ import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={
"meshes": {
"gold_ball_Sphere": {
"generate/lightmap_uv": 0,
"generate/lods": 0,
"generate/shadow_meshes": 0,
"lods/normal_merge_angle": 60.0,
"lods/normal_split_angle": 25.0,
"save_to_file/enabled": true,
"save_to_file/fallback_path": "res://assets/models/gold_ball.res",
"save_to_file/make_streamable": "",
"save_to_file/path": "uid://ucw1lyo43yi4"
}
}
}
gltf/naming_version=0
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=0
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://dqsruccgu70n6"
path="res://.godot/imported/ship_canopy.glb-eb012be4d2aaadd3ad4ce782ee3cac26.scn"
[deps]
source_file="res://assets/models/ship_canopy.glb"
dest_files=["res://.godot/imported/ship_canopy.glb-eb012be4d2aaadd3ad4ce782ee3cac26.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://3kf7d62qivgv"
path="res://.godot/imported/ship_engine_l.glb-36865e4bdf2ded2bf550380b5e5a31da.scn"
[deps]
source_file="res://assets/models/ship_engine_l.glb"
dest_files=["res://.godot/imported/ship_engine_l.glb-36865e4bdf2ded2bf550380b5e5a31da.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://w3ps73chyt2t"
path="res://.godot/imported/ship_engine_r.glb-214ece30da53490ddc1cb491c37e947a.scn"
[deps]
source_file="res://assets/models/ship_engine_r.glb"
dest_files=["res://.godot/imported/ship_engine_r.glb-214ece30da53490ddc1cb491c37e947a.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://31h3nccel10k"
path="res://.godot/imported/ship_hull.glb-e35cc22e21d218aa71b911f28b0dd14f.scn"
[deps]
source_file="res://assets/models/ship_hull.glb"
dest_files=["res://.godot/imported/ship_hull.glb-e35cc22e21d218aa71b911f28b0dd14f.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://yio14umwtku1"
path="res://.godot/imported/ship_nose.glb-84e1b2cefdde564b2174201282e01d4e.scn"
[deps]
source_file="res://assets/models/ship_nose.glb"
dest_files=["res://.godot/imported/ship_nose.glb-84e1b2cefdde564b2174201282e01d4e.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://c1i2lsx58u146"
path="res://.godot/imported/ship_tailfin.glb-d9d8f37674e2cf04cd3606e5c7a5c641.scn"
[deps]
source_file="res://assets/models/ship_tailfin.glb"
dest_files=["res://.godot/imported/ship_tailfin.glb-d9d8f37674e2cf04cd3606e5c7a5c641.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1
Binary file not shown.
+3 -3
View File
@@ -1,6 +1,6 @@
[gd_scene load_steps=5 format=3 uid="uid://27u3tdc5yqnl"]
[ext_resource type="ArrayMesh" uid="uid://ucw1lyo43yi4" path="res://assets/models/gold_ball.res" id="1_ct1s3"]
[ext_resource type="ArrayMesh" path="res://assets/models/ball.res" id="1_ball"]
[ext_resource type="Script" path="res://scripts/ball.gd" id="2_ball"]
[sub_resource type="SphereShape3D" id="SphereShape3D_c5p07"]
@@ -24,5 +24,5 @@ metadata/_edit_group_ = true
shape = SubResource("SphereShape3D_c5p07")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 2.08165e-12, 2.08165e-12, 2.08165e-12)
mesh = ExtResource("1_ct1s3")
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0)
mesh = ExtResource("1_ball")
+21 -58
View File
@@ -1,58 +1,17 @@
[gd_scene load_steps=13 format=3 uid="uid://p07epxnh8wwp"]
[ext_resource type="Script" uid="uid://dyq1n7q1bqjps" path="res://scripts/ship.gd" id="1_efag7"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_hull.res" id="2_hull"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_nose.res" id="3_nose"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_canopy.res" id="4_canopy"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_tailfin.res" id="5_talfin"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_engine_l.res" id="6_enginel"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_engine_r.res" id="7_enginer"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_ship"]
friction = 0.1
bounce = 0.15
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hull"]
albedo_color = Color(0.35, 0.37, 0.42, 1)
metallic = 0.6
roughness = 0.4
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_accent"]
albedo_color = Color(0.25, 0.55, 1, 1)
metallic = 0.3
roughness = 0.5
emission_enabled = true
emission = Color(0.25, 0.55, 1, 1)
emission_energy_multiplier = 0.35
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_canopy"]
albedo_color = Color(0.15, 0.85, 1, 1)
metallic = 0.8
roughness = 0.1
emission_enabled = true
emission = Color(0.15, 0.85, 1, 1)
emission_energy_multiplier = 0.5
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_engine"]
albedo_color = Color(1, 0.55, 0.15, 1)
emission_enabled = true
emission = Color(1, 0.55, 0.15, 1)
emission_energy_multiplier = 2.0
[sub_resource type="BoxMesh" id="BoxMesh_hull"]
material = SubResource("StandardMaterial3D_hull")
size = Vector3(1, 0.75, 2.7)
[sub_resource type="PrismMesh" id="PrismMesh_nose"]
material = SubResource("StandardMaterial3D_accent")
size = Vector3(1, 1.4, 0.75)
[sub_resource type="BoxMesh" id="BoxMesh_canopy"]
material = SubResource("StandardMaterial3D_canopy")
size = Vector3(0.55, 0.28, 0.8)
[sub_resource type="BoxMesh" id="BoxMesh_fin"]
material = SubResource("StandardMaterial3D_accent")
size = Vector3(0.1, 0.5, 0.8)
[sub_resource type="BoxMesh" id="BoxMesh_engine"]
material = SubResource("StandardMaterial3D_engine")
size = Vector3(0.7, 0.5, 0.25)
[sub_resource type="BoxShape3D" id="BoxShape3D_dsjou"]
size = Vector3(1, 1, 4)
@@ -63,24 +22,28 @@ inertia = Vector3(1, 1, 1)
script = ExtResource("1_efag7")
[node name="Hull" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.125, 0.35)
mesh = SubResource("BoxMesh_hull")
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0)
mesh = ExtResource("2_hull")
[node name="Nose" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0, -0.125, -1.3)
mesh = SubResource("PrismMesh_nose")
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0)
mesh = ExtResource("3_nose")
[node name="Canopy" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.36, -0.5)
mesh = SubResource("BoxMesh_canopy")
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.31, -0.55)
mesh = ExtResource("4_canopy")
[node name="TailFin" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 1.25)
mesh = SubResource("BoxMesh_fin")
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.24, 0.72)
mesh = ExtResource("5_talfin")
[node name="EngineGlow" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.125, 1.85)
mesh = SubResource("BoxMesh_engine")
[node name="EngineGlowL" type="MeshInstance3D" parent="."]
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, -0.42, -0.05, 0.95)
mesh = ExtResource("6_enginel")
[node name="EngineGlowR" type="MeshInstance3D" parent="."]
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0.42, -0.05, 0.95)
mesh = ExtResource("7_enginer")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_dsjou")