mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
18fdb0f232
Retraining from scratch removes the constraint that blocked these: the existing checkpoints in Game/bots/promoted/ no longer need byte-identical geometry. - Fix the goal aperture constants (were 1.85/1.65, now match objects/goal.tscn's actual sensor exactly at 1.75/1.5) so a ball crossing the visible edge can't fail to score. - Cut a real navigable hole in each end wall's collision (_build_end_wall_colliders), replacing the previous solid box — the ball now genuinely enters the net instead of triggering the sensor a hair before hitting a solid wall. Correct for both FLOOR and ELEVATED goal modes via _goal_surround_bounds. A separate, slightly wider GOAL_VISUAL_APERTURE_* pair keeps the collision hole exact while still giving goal.gd's bezel/rim frame clearance to be seen against the hull cut. - Resize the play volume 1.5x (INNER_HALF_X/Z/HEIGHT 12/18/12 -> 18/27/18) to comfortably fit a 5v5 roster: updates every hand-authored literal in arena_boundary.tscn/arena_base.tscn/the elevated arena variants that doesn't derive from those constants, adds 5 spawn markers per team, and rescales ship_observations.gd's normalization scales and arena_02's cosmetic decoration/nebula-dust shader uniforms to match. - Bake the ~170 runtime-generated CollisionShape3D nodes into the scene via a new bake_colliders()/tools/bake_arena_boundary.gd instead of rebuilding them on every load — a real load-time cost repeated in every parallel headless training env. Colliders must be direct children of the StaticBody3D to register at all, so bake_colliders() parents them onto self and tags them with a group for idempotent re-baking, rather than grouping them under an intermediate container node. _ready() self-heals: it skips regenerating only when an existing bake's goal_mode metadata matches the current one, so the FLOOR-mode bake in the shared scene is never silently reused by an ELEVATED arena variant.
69 lines
3.1 KiB
Plaintext
69 lines
3.1 KiB
Plaintext
shader_type spatial;
|
|
render_mode blend_mix, depth_draw_never, cull_disabled, specular_disabled;
|
|
|
|
uniform sampler2D albedo_tex : source_color;
|
|
uniform sampler2D depth_tex : hint_depth_texture, filter_linear_mipmap;
|
|
uniform vec3 core_bias_color : source_color = vec3(1.0, 0.6, 0.85);
|
|
uniform float core_bias_amount : hint_range(0.0, 1.0) = 0.35;
|
|
uniform float emission_strength : hint_range(0.0, 5.0) = 2.5;
|
|
uniform float soft_fade_distance : hint_range(0.0, 5.0) = 1.0;
|
|
// Arena play volume (world space) this weather effect must stay clear of —
|
|
// see ArenaBoundary.INNER_HALF_X/INNER_HALF_Z/INNER_HEIGHT. Dust is fully
|
|
// hidden inside that box and fades in over arena_clear_distance beyond it,
|
|
// so it reads as drifting around the station rather than through the pitch.
|
|
uniform vec3 arena_half_extents = vec3(18.0, 9.0, 27.0);
|
|
uniform vec3 arena_centre = vec3(0.0, 9.0, 0.0);
|
|
uniform float arena_clear_distance : hint_range(0.0, 10.0) = 2.0;
|
|
|
|
varying float v_flicker;
|
|
varying float v_arena_fade;
|
|
|
|
void vertex() {
|
|
// true billboard: strip rotation from the per-instance modelview, keep translation + scale
|
|
mat4 mv = MODELVIEW_MATRIX;
|
|
mv[0].xyz = vec3(length(mv[0].xyz), 0.0, 0.0);
|
|
mv[1].xyz = vec3(0.0, length(mv[1].xyz), 0.0);
|
|
mv[2].xyz = vec3(0.0, 0.0, length(mv[2].xyz));
|
|
VERTEX = (mv * vec4(VERTEX, 1.0)).xyz;
|
|
|
|
// INSTANCE_CUSTOM.x is GPUParticles3D's per-particle random seed, baked at spawn
|
|
float seed = INSTANCE_CUSTOM.x;
|
|
float flicker_hash = fract(sin((seed + floor(TIME * 6.0)) * 127.1) * 43758.5453);
|
|
v_flicker = 0.85 + 0.15 * flicker_hash;
|
|
|
|
// MODEL_MATRIX's translation column is this particle's world-space
|
|
// origin (pre-billboard, so unaffected by the VERTEX rewrite above).
|
|
// Chebyshev (box) distance outside arena_half_extents, in metres.
|
|
vec3 particle_pos = MODEL_MATRIX[3].xyz;
|
|
vec3 outside = abs(particle_pos - arena_centre) - arena_half_extents;
|
|
float outside_dist = max(max(outside.x, outside.y), outside.z);
|
|
v_arena_fade = smoothstep(0.0, arena_clear_distance, outside_dist);
|
|
}
|
|
|
|
void fragment() {
|
|
// fake a puff/sphere normal from local UV so a camera-facing billboard can still catch directional light;
|
|
// the quad is billboarded to face the camera in vertex(), so this normal is already view-space aligned
|
|
vec2 centered = UV * 2.0 - 1.0;
|
|
float r2 = dot(centered, centered);
|
|
float mask = clamp(1.0 - r2, 0.0, 1.0);
|
|
NORMAL = normalize(vec3(centered, sqrt(max(mask, 0.001))));
|
|
|
|
vec4 tex = texture(albedo_tex, UV);
|
|
ALBEDO = tex.rgb * mix(vec3(1.0), core_bias_color, core_bias_amount);
|
|
EMISSION = core_bias_color * tex.rgb * emission_strength * 0.15;
|
|
ALPHA = tex.a * COLOR.a * mask * v_arena_fade;
|
|
|
|
float raw_depth = texture(depth_tex, SCREEN_UV).r;
|
|
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, raw_depth);
|
|
vec4 view_pos = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
|
|
view_pos.xyz /= view_pos.w;
|
|
float scene_depth = -view_pos.z;
|
|
float particle_depth = -VERTEX.z;
|
|
ALPHA *= clamp((scene_depth - particle_depth) / soft_fade_distance, 0.0, 1.0);
|
|
}
|
|
|
|
void light() {
|
|
float ndotl = clamp(dot(NORMAL, LIGHT), 0.0, 1.0);
|
|
DIFFUSE_LIGHT += LIGHT_COLOR * ndotl * ALBEDO * emission_strength * v_flicker * ATTENUATION;
|
|
}
|