mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
137 lines
5.8 KiB
Plaintext
137 lines
5.8 KiB
Plaintext
// Opaque hull for the arena: the deck, the fillets easing it into the walls,
|
|
// and the bulkheads surrounding each goal mouth — the lit half of
|
|
// ArenaBoundary's visual shell.
|
|
//
|
|
// Everything is drawn procedurally from the vertex's position in the
|
|
// boundary's local space, so field markings are resolution-independent and
|
|
// need no decals, UVs or texture authoring. All dimensions arrive as uniforms
|
|
// set from ArenaBoundary's constants (see _make_deck_material), so the
|
|
// markings cannot drift away from the collision geometry they describe.
|
|
shader_type spatial;
|
|
render_mode cull_back, diffuse_burley, specular_schlick_ggx;
|
|
|
|
uniform vec3 deck_color : source_color = vec3(0.085, 0.095, 0.122);
|
|
// Kept close to deck_color on purpose: per-plate variation is meant to break
|
|
// up a 24x36 m plane, not to reintroduce visible tiling.
|
|
uniform vec3 panel_color : source_color = vec3(0.104, 0.116, 0.146);
|
|
uniform float panel_variation : hint_range(0.0, 1.0) = 0.4;
|
|
uniform vec3 line_color : source_color = vec3(0.62, 0.78, 1.0);
|
|
// Must track TeamColors.TEAM_COLORS in scripts/team_colors.gd — shaders can't
|
|
// import GDScript consts, and arena_boundary.gd always overrides these at
|
|
// runtime, but keep the literal defaults in sync for anyone inspecting the
|
|
// shader/material directly.
|
|
uniform vec3 team0_color : source_color = vec3(0.48, 0.18, 0.88);
|
|
uniform vec3 team1_color : source_color = vec3(0.24, 0.86, 0.42);
|
|
uniform vec3 seam_color : source_color = vec3(0.35, 0.75, 1.0);
|
|
|
|
// Play-volume dimensions, from ArenaBoundary's constants.
|
|
uniform float half_x = 12.0;
|
|
uniform float half_z = 18.0;
|
|
uniform float goal_line_z = 18.0;
|
|
uniform float base_radius = 2.0;
|
|
|
|
uniform float centre_circle_radius = 4.0;
|
|
uniform float goal_area_depth = 6.0;
|
|
uniform float goal_area_half_width = 6.0;
|
|
uniform float line_width = 0.14;
|
|
// Each arena's Environment runs glow at hdr_threshold ~1.0 with hdr_scale 2.0,
|
|
// so emission much above 1 blooms into a white smear. These stay under it.
|
|
uniform float line_emission : hint_range(0.0, 8.0) = 0.65;
|
|
uniform float seam_emission : hint_range(0.0, 8.0) = 0.8;
|
|
uniform float seam_width = 0.22;
|
|
uniform float end_zone_strength : hint_range(0.0, 1.0) = 0.12;
|
|
uniform float panel_size = 4.0;
|
|
uniform float panel_line_width : hint_range(0.0, 0.5) = 0.05;
|
|
// Deliberately not a high metallic value: the local pitch lights and SDFGI
|
|
// need enough diffuse response to reveal the plating instead of turning it
|
|
// into a dark mirror at grazing angles.
|
|
uniform float deck_metallic : hint_range(0.0, 1.0) = 0.3;
|
|
uniform float deck_roughness : hint_range(0.0, 1.0) = 0.34;
|
|
|
|
varying vec3 v_local;
|
|
varying vec3 v_local_normal;
|
|
|
|
void vertex() {
|
|
v_local = VERTEX;
|
|
v_local_normal = NORMAL;
|
|
}
|
|
|
|
float hash21(vec2 p) {
|
|
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
|
|
}
|
|
|
|
// 1 inside a band of width `w` centred on the zero of `d`, screen-space
|
|
// antialiased so lines stay crisp at grazing angles and don't shimmer.
|
|
float band(float d, float w) {
|
|
float aa = fwidth(d) + 0.001;
|
|
return 1.0 - smoothstep(w * 0.5, w * 0.5 + aa, abs(d));
|
|
}
|
|
|
|
// Antialiased outline of the axis-aligned box |p| <= half_size.
|
|
float rect_outline(vec2 p, vec2 half_size, float w) {
|
|
vec2 d = abs(p) - half_size;
|
|
return band(max(d.x, d.y), w);
|
|
}
|
|
|
|
// Plate seam mask for one projection plane.
|
|
float plate_seam(vec2 p) {
|
|
vec2 d = abs(fract(p / panel_size) - 0.5) * panel_size;
|
|
float m = min(d.x, d.y);
|
|
return 1.0 - smoothstep(panel_line_width, panel_line_width + fwidth(m) + 0.01, m);
|
|
}
|
|
|
|
void fragment() {
|
|
vec2 xz = v_local.xz;
|
|
vec3 n = normalize(v_local_normal);
|
|
float up_facing = clamp(n.y, 0.0, 1.0);
|
|
|
|
// --- hull plating ----------------------------------------------------
|
|
// Projected onto whichever plane each facet most faces, blended by
|
|
// |normal|, so plating doesn't smear up the fillets or stripe the vertical
|
|
// goal bulkheads the way a flat XZ projection did.
|
|
vec3 w = abs(n);
|
|
w /= max(w.x + w.y + w.z, 0.001);
|
|
float seams = w.x * plate_seam(v_local.zy)
|
|
+ w.y * plate_seam(v_local.xz)
|
|
+ w.z * plate_seam(v_local.xy);
|
|
vec3 albedo = mix(deck_color, panel_color, hash21(floor(xz / panel_size)) * panel_variation);
|
|
albedo = mix(albedo, deck_color * 0.55, seams);
|
|
float rough = deck_roughness + seams * 0.25;
|
|
|
|
// --- team-tinted end zones -------------------------------------------
|
|
// Team 0 defends +z (see the arenas' GoalTeam0 transforms), team 1 -z.
|
|
float t0 = smoothstep(0.0, half_z, xz.y);
|
|
float t1 = smoothstep(0.0, half_z, -xz.y);
|
|
vec3 zone = team0_color * t0 + team1_color * t1;
|
|
|
|
// Markings belong on the flat deck only: fade them out as the fillet lifts
|
|
// away from the floor, and drop them entirely on anything not facing up so
|
|
// they never wrap onto a goal bulkhead.
|
|
float flat_deck = (1.0 - smoothstep(0.0, base_radius * 0.4, v_local.y)) * up_facing;
|
|
albedo = mix(albedo, albedo + zone * 0.18, end_zone_strength * flat_deck);
|
|
|
|
// --- field markings ---------------------------------------------------
|
|
float marks = band(length(xz) - centre_circle_radius, line_width);
|
|
marks = max(marks, band(xz.y, line_width));
|
|
for (int i = 0; i < 2; i++) {
|
|
float s = i == 0 ? 1.0 : -1.0;
|
|
vec2 c = vec2(0.0, s * (goal_line_z - goal_area_depth * 0.5));
|
|
marks = max(marks, rect_outline(
|
|
xz - c, vec2(goal_area_half_width, goal_area_depth * 0.5), line_width));
|
|
}
|
|
marks *= flat_deck;
|
|
|
|
// --- deck/field handover ---------------------------------------------
|
|
// A band, not a step: it has to light the top edge of the fillets and the
|
|
// matching edge of the goal bulkheads without setting the whole of an
|
|
// elevated bulkhead (which sits far above base_radius) glowing.
|
|
float seam = 1.0 - smoothstep(0.0, seam_width, abs(v_local.y - base_radius));
|
|
|
|
ALBEDO = mix(albedo, line_color, marks);
|
|
METALLIC = deck_metallic * (1.0 - marks);
|
|
ROUGHNESS = clamp(mix(rough, 0.5, marks), 0.05, 1.0);
|
|
EMISSION = line_color * marks * line_emission
|
|
+ seam_color * seam * seam_emission
|
|
+ zone * 0.015 * flat_deck;
|
|
}
|