Files
coven/core/ray.jai
2024-10-11 22:21:32 +02:00

239 lines
6.3 KiB
Plaintext

Ray :: struct {
origin : Vector3;
direction : Vector3;
}
ray_aabb_intersection :: (origin: Vector3, direction: Vector3, aabb: AABB) -> float {
t1 := (aabb.min.x - origin.x) / direction.x;
t2 := (aabb.max.x - origin.x) / direction.x;
t3 := (aabb.min.y - origin.y) / direction.y;
t4 := (aabb.max.y - origin.y) / direction.y;
t5 := (aabb.min.z - origin.z) / direction.z;
t6 := (aabb.max.z - origin.z) / direction.z;
tmin := max(max(min(t1, t2), min(t3, t4)), min(t5, t6));
tmax := min(min(max(t1, t2), max(t3, t4)), max(t5, t6));
// if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
if tmax < 0 {
return -1;
}
// if tmin > tmax, ray doesn't intersect AABB
if tmin > tmax {
return -1;
}
if tmin < 0 {
return tmax;
}
return tmin;
}
ray_sphere_intersect :: (ray: Ray, center: Vector3, radius: float) -> bool {
t : float;
oc := ray.origin - center;
a := dot(ray.direction, ray.direction);
b := 2.0 * dot(oc, ray.direction);
c := dot(oc, oc) - radius * radius;
discriminant := b * b - 4 * a * c;
if discriminant > 0 {
// Two intersection points, choose the closest one (smallest positive t)
t1 := (-b - sqrt(discriminant)) / (2.0 * a);
t2 := (-b + sqrt(discriminant)) / (2.0 * a);
if t1 > 0 || t2 > 0 {
t = ifx (t1 < t2) then t1 else t2;
return true;
}
} else if discriminant == 0 {
// One intersection point
t = -b / (2.0 * a);
return t > 0;
}
// No intersection
return false;
}
ray_plane_intersection :: (ray: Ray, p: Vector3, n: Vector3) -> bool, float {
denom := dot(n, ray.direction);
if abs(denom) > 0.0001 {
offset := p - ray.origin;
t := dot(offset, n) / denom;
return t >= 0.0, t;
}
return false, 0.0;
}
ray_triangle_intersect :: (origin: Vector3, dir: Vector3, v0: Vector3, v1: Vector3, v2: Vector3) -> bool, float, Vector3 {
EPSILON := 0.0000001;
edge1 := v1 - v0;
edge2 := v2 - v0;
h := cross(dir, edge2);
a := dot(edge1, h);
if a > -EPSILON && a < EPSILON return false, 0.0, .{0,0,0}; // This ray is parallel to this triangle.
f := 1.0/a;
s := origin - v0;
u := f * dot(s, h);
if u < 0.0 || u > 1.0 return false, 0.0, .{0,0,0};
q := cross(s, edge1);
v := f * dot(dir, q);
if v < 0.0 || u + v > 1.0 return false, 0.0, .{0,0,0};
// At this stage we can compute t to find out where the intersection point is on the line.
t := f * dot(edge2, q);
if t > EPSILON { // ray intersection
//outIntersectionPoint = rayOrigin + rayVector * t;
normal := normalize(cross(edge1, edge2));
return true, t, normal;
}
else // This means that there is a line intersection but not a ray intersection.
return false, 0.0, .{0,0,0};
//e0 := v1 - v0;
//e1 := v2 - v0;
//pvec := cross(dir, e1);
//det := dot(pvec, e0);
//if det > 0 {
// inv_det := 1.0 / det;
// tvec := origin - v0;
// u := inv_det * dot(tvec, pvec);
// if u < 0.0 || u > 1.0 {
// return false, 0.0;
// }
// qvec := cross(tvec, e0);
// v := inv_det * dot(qvec, dir);
// if v < 0.0 || u + v > 1.0 {
// return false, 0.0;
// }
// return true, dot(e1, qvec) * inv_det;
//}
//return false, 0.0;
}
distance_from_ray_to_point :: (ray: Ray, p: Vector3) -> float {
pb := p - ray.origin;
t0 := dot(ray.direction, pb) / dot(ray.direction, ray.direction);
if t0 <= 0.0 {
return length(pb);
} else if t0 > 0.0 && t0 < 1.0 {
return length(p - (ray.origin + t0 * ray.direction));
} else {
return length(p - (ray.origin + ray.direction));
}
}
closest_point_on_ray :: (from: Vector3, dir: Vector3, p: Vector3) -> Vector3 {
lhs := p - from;
dot_p := dot(lhs, dir);
return from + dir * dot_p;
}
closest_distance_between_rays :: (l1: Ray, l2: Ray) -> distance: float, t1: float, t2: float {
u := l1.direction;
v := l2.direction;
w := l1.origin - l2.origin;
a := dot(u, u);
b := dot(u, v);
c := dot(v, v);
d := dot(u, w);
e := dot(v, w);
D := a * c - b * b;
sc: float;
tc: float;
if D < 0.00001 {
sc = 0.0;
if b > c {
tc = d / b;
} else {
tc = e / c;
}
} else {
sc = ((b * e) - (c * d)) / D;
tc = ((a * e) - (b * d)) / D;
}
P1 := u * sc;
P2 := v * tc;
dP := w + P1 - P2;
return length(dP), sc, tc;
}
get_positions :: (e : *Entity, n : Node_Render_Data, m : Mesh, i0 : u32, i1 : u32, i2 : u32) -> Vector3, Vector3, Vector3 {
p0 : Vector3;
p1 : Vector3;
p2 : Vector3;
p0 = transform_point(n.transform.world_matrix, m.positions[i0]);
p1 = transform_point(n.transform.world_matrix, m.positions[i1]);
p2 = transform_point(n.transform.world_matrix, m.positions[i2]);
return p0, p1, p2;
}
ray_entity_intersect :: (ray: Ray, e: *Entity) -> bool, float, Vector3 {
has_hit := false;
closest : float = 10000000;
closest_normal : Vector3;
for n: e.renderable.model.nodes {
render_node := e.renderable.nodes[it_index];
for handle: n.meshes {
m := parray_get(*renderer.meshes, handle);
index := 0;
if m.indices.count > 0 {
while index < m.indices.count - 1 {
i0 := m.indices[index];
i1 := m.indices[index + 1];
i2 := m.indices[index + 2];
p2, p1, p0 := get_positions(e, render_node, m, i0, i1, i2);
result, t, normal := ray_triangle_intersect(ray.origin, ray.direction, p0, p1, p2);
if result && t < closest {
has_hit = true;
closest = t;
closest_normal = normal;
}
index += 3;
}
} else {
while index < m.positions.count - 1 {
p2, p1, p0 := get_positions(e, render_node, m, xx index, xx (index + 1), xx (index + 2));
result, t, normal := ray_triangle_intersect(ray.origin, ray.direction, p0, p1, p2);
if result && t < closest {
has_hit = true;
closest = t;
closest_normal = normal;
}
index += 3;
}
}
}
}
return has_hit, closest, closest_normal;
}