use std::f32::consts::PI;
use embree4_rs::{
geometry::{UserGeometry, UserGeometryImpl},
Device, Scene,
};
use anyhow::Result;
use embree4_sys::RTCRay;
use glam::{vec3, Vec3};
fn main() -> Result<()> {
let config = Some("verbose=1");
let device = Device::try_new(config)?;
let scene = Scene::try_new(device, Default::default())?;
let sphere = Sphere {
center: vec3(0.0, 0.0, 5.0),
radius: 1.0,
};
let geom = UserGeometry::try_new(&scene.device, &sphere)?;
scene.attach_geometry(&geom)?;
let scene = scene.commit()?;
let width = 4096;
let height = 4096;
let cam_dist = sphere.center.z;
let rays = width * height;
let mut hits = 0;
let t0 = std::time::Instant::now();
for x in 0..width {
for y in 0..height {
let u = (x as f32 + 0.5) / width as f32;
let v = (y as f32 + 0.5) / height as f32;
let target = vec3(u * 2.0 - 1.0, v * 2.0 - 1.0, 5.0);
let direction = cam_dist * Vec3::Z;
let origin = target - direction;
let ray = RTCRay {
org_x: origin.x,
org_y: origin.y,
org_z: origin.z,
dir_x: direction.x,
dir_y: direction.y,
dir_z: direction.z,
..Default::default()
};
let hit = scene.intersect_1(ray, None)?;
if hit.is_some() {
hits += 1
}
}
}
let elapsed = t0.elapsed();
let hit_fraction = hits as f32 / rays as f32;
println!("hit_fraction: {}", hit_fraction);
let approx_pi = hit_fraction * 4.0;
println!(" approx_pi: {}", approx_pi);
let err = (approx_pi - PI).abs();
let err_percent = err / PI * 100.0;
println!(" err: {} ({:.5}%)", err, err_percent);
let rays_per_sec = (rays as f32 / elapsed.as_secs_f32()) as usize;
println!("rays_per_sec: {}", rays_per_sec);
Ok(())
}
struct Sphere {
center: Vec3,
radius: f32,
}
impl UserGeometryImpl for Sphere {
fn bounds(&self) -> embree4_sys::RTCBounds {
embree4_sys::RTCBounds {
lower_x: self.center.x - self.radius,
lower_y: self.center.y - self.radius,
lower_z: self.center.z - self.radius,
align0: Default::default(),
upper_x: self.center.x + self.radius,
upper_y: self.center.y + self.radius,
upper_z: self.center.z + self.radius,
align1: Default::default(),
}
}
fn intersect(
&self,
geom_id: u32,
prim_id: u32,
ctx: &embree4_sys::RTCRayQueryContext,
ray_hit: &mut embree4_sys::RTCRayHit,
) {
let o = vec3(ray_hit.ray.org_x, ray_hit.ray.org_y, ray_hit.ray.org_z);
let d = vec3(ray_hit.ray.dir_x, ray_hit.ray.dir_y, ray_hit.ray.dir_z);
let oc = o - self.center;
let a = d.dot(d);
let b = 2.0 * oc.dot(d);
let c = oc.dot(oc) - self.radius * self.radius;
let discriminant = b * b - 4.0 * a * c;
if discriminant < 0.0 {
return;
}
let t1 = (-b - discriminant.sqrt()) / (2.0 * a);
let t2 = (-b + discriminant.sqrt()) / (2.0 * a);
let t = t1.min(t2);
ray_hit.ray.tfar = t;
let n = (o + t * d - self.center).normalize();
ray_hit.hit.Ng_x = n.x;
ray_hit.hit.Ng_y = n.y;
ray_hit.hit.Ng_z = n.z;
let p = o + t * d;
let phi = p.z.atan2(p.x);
let theta = p.y.asin();
let u = 1.0 - (phi + PI) / (2.0 * PI);
ray_hit.hit.u = u;
let v = (theta + PI / 2.0) / PI;
ray_hit.hit.v = v;
ray_hit.hit.instID = ctx.instID;
ray_hit.hit.geomID = geom_id;
ray_hit.hit.primID = prim_id;
}
}