Skip to content

Commit

Permalink
Almost setup ray marching? :)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgayfer committed Jul 31, 2024
1 parent 3353913 commit b710d85
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 19 deletions.
111 changes: 92 additions & 19 deletions src/render/lighting/lighting.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,28 @@ struct AmbientLight2d {
color: vec4<f32>
}

fn world_to_ndc(world_position: vec2<f32>, view_projection: mat4x4<f32>) -> vec2<f32> {
return (view_projection * vec4<f32>(world_position, 0.0, 1.0)).xy;
fn world_to_ndc(world_position: vec2<f32>) -> vec2<f32> {
return (view.clip_from_world * vec4(world_position, 0.0, 1.0)).xy;
}

fn ndc_to_world(ndc_position: vec2<f32>) -> vec2<f32> {
return (view.world_from_clip * vec4(ndc_position, 0.0, 1.0)).xy;
}

fn ndc_to_uv(ndc: vec2<f32>) -> vec2<f32> {
return ndc * vec2(0.5, -0.5) + vec2(0.5);
}

fn frag_coord_to_uv(frag_coord: vec2<f32>) -> vec2<f32> {
return (frag_coord - view.viewport.xy) / view.viewport.zw;
}

fn frag_coord_to_ndc(frag_coord: vec2<f32>) -> vec2<f32> {
return uv_to_ndc(frag_coord_to_uv(frag_coord.xy));
}

fn uv_to_ndc(uv: vec2<f32>) -> vec2<f32> {
return uv * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
}

fn ndc_to_screen(ndc: vec2<f32>, screen_size: vec2<f32>) -> vec2<f32> {
Expand All @@ -29,10 +49,9 @@ fn ndc_to_screen(ndc: vec2<f32>, screen_size: vec2<f32>) -> vec2<f32> {

fn world_to_screen(
world_position: vec2<f32>,
screen_size: vec2<f32>,
view_projection: mat4x4<f32>
screen_size: vec2<f32>
) -> vec2<f32> {
return ndc_to_screen(world_to_ndc(world_position, view_projection), screen_size);
return ndc_to_screen(world_to_ndc(world_position), screen_size);
}

fn scale_factor(view: View) -> f32 {
Expand Down Expand Up @@ -63,8 +82,18 @@ var<uniform> ambient_light: AmbientLight2d;
var<uniform> point_lights: array<PointLight2d, MAX_POINT_LIGHTS>;
#endif

@group(0) @binding(5)
var sdf_texture: texture_2d<f32>;

@fragment
fn fragment(vo: FullscreenVertexOutput) -> @location(0) vec4<f32> {
let current_position = ndc_to_world(frag_coord_to_ndc(vo.position.xy));

// Use the ambient texture if we're inside an occluder.
if (signed_distance(current_position) <= 0.0) {
return ambient_texture(vo);
}

// Setup aggregate color from light sources to multiply the main texture by.
var light_color = vec3(1.0);

Expand All @@ -84,8 +113,7 @@ fn fragment(vo: FullscreenVertexOutput) -> @location(0) vec4<f32> {
// Our point light position is still in world space. We need to convert
// it to screen space in order to do things like compute distances (let
// alone render it in the correct place).
let point_light_screen_center =
world_to_screen(point_light.center, view.viewport.zw, view.clip_from_world);
let point_light_screen_center = world_to_screen(point_light.center, view.viewport.zw);

// Compute the distance between the current position and the light's center.
// We multiply by the scale factor as otherwise our distance will always be
Expand All @@ -97,22 +125,29 @@ fn fragment(vo: FullscreenVertexOutput) -> @location(0) vec4<f32> {
// of illumination.
if distance < point_light.radius {

// Compute light color falloff (a value between 0.0 and 1.0).
let attenuation = attenuation(
distance,
point_light.radius,
point_light.intensity,
point_light.falloff
);

// Add in the color from the light, taking into account its attenuation.
light_color += point_light.color.rgb * attenuation;
// Check if the point light is occluded from the current position.
if (raymarch(current_position, point_light.center) > 0.0) {

// Compute light color falloff (a value between 0.0 and 1.0).
let attenuation = attenuation(
distance,
point_light.radius,
point_light.intensity,
point_light.falloff
);

// Add in the color from the light, taking into account its attenuation.
light_color += point_light.color.rgb * attenuation;
}
}
}

return ambient_texture(vo) * vec4(light_color, 1.0);
}

fn ambient_texture(vo: FullscreenVertexOutput) -> vec4<f32> {
return textureSample(screen_texture, texture_sampler, vo.uv)
* vec4(ambient_light.color.rgb, 1.0)
* vec4(light_color, 1.0);
* vec4(ambient_light.color.rgb, 1.0);
}

fn square(x: f32) -> f32 {
Expand All @@ -129,3 +164,41 @@ fn attenuation(distance: f32, radius: f32, intensity: f32, falloff: f32) -> f32
let s2 = square(s);
return intensity * square(1 - s2) / (1 + falloff * s2);
}

fn signed_distance(pos: vec2<f32>) -> f32 {
let uv = ndc_to_uv(world_to_ndc(pos));
let dist = textureSample(sdf_texture, texture_sampler, uv).r;
return dist;
}

fn distance_squared(a: vec2<f32>, b: vec2<f32>) -> f32 {
let c = a - b;
return dot(c, c);
}

fn raymarch(ray_origin: vec2<f32>, ray_target: vec2<f32>) -> f32 {
let ray_direction = normalize(ray_target - ray_origin);
let stop_at = distance_squared(ray_origin, ray_target);

var ray_progress: f32 = 0.0;
var pos = vec2<f32>(0.0);

for (var i = 0; i < 32; i++) {
pos = ray_origin + ray_progress * ray_direction;

if (ray_progress * ray_progress >= stop_at) {
// ray found target
return 1.0;
}

let dist = signed_distance(pos);

if dist <= 0.0 {
break;
}

ray_progress += dist;
}

return 0.0;
}
1 change: 1 addition & 0 deletions src/render/lighting/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ impl ViewNode for LightingNode {
view_uniform_binding,
ambient_light_uniform,
point_light_binding,
&aux_textures.sdf.default_view.clone(),
)),
);

Expand Down
1 change: 1 addition & 0 deletions src/render/lighting/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ impl FromWorld for LightingPipeline {
uniform_buffer::<ViewUniform>(true),
uniform_buffer::<ExtractedAmbientLight2d>(true),
GpuArrayBuffer::<ExtractedPointLight2d>::binding_layout(render_device),
texture_2d(TextureSampleType::Float { filterable: true }),
),
),
);
Expand Down

0 comments on commit b710d85

Please sign in to comment.