So i am aware there is already a lot of info on this topic but i am having trouble putting the theory into actual code.
I am making a raymarcher to march into an octree and get the color of the voxel the ray hits. But i am having trouble getting the direction of the ray. I saw this but i dont understand how the code works. im working with bevy on the cpu side, so using wgsl in gpu land.
this is my direction code now but it does not take into account where the camera is facing
fn ray_dir(x: f32, y: f32) -> vec3<f32> {
let d = 1/tan(radians(screen.fov/2));
let px = x + 0.5;
let py = y + 0.5;
let aspect_ratio = f32(screen.width) / f32(screen.height);
let ray_dir_x = aspect_ratio * (2 * px / f32(screen.width)) - 1;
let ray_dir_y = (2 * py/f32(screen.height)) - 1;
let ray_dir_z = d;
return vec3<f32>(ray_dir_x, ray_dir_y, ray_dir_z);
}
this makes the screen either full background or full voxel(all voxels are the same colour as of now)
so my Question is how do i get the direction of the ray for each pixel in wgsl?
--edit--
i have used the same code in bevy to debug where the rays go:
for x in 0..shader_screen.width / 100 {
for y in 0..shader_screen.height / 100 {
let y = y * 100;
let x = x * 100;
let ray_dir = ray_dir(x as f32, y as f32, shader_screen.clone());
gizmos.ray(
Vec3 {
x: 0.0,
y: 0.0,
z: 0.0,
},
ray_dir,
Color::RED,
);
}
}
fn ray_dir(x: f32, y: f32, screen: ShaderScreen) -> Vec3 {
let d = 1.0 / ((screen.fov / 2.0).to_radians()).tan();
let px = x + 0.5;
let py = y + 0.5;
let aspect_ratio = screen.width as f32 / screen.height as f32;
let dir_x = aspect_ratio * (2.0 * px / screen.width as f32) - 1.0;
let dir_y = (2.0 * py / screen.height as f32) - 1.0;
let dir_z = d;
let mut vector = Vec3 {
x: dir_x.abs(),
y: dir_y.abs(),
z: dir_z as f32,
};
vector = vector.normalize();
vector = Vec3 {
x: vector.x * 15.0,
y: vector.y * 15.0,
z: vector.z * 15.0,
};
return vector;
}
and this would look like this: https://imgur.com/Gulniva all seem to go in the same spot on the bottom left. But there is also a dot/line seen more towards the middle of the camera. i think that is because there are 2 cameras in the scene
--edit2--
i changed 1.0 / ((screen.fov / 2.0).to_radians()).tan();
to 1.0 / ((screen.fov / 2.0).tan();
this gave me this result: https://imgur.com/a/Hb06kim
--edit3--
in bevy i can use this
fn ray_dir_v3(x: f32, y: f32, camera: (&GlobalTransform, &Transform, &Camera)) -> Vec3 {
let ndc_x = (x + 0.5) / RESWIDTH as f32;
let ndc_y = (y + 0.5) / RESHIGHT as f32;
let world_pos = camera
.2
.ndc_to_world(camera.0, Vec3::new(ndc_x, ndc_y, 0.1))
.unwrap();
let mut dir = (world_pos - camera.0.translation()).normalize();
dir = Vec3::new(dir.x * 50.0, dir.y * 50.0, dir.z * 50.0);
dir
}
to get this result https://imgur.com/a/I3sppl8
and then i use this
fn rotate_at_z(vector: vec3<f32>, a: f32) -> vec3<f32> {
let x = vector.x * cos(a) - vector.y * sin(a);
let y = vector.x * sin(a) + vector.y * cos(a);
let z = vector.z;
return vec3<f32>(x, y, z);
}
fn rotate_at_y(vector: vec3<f32>, b: f32) -> vec3<f32> {
let x = vector.z * sin(b) + vector.x * cos(b);
let y = vector.y;
let z = vector.z * cos(b) - vector.x * sin(b);
return vec3<f32>(x, y, z);
}
fn rotate_at_x(vector: vec3<f32>, c: f32) -> vec3<f32> {
let x = vector.x;
let y = vector.y * cos(c) - vector.z * sin(c);
let z = vector.y * sin(c) + vector.z * cos(c);
return vec3<f32>(x, y, z);
}
to rotate every ray in the direction of the camera.forward()
this makes the entirety move with the camera. this has solved the ray direction problem, however because nothing is every easy, there still remains some problem with the raymarching that makes it not detect voxels untill the camera is inside the voxel volume