diff --git a/assets/shaders/black_hole.wgsl b/assets/shaders/black_hole.wgsl index 66c456e..0be4aa3 100644 --- a/assets/shaders/black_hole.wgsl +++ b/assets/shaders/black_hole.wgsl @@ -1,6 +1,7 @@ #import bevy_sprite::mesh2d_vertex_output::VertexOutput #import "shaders/ray_gen.wgsl" #import "shaders/geodesic_schwarzschild.wgsl" +#import "shaders/stars.wgsl" struct BlackHoleUniforms { eye: vec4, @@ -36,13 +37,13 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 { var uv = (in.uv * 2.0 - 1.0); uv.x *= aspect; let dir = ray_direction(uv); - // Step size scales with how far we need to travel (~ distance/ steps). let dt = max(length(uniforms.eye.xyz), 20.0) / f32(uniforms.steps); let res = classify_ray(uniforms.eye.xyz, dir, uniforms.steps, dt); if (res.status == 1u) { // Captured = shadow. return vec4(0.0, 0.0, 0.0, 1.0); } - // Escaped: dim grey for now (stars come in Task 11). - return vec4(0.02, 0.02, 0.02, 1.0); + // Escaped: sample procedural stars along the bent final direction. + let star = star_color(normalize(res.final_dir), uniforms.star_intensity); + return vec4(star, 1.0); } diff --git a/assets/shaders/stars.wgsl b/assets/shaders/stars.wgsl new file mode 100644 index 0000000..2690777 --- /dev/null +++ b/assets/shaders/stars.wgsl @@ -0,0 +1,27 @@ +// Hash-based procedural stars on the unit sphere. Returns RGB radiance. +fn hash13(p: vec3) -> f32 { + var q = vec3(dot(p, vec3(127.1, 311.7, 74.7)), + dot(p, vec3(269.5, 183.3, 246.1)), + dot(p, vec3(113.5, 271.9, 124.6))); + let h = fract(sin(q) * 43758.5453); + return h.x; +} + +fn star_color(dir: vec3, intensity: f32) -> vec3 { + // Divide the sphere into cells; a cell gets a star if its hash passes a threshold. + let scale = 80.0; + let cell = floor(dir * scale); + let h = hash13(cell); + let threshold = 0.985; // ~1.5% of cells hold a star + if (h > threshold) { + // Brightness from the hash remainder. + let b = (h - threshold) / (1.0 - threshold); + let col = mix(vec3(0.6, 0.7, 1.0), vec3(1.0, 0.9, 0.7), b); + // Soften the star with the fractional position inside the cell. + let f = abs(dir * scale - cell); + let d = max(f.x, max(f.y, f.z)); + let falloff = smoothstep(0.5, 0.0, d); + return col * b * falloff * 3.0 * intensity; + } + return vec3(0.0); +}