aurora-rendering-engine/shaders/include/bvh.glsl

191 lines
5.1 KiB
GLSL

// BVH traversal and ray-triangle intersection
#ifndef BVH_GLSL
#define BVH_GLSL
// Ray-AABB intersection
bool intersect_aabb(Ray ray, vec3 aabb_min, vec3 aabb_max, float t_max) {
vec3 inv_d = 1.0 / ray.direction;
vec3 t0 = (aabb_min - ray.origin) * inv_d;
vec3 t1 = (aabb_max - ray.origin) * inv_d;
vec3 tmin3 = min(t0, t1);
vec3 tmax3 = max(t0, t1);
float tmin = max(max(tmin3.x, tmin3.y), tmin3.z);
float tmax2 = min(min(tmax3.x, tmax3.y), tmax3.z);
return (tmax2 >= max(tmin, 0.0)) && (tmin <= t_max);
}
// Moller-Trumbore triangle intersection
bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) {
vec3 v0 = tri.v0_material.xyz;
vec3 v1 = tri.v1.xyz;
vec3 v2 = tri.v2.xyz;
vec3 e1 = v1 - v0;
vec3 e2 = v2 - v0;
vec3 pvec = cross(ray.direction, e2);
float det = dot(e1, pvec);
if (abs(det) < EPSILON) return false;
float inv_det = 1.0 / det;
vec3 tvec = ray.origin - v0;
float u = dot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0) return false;
vec3 qvec = cross(tvec, e1);
float v = dot(ray.direction, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0) return false;
float t = dot(e2, qvec) * inv_det;
if (t < EPSILON || t >= hit.t) return false;
float w = 1.0 - u - v;
vec3 n0 = tri.n0.xyz;
vec3 n1 = tri.n1.xyz;
vec3 n2 = tri.n2.xyz;
vec2 uv0 = tri.uv0_uv1.xy;
vec2 uv1 = tri.uv0_uv1.zw;
vec2 uv2 = tri.uv2.xy;
vec3 t0 = tri.t0.xyz;
vec3 t1 = tri.t1.xyz;
vec3 t2 = normalize(cross(n0, t0));
hit.hit = true;
hit.t = t;
hit.position = ray.origin + t * ray.direction;
hit.normal = normalize(n0 * w + n1 * u + n2 * v);
hit.texcoord = uv0 * w + uv1 * u + uv2 * v;
hit.tangent = normalize(t0 * w + t1 * u + t2 * v);
hit.material_id = as_uint(tri.v0_material.w);
return true;
}
// BVH traversal (closest hit)
HitInfo trace_ray_bvh(Ray ray) {
HitInfo hit;
hit.hit = false;
hit.t = MAX_FLOAT;
if (!u_use_bvh || u_bvh_node_count == 0u) {
return hit;
}
uint stack[64];
int sp = 0;
stack[sp++] = 0u;
while (sp > 0) {
uint node_idx = stack[--sp];
if (node_idx >= u_bvh_node_count) continue;
BVHNodeGpu node = bvh_nodes[node_idx];
vec3 bmin = node.aabb_min_left_first.xyz;
vec3 bmax = node.aabb_max_count.xyz;
uint left_first = as_uint(node.aabb_min_left_first.w);
uint count = as_uint(node.aabb_max_count.w);
if (!intersect_aabb(ray, bmin, bmax, hit.t)) continue;
if (count > 0u) {
for (uint i = 0u; i < count; ++i) {
TriangleGpu tri = bvh_tris[left_first + i];
intersect_triangle(ray, tri, hit);
}
} else {
uint left = left_first;
uint right = left_first + 1u;
if (sp < 63) stack[sp++] = right;
if (sp < 63) stack[sp++] = left;
}
}
return hit;
}
// Any-hit BVH for shadow ray
bool trace_any_bvh(Ray ray, float t_max) {
if (!u_use_bvh || u_bvh_node_count == 0u) return false;
uint stack[64];
int sp = 0;
stack[sp++] = 0u;
HitInfo hit;
hit.hit = false;
hit.t = t_max;
while (sp > 0) {
uint node_idx = stack[--sp];
if (node_idx >= u_bvh_node_count) continue;
BVHNodeGpu node = bvh_nodes[node_idx];
vec3 bmin = node.aabb_min_left_first.xyz;
vec3 bmax = node.aabb_max_count.xyz;
uint left_first = as_uint(node.aabb_min_left_first.w);
uint count = as_uint(node.aabb_max_count.w);
if (!intersect_aabb(ray, bmin, bmax, hit.t)) continue;
if (count > 0u) {
for (uint i = 0u; i < count; ++i) {
TriangleGpu tri = bvh_tris[left_first + i];
if (intersect_triangle(ray, tri, hit)) return true;
}
} else {
uint left = left_first;
uint right = left_first + 1u;
if (sp < 63) stack[sp++] = right;
if (sp < 63) stack[sp++] = left;
}
}
return false;
}
// Read primary hit from G-Buffer
HitInfo trace_primary_gbuffer(Ray ray, ivec2 pixel_coords) {
HitInfo hit;
hit.hit = false;
hit.t = MAX_FLOAT;
hit.position = vec3(0.0);
hit.normal = vec3(0.0, 1.0, 0.0);
hit.texcoord = vec2(0.0);
hit.tangent = vec3(0.0);
hit.material_id = 0u;
hit.material_type = 0;
vec4 pos = imageLoad(g_position, pixel_coords);
if (pos.w <= 0.5) {
return hit;
}
vec3 p = pos.xyz;
vec3 n = normalize(imageLoad(g_normal, pixel_coords).xyz);
uint mid = imageLoad(g_material_id, pixel_coords).r;
vec4 mat = imageLoad(g_material, pixel_coords);
int mtype = int(mat.w);
vec4 texcoord_tangent = imageLoad(g_texcoord, pixel_coords);
vec2 texcoord = texcoord_tangent.xy;
vec4 tangent_data = imageLoad(g_tangent, pixel_coords);
vec3 tangent = tangent_data.xyz;
hit.hit = true;
hit.position = p;
hit.normal = n;
hit.texcoord = texcoord;
hit.tangent = tangent;
hit.material_id = mid;
hit.material_type = mtype;
hit.t = length(p - ray.origin);
return hit;
}
#endif // BVH_GLSL