shader_type spatial; render_mode diffuse_burley, specular_schlick_ggx; // Luneraria CRYSTAL: opaque faceted crystal with depth. A dark tinted body, inner veins and // star specks sampled at several depths along the view ray (parallax layers) so the crystal // reads as deep rather than as flat transparent plastic, a bright heart towards the object // centre, a fresnel rim and controlled emission. `energy` is the state channel (stable, // unstable, failing), `flicker` adds irregular pulsing, `fracture` dark cracks. uniform float depth_scale = .55; uniform float vein_scale = 2.6; uniform float heart_radius = .45; uniform float rim_power = 2.5; instance uniform vec4 tint : source_color, instance_index(4) = vec4(.45, .75, 1.0, 1.0); instance uniform float energy : instance_index(5) = 1.0; instance uniform float flicker : instance_index(6) = 0.0; instance uniform float fracture : instance_index(11) = 0.0; instance uniform float fade : instance_index(1) = 0.0; instance uniform float fade_floor : instance_index(2) = 2.2; instance uniform float seed : instance_index(3) = 0.0; varying vec3 local_pos; varying vec3 local_view; varying vec3 world_pos; #include "res://scripts/luneraria/view/materials/lune_common.gdshaderinc" void vertex() { local_pos = VERTEX; world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; vec3 camera_local = (inverse(MODEL_MATRIX) * vec4(CAMERA_POSITION_WORLD, 1.0)).xyz; local_view = VERTEX - camera_local; } void fragment() { if (PROJECTION_MATRIX[3][3] < .5 && faded(fade, fade_floor, world_pos.y, FRAGCOORD.xy)) discard; vec3 ray = normalize(local_view); float inner = 0.0; float stars = 0.0; // Three layers deeper and deeper inside the crystal. for (int i = 1; i <= 3; i++) { float d = depth_scale * float(i) / 3.0; vec3 q = local_pos + ray * d; float v = fbm3(q * vein_scale + seed); inner += smoothstep(.52, .78, v) * (1.0 - float(i) * .22); float s = hash13(floor(q * 14.0 + seed)); stars += step(.9965, s) * (1.0 - float(i) * .25); } float heart = exp(-length(local_pos.xz) / max(.05, heart_radius) * 1.6) * (1.0 - smoothstep(0.0, 1.0, abs(local_pos.y) * .5)); float fres = pow(1.0 - clamp(dot(normalize(NORMAL), normalize(VIEW)), 0.0, 1.0), rim_power); float t = TIME * (1.3 + flicker * 5.0) + seed * 6.0; float pulse = .85 + .15 * sin(t); if (flicker > 0.0) { float stutter = step(.5, noise3(vec3(t * 1.7, seed, 0.0))); pulse *= mix(1.0, .35 + .65 * stutter, flicker); } float crack = 0.0; if (fracture > .01) { float c = abs(noise3(local_pos * 6.0 + seed) - .5); crack = (1.0 - smoothstep(.0, .045 * fracture, c)) * step(.3, noise3(local_pos * 2.0 + seed + 5.0)); } // Flat facets: each face gets its own brightness from its normal, so the cut reads. vec3 facet_n = normalize(cross(dFdx(local_pos), dFdy(local_pos))); float facet = .55 + .45 * hash13(floor(facet_n * 3.0 + 7.0)); vec3 body = tint.rgb * .12; ALBEDO = body * (1.0 - crack * .8); ROUGHNESS = .05; METALLIC = 0.0; SPECULAR = .95; float glow = (.12 + inner * .5 * facet + heart * 1.05 + fres * 1.1) * pulse * mix(.7, 1.15, facet); // Hot parts brighten towards a lighter version of the hue, not towards white. vec3 hot = mix(tint.rgb, tint.rgb * .6 + vec3(.4), .22 * heart + .12 * fres); EMISSION = hot * glow * energy * (1.0 - crack * .9) + tint.rgb * stars * .9 * energy; RIM = .3; RIM_TINT = .6; }