diff --git a/crates/shaders/src/lib.rs b/crates/shaders/src/lib.rs index f314f90..b775b4b 100644 --- a/crates/shaders/src/lib.rs +++ b/crates/shaders/src/lib.rs @@ -40,35 +40,97 @@ pub fn get_uv_u(pix: UVec2, tex_size: Vec4) -> spirv_std::glam::Vec2 { (pix.as_vec2() + Vec2::splat(0.5)) * tex_size.zw() } +fn ray_triangle_intersect( + ray_origin: Vec3, + ray_direction: Vec3, + v0: Vec3, + v1: Vec3, + v2: Vec3, +) -> f32 { + let epsilon = 0.000001; + let edge1 = v1 - v0; + let edge2 = v2 - v0; + let h = ray_direction.cross(edge2); + let a = edge1.dot(h); + if a > -epsilon && a < epsilon { + return -1.0; + } + let f = 1.0 / a; + let s = ray_origin - v0; + let u = f * s.dot(h); + if !(0.0..=1.0).contains(&u) { + return -1.0; + } + let q = s.cross(edge1); + let v = f * ray_direction.dot(q); + if v < 0.0 || u + v > 1.0 { + return -1.0; + } + let t = f * edge2.dot(q); + if t > epsilon { + return t; + } + -1.0 +} + +fn material_color( + frag_world_position: Vec3, + frag_normal: Vec3, + light_pos: Vec3, + object_color: Vec3, +) -> Vec3 { + let l = (light_pos - frag_world_position).normalize(); + let n = frag_normal.normalize(); + let lambertian = f32::max(n.dot(l), 0.0); + object_color * lambertian +} + #[spirv(fragment)] pub fn main_fs( frag_world_position: Vec3, frag_world_normal: Vec3, frag_tex_coord: Vec2, + + #[spirv(uniform, descriptor_set = 0, binding = 0)] ubo: &UniformBufferObject, #[spirv(descriptor_set = 0, binding = 1)] texture: &Image2d, #[spirv(descriptor_set = 0, binding = 2)] sampler: &Sampler, + #[spirv(storage_buffer, descriptor_set = 0, binding = 3)] vertices: &[Vec4], + out_color: &mut Vec4, ) { - // Convert fragment coordinate to UV coordinate - // Sample the texture - let base_color = texture.sample(*sampler, frag_tex_coord); - // let light_pos = Vec3::new(2.0, 2.0, -2.0); - // - // // Calculate light direction - // let l = (light_pos - frag_world_position).normalize(); - // let n = frag_world_normal.normalize(); - // - // // Calculate lambertian lighting - // let lambertian = f32::max(n.dot(l), 0.0); - // - // // Ambient lighting - // let ambient = Vec3::splat(0.2); - // - // // Combine texture color with model color - // let color_from_texture = Vec3::new(base_color.x, base_color.y, base_color.z); - // let combined_color = color_from_texture; - // - // // Final color calculation with gamma correction - // let color = (combined_color * lambertian + ambient).powf(2.2); - *out_color = Vec4::new(base_color.x, base_color.y, base_color.z, base_color.w); + let ray_origin = ubo.view.inverse().col(3).xyz(); + let ray_direction = (frag_world_position - ray_origin).normalize(); + + let mut closest_t = f32::MAX; + let mut closest_normal = Vec3::ZERO; + let mut hit = false; + let num_vertices = vertices.len() as u32; + for i in (0..num_vertices).step_by(3_usize) { + if i + 2 >= num_vertices { + break; + } + let v0 = vertices[i as usize].xyz(); + let v1 = vertices[(i + 1) as usize].xyz(); + let v2 = vertices[(i + 2) as usize].xyz(); + + let t = ray_triangle_intersect(ray_origin, ray_direction, v0, v1, v2); + if t > 0.0 && t < closest_t { + hit = true; + closest_t = t; + let normal = (v1 - v0).cross(v2 - v0).normalize(); + closest_normal = normal; + } + } + + let final_color = if hit { + let intersection_point = ray_origin + ray_direction * closest_t; + let light_pos = Vec3::new(2.0, 2.0, -2.0); + let object_color = Vec3::new(1.0, 0.8, 0.4); + material_color(intersection_point, closest_normal, light_pos, object_color) + } else { + let sampled = texture.sample(*sampler, frag_tex_coord); + Vec3::new(sampled.x, sampled.y, sampled.z) + }; + + *out_color = Vec4::new(final_color.x, final_color.y, final_color.z, 1.0); } diff --git a/crates/vk-rs/shaders/main_fs.spv b/crates/vk-rs/shaders/main_fs.spv index 889bbec..1655ab6 100644 Binary files a/crates/vk-rs/shaders/main_fs.spv and b/crates/vk-rs/shaders/main_fs.spv differ diff --git a/crates/vk-rs/src/renderer.rs b/crates/vk-rs/src/renderer.rs index 1ee523f..19323fe 100644 --- a/crates/vk-rs/src/renderer.rs +++ b/crates/vk-rs/src/renderer.rs @@ -502,7 +502,6 @@ fn process_node( }) }); - // Rest of the mesh creation code... let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); if let (Some(positions), Some(normals), Some(tex_coords)) = ( @@ -523,9 +522,21 @@ fn process_node( for &index in indices.iter() { let i = index as usize; + // Apply world transform to position + let position = world_transform.transform_point3(Vec3::new( + positions[i][0], + positions[i][1], + positions[i][2], + )); + let normal = world_transform.transform_vector3(Vec3::new( + normals[i][0], + normals[i][1], + normals[i][2], + )); + let vertex = Vertex { - position: Vec3::new(positions[i][0], positions[i][1], positions[i][2]), - normal: Vec3::new(normals[i][0], normals[i][1], normals[i][2]), + position, + normal, tex_coords: Vec2::new(tex_coords[i][0], tex_coords[i][1]), }; vertices.push(vertex); @@ -538,7 +549,8 @@ fn process_node( vertex_buffer, vertex_buffer_allocation: Some(vertex_buffer_allocation), vertex_count: vertices.len() as u32, - transform: world_transform, + // Store identity matrix, it is not used here anymore + transform: Mat4::IDENTITY, texture, descriptor_sets: Vec::new(), });