diff --git a/assets/trace.wgsl b/assets/trace.wgsl index f902795..92e4834 100644 --- a/assets/trace.wgsl +++ b/assets/trace.wgsl @@ -39,33 +39,99 @@ fn update(@builtin(global_invocation_id) invocation_id: vec3) { let loc = vec2(f32(invocation_id.x), f32(invocation_id.y)) / vec2(size.xy); let ndc = loc * 2.0f - 1.0f; - var ray = createCameraRay2(ndc); - var result = vec3(0.0); + var ray = createCameraRay(ndc); + // var result = vec3(0.0); - for (var i: i32 = 0; i < 1; i++){ - var hit = trace(ray); - result += ray.energy * shade(&ray, hit); - if !any(ray.energy != vec3(0.0)) - { - break; - } - } + // for (var i: i32 = 0; i < 1; i++){ + // var hit = trace(ray); + // result += ray.energy * shade(&ray, hit); + // if !any(ray.energy != vec3(0.0)) + // { + // break; + // } + // } - let clip = vec4(ndc, 0.0, 1.0); - let world = config.world_from_clip * clip; - let world_pos = world.xyz / world.w; - let dir = normalize(world_pos - config.world_position); + let hit_data = trace_test(ray); - let color = vec4((ray.direction * 0.1), 1.0); - // let color = vec4(ray.direction, 1.0); - // let color = vec4((ray.direction * 0.1) + vec3(0.5), 1.0); - // let color = vec4(result, 1.0); + var final_color = hit_data.color; + + // Simple fog/distance visualization + let distance_factor = clamp(hit_data.distance / 50.0, 0.0, 1.0); + final_color = mix(final_color * (f32(hit_data.steps)/ 100.0), vec3(0.1), distance_factor); // Fog: mix object color with dark gray + + let color = vec4(final_color, 1.0); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); textureStore(output, location, color); } +fn debug_matrix(uv: vec2) -> vec4{ + let ndc = uv * 2.0f - 1.0f; + var color = vec3(0.0, 0.0, 0.0); + + if uv.y < 0.5 { + if uv.x < 0.5 { + color = debugColor(config.world_from_clip[0][3] * 10); + }else{ + color = debugColor(config.world_from_clip[1][3] * 10); + } + }else{ + if uv.x < 0.5 { + color = debugColor(config.world_from_clip[3][2] * 10); + }else{ + color = debugColor(config.world_from_clip[3][3] * 10); + } + } + + + return vec4(color, 1.0); +} +fn debug(uv: vec2) -> vec4{ + let ndc = uv * 2.0f - 1.0f; + + let near_clip = vec4(ndc, 0.0, 1.0); + let far_clip = vec4(ndc, 1.0, 1.0); + + // project into world space + let near_world4 = config.world_from_clip * near_clip; + let far_world4 = config.world_from_clip * far_clip; + + //Add epsilon to protect from divide by zero + let inv_w_near = 1.0 / (near_world4.w + 1e-6); + let inv_w_far = 1.0 / (far_world4.w + 1e-6); + + let near_world = near_world4.xyz * inv_w_near; + let far_world = far_world4.xyz * inv_w_far; + + let origin = config.world_position; + + let direction = normalize(near_world - origin); + + var ray = createRay(origin, direction); + var color = vec3(0.0, 0.0, 0.0); + if uv.y < 0.5 { + if uv.x < 0.5 { + color = debugColor(ray.direction.x); + }else{ + color = debugColor(ray.direction.y); + } + }else{ + if uv.x < 0.5 { + color = debugColor(ray.direction.z); + }else{ + // color = debugColor(ray.direction.z); + color = debugColor(origin.x * 0.1); + } + } + + return vec4(color, 1.0); +} + +fn debugColor(v: f32) -> vec3{ + return vec3(v * 0.5 + 0.5); +} + struct Ray { origin: vec3, direction: vec3, @@ -81,14 +147,6 @@ struct RayHit { specular: vec3 } -struct Sphere -{ - position: vec3, - radius: f32, - albedo: vec3, - specular: vec3 -} - fn createRayHit() -> RayHit { var hit: RayHit; hit.position = vec3(0.0, 0.0, 0.0); @@ -109,121 +167,73 @@ fn createRay(origin: vec3, direction: vec3) -> Ray } fn createCameraRay(ndc: vec2) -> Ray { + let uv = vec2(ndc.x, -ndc.y); - let target_point = config.world_from_clip * vec4(ndc, 0.0, 1.0); - let direction_point = target_point.xyz / target_point.w; - let direction = normalize(direction_point - config.world_position); - - return createRay(config.world_position, direction); -} - -fn createCameraRay2(ndc: vec2) -> Ray { // clip points at near and far - let near_clip = vec4(ndc, 0.0, 1.0); - let far_clip = vec4(ndc, 1.0, 1.0); + let near_clip = vec4(uv, 0.0, 1.0); + let far_clip = vec4(uv, 1.0, 1.0); // project into world space let near_world4 = config.world_from_clip * near_clip; let far_world4 = config.world_from_clip * far_clip; - let near_world = near_world4.xyz / near_world4.w; - let far_world = far_world4.xyz / far_world4.w; + //Add epsilon to protect from divide by zero + let inv_w_near = 1.0 / (near_world4.w + 1e-6); + let inv_w_far = 1.0 / (far_world4.w + 1e-6); - // ray starts at near plane, points toward far plane - let origin = near_world + config.world_position; - let direction = normalize(origin - near_world); + let near_world = near_world4.xyz * inv_w_near; + let far_world = far_world4.xyz * inv_w_far; + + let origin = config.world_position; + + let direction = normalize(near_world - origin); return createRay(origin, direction); } -fn createSphere(position: vec3, radius: f32) -> Sphere -{ - var s: Sphere; - s.position = position; - s.radius = radius; - s.albedo = vec3(0.8f, 0.8f, 0.8f); - s.specular = vec3(0.6f, 0.6f, 0.6f); - return s; +struct Hit { + distance: f32, + hit_pos: vec3, + normal: vec3, + color: vec3, + steps: i32, +}; + +fn distance_field(p: vec3) -> f32 { + // Simple sphere centered at (0, 0, 0) with radius 1.0 + let sphere_center = vec3(0.0, 0.0, 0.0); + let sphere_radius = 1.0; + + // SDF for a sphere: length(p - center) - radius + let d = length(p - sphere_center) - sphere_radius; + return d; } -fn intersectSphere(ray: Ray, bestHit: ptr, sphereIndex: u32) -{ - //Sphere sphere = _Spheres[sphereIndex]; - var sphere = createSphere(vec3(0.0f, 2.0f, 0.0f), 2.0f); +fn trace_test(ray: Ray) -> Hit { + var total_distance: f32 = 0.0; + let max_distance: f32 = 100.0; + let min_hit_distance: f32 = 0.001; + const max_steps: i32 = 100; + for (var i: i32 = 0; i < max_steps; i = i + 1) { + let current_pos = ray.origin + ray.direction * total_distance; + let distance_to_scene = distance_field(current_pos); - var d = ray.origin - sphere.position; - var p1 = -dot(ray.direction, d); - var p2sqr = p1 * p1 - dot(d, d) + sphere.radius * sphere.radius; - if p2sqr < 0 { - return; - } - var p2 = sqrt(p2sqr); - // var t = p1 - p2 > 0 ? p1 - p2 : p1 + p2; - var t = 0f; - if p1 - p2 > 0 { - t = p1 - p2; - } else { - t = p1 + p2; - } - if t > 0 && t < (*bestHit).distance - { - (*bestHit).position = ray.origin + t * ray.direction; - (*bestHit).normal = normalize((*bestHit).position - sphere.position); - (*bestHit).albedo = sphere.albedo; - (*bestHit).specular = sphere.specular; - (*bestHit).distance = t; - } -} - -fn intersectGroundPlane(ray: Ray, bestHit: ptr) -{ - var t = -ray.origin.y / ray.direction.y; - if t > 0 && t < (*bestHit).distance - { - (*bestHit).distance = t; - (*bestHit).position = ray.origin + t * ray.direction; - (*bestHit).normal = vec3(0.0f, 1.0f, 0.0f); - (*bestHit).albedo = vec3(0.1f); - (*bestHit).specular = vec3(0.3f); - } -} - -fn trace(ray: Ray) -> RayHit -{ - var bestHit = createRayHit(); - intersectSphere(ray, &bestHit, 0); - intersectGroundPlane(ray, &bestHit); - return bestHit; -} - - -fn shade(ray: ptr, hit: RayHit) -> vec3 -{ - if hit.distance > -999999999.0f - { - (*ray).origin = hit.position + hit.normal * 0.001f; - (*ray).direction = reflect((*ray).direction, hit.normal); - (*ray).energy *= hit.specular; - - //Shadows - // var shadow = false; - // var shadowRay = createRay(hit.position + hit.normal * 0.001f, -1 * _DirectionalLight.xyz); - // var shadowHit = trace(shadowRay); - // if (shadowHit.distance != 9999999.0f) - // { - // return float3(0.0f, 0.0f, 0.0f); - // } - - // return saturate(dot(hit.normal, _DirectionalLight.xyz) * -1) * _DirectionalLight.w * hit.albedo; - return hit.albedo; - } - else - { - (*ray).energy = vec3(0.0f); - return config.sky_color.xyz; - // var theta = acos((*ray).direction.y) / -PI; - // var phi = atan2((*ray).direction.x, -(*ray).direction.z) / -PI * .5f; - // return _SkyboxTexture.SampleLevel(sampler_SkyboxTexture, float2(phi, theta), 0).xyz; - } + // Check for a hit + if (distance_to_scene < min_hit_distance) { + // A hit occurred! + return Hit(total_distance, current_pos, vec3(0.0), vec3(1.0, 0.0, 0.0), i); // Return red color for now + } + + // Check if we marched too far + if (total_distance > max_distance) { + break; + } + + // Advance the ray + total_distance = total_distance + distance_to_scene; + } + + // No hit found + return Hit(max_distance, vec3(0.0), vec3(0.0), vec3(0.0, 0.0, 0.0), 0); // Return black for background } diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs index a95bb31..1ccaf30 100644 --- a/src/render/pipeline.rs +++ b/src/render/pipeline.rs @@ -177,9 +177,14 @@ fn update_tracer_uniforms( rt_camera: Single<(&GlobalTransform, &Camera), With>, ) { let (transform, cam) = rt_camera.into_inner(); + /* + + let clip_from_view = cam.clip_from_view(); + let world_from_clip = clip_from_view.inverse() * transform.compute_matrix().inverse(); + */ let clip_from_view = cam.clip_from_view(); - let world_from_clip = clip_from_view.inverse() * transform.compute_matrix().inverse(); + let world_from_clip = transform.compute_matrix() * clip_from_view.inverse(); // cam.ndc_to_world(camera_transform, ndc) tracer_uniforms.world_from_clip = world_from_clip;