feat: procedural lensed starfield background
This commit is contained in:
parent
d5e3008343
commit
fbe1685a38
@ -1,6 +1,7 @@
|
|||||||
#import bevy_sprite::mesh2d_vertex_output::VertexOutput
|
#import bevy_sprite::mesh2d_vertex_output::VertexOutput
|
||||||
#import "shaders/ray_gen.wgsl"
|
#import "shaders/ray_gen.wgsl"
|
||||||
#import "shaders/geodesic_schwarzschild.wgsl"
|
#import "shaders/geodesic_schwarzschild.wgsl"
|
||||||
|
#import "shaders/stars.wgsl"
|
||||||
|
|
||||||
struct BlackHoleUniforms {
|
struct BlackHoleUniforms {
|
||||||
eye: vec4<f32>,
|
eye: vec4<f32>,
|
||||||
@ -36,13 +37,13 @@ fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||||||
var uv = (in.uv * 2.0 - 1.0);
|
var uv = (in.uv * 2.0 - 1.0);
|
||||||
uv.x *= aspect;
|
uv.x *= aspect;
|
||||||
let dir = ray_direction(uv);
|
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 dt = max(length(uniforms.eye.xyz), 20.0) / f32(uniforms.steps);
|
||||||
let res = classify_ray(uniforms.eye.xyz, dir, uniforms.steps, dt);
|
let res = classify_ray(uniforms.eye.xyz, dir, uniforms.steps, dt);
|
||||||
if (res.status == 1u) {
|
if (res.status == 1u) {
|
||||||
// Captured = shadow.
|
// Captured = shadow.
|
||||||
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
// Escaped: dim grey for now (stars come in Task 11).
|
// Escaped: sample procedural stars along the bent final direction.
|
||||||
return vec4<f32>(0.02, 0.02, 0.02, 1.0);
|
let star = star_color(normalize(res.final_dir), uniforms.star_intensity);
|
||||||
|
return vec4<f32>(star, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
27
assets/shaders/stars.wgsl
Normal file
27
assets/shaders/stars.wgsl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Hash-based procedural stars on the unit sphere. Returns RGB radiance.
|
||||||
|
fn hash13(p: vec3<f32>) -> f32 {
|
||||||
|
var q = vec3<f32>(dot(p, vec3<f32>(127.1, 311.7, 74.7)),
|
||||||
|
dot(p, vec3<f32>(269.5, 183.3, 246.1)),
|
||||||
|
dot(p, vec3<f32>(113.5, 271.9, 124.6)));
|
||||||
|
let h = fract(sin(q) * 43758.5453);
|
||||||
|
return h.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn star_color(dir: vec3<f32>, intensity: f32) -> vec3<f32> {
|
||||||
|
// 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<f32>(0.6, 0.7, 1.0), vec3<f32>(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<f32>(0.0);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user