Working BVH
This commit is contained in:
parent
493f311ad0
commit
7a77d1c409
@ -112,7 +112,7 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
||||
loaded_bvh, ok := assetman.bvhs[path]
|
||||
model, modtime, reloaded := get_model_ex(assetman, path, loaded_bvh.modtime)
|
||||
|
||||
should_recreate := reloaded || !ok || true
|
||||
should_recreate := reloaded || !ok
|
||||
|
||||
if ok && should_recreate {
|
||||
destroy_loaded_bvh(loaded_bvh)
|
||||
@ -124,7 +124,7 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
||||
|
||||
outer_aabb := bvh.AABB {
|
||||
min = math.F32_MAX,
|
||||
max = math.F32_MIN,
|
||||
max = -math.F32_MAX,
|
||||
}
|
||||
|
||||
for i in 0 ..< model.meshCount {
|
||||
|
@ -73,6 +73,8 @@ Game_Memory :: struct {
|
||||
es: Editor_State,
|
||||
editor: bool,
|
||||
preview_bvh: int,
|
||||
preview_node: int,
|
||||
draw_car: bool,
|
||||
}
|
||||
|
||||
Track_Edit_State :: enum {
|
||||
@ -362,11 +364,37 @@ update :: proc() {
|
||||
|
||||
dt := rl.GetFrameTime()
|
||||
|
||||
if rl.IsKeyReleased(.LEFT_BRACKET) {
|
||||
g_mem.preview_bvh -= 1
|
||||
// Debug BVH traversal
|
||||
mesh_bvh := assets.get_bvh(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
|
||||
|
||||
if rl.IsKeyDown(.LEFT_SHIFT) {
|
||||
if g_mem.preview_bvh >= 0 && g_mem.preview_bvh < len(mesh_bvh.bvhs) {
|
||||
b := mesh_bvh.bvhs[g_mem.preview_bvh]
|
||||
node := &b.nodes[g_mem.preview_node]
|
||||
|
||||
if !bvh.is_leaf_node(node^) {
|
||||
if rl.IsKeyPressed(.LEFT_BRACKET) {
|
||||
g_mem.preview_node = int(node.child_or_prim_start)
|
||||
} else if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
||||
g_mem.preview_node = int(node.child_or_prim_start + 1)
|
||||
} else if rl.IsKeyPressed(.P) {
|
||||
g_mem.preview_node = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if rl.IsKeyPressed(.LEFT_BRACKET) {
|
||||
g_mem.preview_bvh -= 1
|
||||
g_mem.preview_node = 0
|
||||
}
|
||||
if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
||||
g_mem.preview_bvh += 1
|
||||
g_mem.preview_node = 0
|
||||
}
|
||||
}
|
||||
if rl.IsKeyReleased(.RIGHT_BRACKET) {
|
||||
g_mem.preview_bvh += 1
|
||||
|
||||
if rl.IsKeyPressed(.SPACE) {
|
||||
g_mem.draw_car = !g_mem.draw_car
|
||||
}
|
||||
|
||||
if g_mem.editor {
|
||||
@ -447,12 +475,12 @@ draw :: proc() {
|
||||
for &blas, i in mesh_bvh.bvhs {
|
||||
mesh := car_model.meshes[i]
|
||||
|
||||
if i == -1 {
|
||||
if i == g_mem.preview_bvh {
|
||||
bvh.debug_draw_bvh_bounds(
|
||||
&blas,
|
||||
bvh.bvh_mesh_from_rl_mesh(mesh),
|
||||
0,
|
||||
g_mem.preview_bvh,
|
||||
g_mem.preview_node,
|
||||
)
|
||||
}
|
||||
|
||||
@ -469,7 +497,7 @@ draw :: proc() {
|
||||
}
|
||||
|
||||
if mesh_col.hit {
|
||||
rl.DrawSphereWires(ray.origin + ray.dir * mesh_col.t, 1, 8, 8, rl.RED)
|
||||
rl.DrawSphereWires(ray.origin + ray.dir * mesh_col.t, 0.1, 8, 8, rl.RED)
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,7 +507,9 @@ draw :: proc() {
|
||||
|
||||
rl.DrawModel(car_model, car_body.x - runtime_world.car_com, 1, rl.WHITE)
|
||||
} else {
|
||||
// rl.DrawModel(car_model, 0, 1, rl.WHITE)
|
||||
if g_mem.draw_car {
|
||||
rl.DrawModel(car_model, 0, 1, rl.WHITE)
|
||||
}
|
||||
}
|
||||
|
||||
physics.draw_debug_scene(&world.physics_scene)
|
||||
@ -534,11 +564,10 @@ draw :: proc() {
|
||||
|
||||
rl.DrawText(
|
||||
fmt.ctprintf(
|
||||
"mesh: %v, tri: %v, bary: %v, idx: %v",
|
||||
"mesh: %v, aabb tests: %v, tri tests: %v",
|
||||
hit_mesh_idx,
|
||||
mesh_col.prim,
|
||||
mesh_col.bary,
|
||||
g_mem.preview_bvh,
|
||||
mesh_col.aabb_tests,
|
||||
mesh_col.triangle_tests,
|
||||
),
|
||||
5,
|
||||
32,
|
||||
@ -546,6 +575,15 @@ draw :: proc() {
|
||||
rl.ORANGE,
|
||||
)
|
||||
|
||||
rl.DrawText(
|
||||
fmt.ctprintf("bvh: %v, node: %v", g_mem.preview_bvh, g_mem.preview_node),
|
||||
5,
|
||||
48,
|
||||
8,
|
||||
rl.ORANGE,
|
||||
)
|
||||
|
||||
|
||||
switch g_mem.es.track_edit_state {
|
||||
case .Select:
|
||||
case .Move:
|
||||
|
@ -144,10 +144,11 @@ update_node_bounds :: proc(bvh: ^BVH, node_idx: i32, prim_aabbs: []AABB) {
|
||||
node := &bvh.nodes[node_idx]
|
||||
|
||||
node.aabb.min = math.F32_MAX
|
||||
node.aabb.max = math.F32_MIN
|
||||
node.aabb.max = -math.F32_MAX
|
||||
|
||||
for i in node.child_or_prim_start ..< node.child_or_prim_start + node.prim_len {
|
||||
prim_aabb := prim_aabbs[bvh.primitives[i]]
|
||||
|
||||
node.aabb.min.x = min(node.aabb.min.x, prim_aabb.min.x)
|
||||
node.aabb.min.y = min(node.aabb.min.y, prim_aabb.min.y)
|
||||
node.aabb.min.z = min(node.aabb.min.z, prim_aabb.min.z)
|
||||
@ -156,11 +157,6 @@ update_node_bounds :: proc(bvh: ^BVH, node_idx: i32, prim_aabbs: []AABB) {
|
||||
node.aabb.max.y = max(node.aabb.max.y, prim_aabb.max.y)
|
||||
node.aabb.max.z = max(node.aabb.max.z, prim_aabb.max.z)
|
||||
}
|
||||
|
||||
size := node.aabb.max - node.aabb.min
|
||||
assert(size.x >= 0)
|
||||
assert(size.y >= 0)
|
||||
assert(size.z >= 0)
|
||||
}
|
||||
|
||||
subdivide :: proc(bvh: ^BVH, node_idx: i32, centroids: []Vec3, aabbs: []AABB) {
|
||||
@ -235,12 +231,15 @@ Ray :: struct {
|
||||
}
|
||||
|
||||
Collision :: struct {
|
||||
hit: bool,
|
||||
t: f32,
|
||||
hit: bool,
|
||||
t: f32,
|
||||
// which primitive we hit
|
||||
prim: u16,
|
||||
prim: u16,
|
||||
// Barycentric coords of the hit triangle
|
||||
bary: Bary,
|
||||
bary: Bary,
|
||||
// jStats
|
||||
aabb_tests: int,
|
||||
triangle_tests: int,
|
||||
}
|
||||
|
||||
traverse_bvh_ray_mesh :: proc(bvh: ^BVH, mesh: Mesh, ray: Ray, out_collision: ^Collision) -> bool {
|
||||
@ -279,8 +278,9 @@ internal_traverse_bvh_ray_triangles :: proc(
|
||||
|
||||
node := &bvh.nodes[node_idx]
|
||||
|
||||
out_collision.aabb_tests += 1
|
||||
if !internal_ray_aabb_test(ray, node.aabb, out_collision.t) {
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
rl.DrawBoundingBox(
|
||||
@ -300,26 +300,9 @@ internal_traverse_bvh_ray_triangles :: proc(
|
||||
}
|
||||
}
|
||||
|
||||
// https://tavianator.com/2022/ray_box_boundary.html
|
||||
internal_ray_aabb_test :: proc(ray: Ray, box: AABB, min_t: f32) -> bool {
|
||||
_, ok := collision.intersect_ray_aabb(ray.origin, ray.dir, collision.Aabb{box.min, box.max})
|
||||
return ok
|
||||
|
||||
// t1 := (box.min[0] - ray.origin[0]) * ray.dir_inv[0]
|
||||
// t2 := (box.max[0] - ray.origin[0]) * ray.dir_inv[0]
|
||||
|
||||
// tmin := min(t1, t2)
|
||||
// tmax := max(t1, t2)
|
||||
|
||||
// for i in 1 ..< 3 {
|
||||
// t1 = (box.min[i] - ray.origin[i]) * ray.dir_inv[i]
|
||||
// t2 = (box.max[i] - ray.origin[i]) * ray.dir_inv[i]
|
||||
|
||||
// tmin = max(tmin, min(t1, t2))
|
||||
// tmax = min(tmax, max(t1, t2))
|
||||
// }
|
||||
|
||||
// return tmax > max(tmin, 0.0)
|
||||
ts, ok := collision.intersect_ray_aabb(ray.origin, ray.dir, collision.Aabb{box.min, box.max})
|
||||
return ok && ts[0] < min_t
|
||||
}
|
||||
|
||||
// Möller–Trumbore intersection algorithm
|
||||
@ -328,6 +311,9 @@ internal_ray_tri_test :: proc(ray: Ray, mesh: Mesh, tri: u16, col: ^Collision) {
|
||||
i1, i2, i3 := mesh.indices[tri * 3], mesh.indices[tri * 3 + 1], mesh.indices[tri * 3 + 2]
|
||||
v1, v2, v3 := mesh.vertices[i1], mesh.vertices[i2], mesh.vertices[i3]
|
||||
|
||||
col.triangle_tests += 1
|
||||
rl.DrawTriangle3D(v1, v2, v3, debug_int_to_color(i32(tri) + 1))
|
||||
|
||||
t, _, barycentric, ok := collision.intersect_segment_triangle(
|
||||
{ray.origin, ray.origin + ray.dir},
|
||||
{v1, v2, v3},
|
||||
@ -339,44 +325,4 @@ internal_ray_tri_test :: proc(ray: Ray, mesh: Mesh, tri: u16, col: ^Collision) {
|
||||
col.prim = tri
|
||||
col.bary = barycentric
|
||||
}
|
||||
// rl.DrawTriangle3D(v1, v2, v3, debug_int_to_color(i32(tri)))
|
||||
|
||||
// rl_col := rl.GetRayCollisionTriangle(rl.Ray{ray.origin, ray.dir}, v1, v2, v3)
|
||||
|
||||
// if rl_col.hit && rl_col.distance < col.t {
|
||||
// col.hit = true
|
||||
// col.t = lg.distance(ray.origin, rl_col.point)
|
||||
// }
|
||||
|
||||
return
|
||||
|
||||
//e1, e2 := v2 - v1, v3 - v1
|
||||
|
||||
//h := lg.cross(ray.dir, e2)
|
||||
//a := lg.dot(e1, h)
|
||||
|
||||
//// ray parallel to triangle
|
||||
//if a > -0.0001 || a < 0.0001 {
|
||||
// return
|
||||
//}
|
||||
|
||||
//f: f32 = 1.0 / a
|
||||
//s := ray.origin - v1
|
||||
//u := f * lg.dot(s, h)
|
||||
//if u < 0 || u > 1 {
|
||||
// return
|
||||
//}
|
||||
//q := lg.cross(s, e1)
|
||||
//v := f * lg.dot(ray.dir, q)
|
||||
//if v < 0 || u + v > 1 {
|
||||
// return
|
||||
//}
|
||||
|
||||
//t := f * lg.dot(e2, q)
|
||||
//if t > 0.0001 && t < col.t {
|
||||
// col.hit = true
|
||||
// col.t = t
|
||||
// col.prim = tri
|
||||
// col.bary = Vec3{u, v, 0} // TODO: calc W
|
||||
//}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user