Skip to content

Commit

Permalink
Merge pull request #4 from Jack-Grogan/main
Browse files Browse the repository at this point in the history
Implementation of raytracing in ImplicitBHV.jl
  • Loading branch information
anicusan authored Nov 4, 2024
2 parents 56d9d23 + bbcce31 commit c74b026
Show file tree
Hide file tree
Showing 18 changed files with 1,306 additions and 415 deletions.
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ detection downwards from this level.

## Examples

### Multithreaded Contact Detection

Simple usage with bounding spheres and default 64-bit types:

```julia
Expand Down Expand Up @@ -130,7 +132,7 @@ traversal = traverse(
Check out the `benchmark` folder for an example traversing an STL model.


# GPU Bounding Volume Hierarchy Building and Traversal
### GPU-Accelerated Contact Detection

Simply use a GPU array for the bounding volumes; the interface remains the same, and all operations - Morton encoding, sorting, BVH building and traversal for contact finding - will run on the right backend:

Expand Down Expand Up @@ -158,6 +160,51 @@ traversal = traverse(bvh)
```


### Multithreaded Ray Tracing

Using `BSphere{Float32}` for leaves, `BBox{Float32}` for merged nodes above, and `UInt32` Morton codes:

```julia
using ImplicitBVH
using ImplicitBVH: BBox, BSphere

# Load mesh and compute bounding spheres for each triangle. Can download mesh from:
# https://github.com/alecjacobson/common-3d-test-models/blob/master/data/xyzrgb_dragon.obj
using MeshIO
using FileIO

mesh = load("xyzrgb_dragon.obj")

# Generate bounding spheres around each triangle in the mesh
bounding_spheres = [BSphere{Float32}(tri) for tri in mesh]

# Build BVH
bvh = BVH(bounding_spheres, BBox{Float32}, UInt32)

# Generate some rays
points = rand(Float32, 3, 1000)
directions = rand(Float32, 3, 1000)

# Traverse BVH to get indices of rays intersecting the bounding spheres
traversal = traverse_rays(bvh, points, directions)
@show traversal.contacts

# output
traversal.contacts = Tuple{Int32, Int32}[...]
```

The bounding spheres around each triangle can be computed in parallel (including on GPUs) using [AcceleratedKernels.jl](https://github.com/anicusan/AcceleratedKernels.jl):

```julia
import AcceleratedKernels as AK

bounding_spheres = Vector{BSphere{Float32}}(undef, length(mesh))
AK.map!(BSphere{Float32}, bounding_spheres, mesh)
```

For GPUs simply swap `Vector` with `ROCVector`, `MtlVector`, `oneVector` or `CuVector`, and AcceleratedKernels will automatically run the code on the right GPU backend (from `AMDGPU`, `Metal`, `oneAPI`, `CUDA`).


# Implicit Bounding Volume Hierarchy

The main idea behind the ImplicitBVH is the use of an implicit perfect binary tree constructed from some
Expand Down
76 changes: 76 additions & 0 deletions benchmark/bvh_rays.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# File : bvh_build.jl
# License: MIT
# Author : Andrei Leonard Nicusan <[email protected]>
# Date : 15.12.2022


using ImplicitBVH
using ImplicitBVH: BSphere, BBox

using Random
Random.seed!(42)

using MeshIO
using FileIO

using BenchmarkTools
using Profile
using PProf


# Types used
const LeafType = BBox{Float32}



num_bvs = 1_000_000

bvs = [LeafType(rand(3, 3)) for _ in 1:num_bvs]
points = rand(Float32, 3, num_bvs)
directions = rand(Float32, 3, num_bvs)


# Example usage
function check_intersections!(intersections, bvs, points, directions)
@inbounds for i in eachindex(intersections)
intersections[i] = isintersection(bvs[i], @view(points[:, i]), @view(directions[:, i]))
end
nothing
end

intersections = Vector{Bool}(undef, length(bvs))
check_intersections!(intersections, bvs, points, directions)


println("Benchmarking $(length(bvs)) intersections:")
display(@benchmark check_intersections!(intersections, bvs, points, directions))


# # Collect a pprof profile of the complete build
# Profile.clear()
# @profile begin
# for _ in 1:1000
# check_intersections!(intersections, bvs, points, directions)
# end
# end
#
#
# # Export pprof profile and open interactive profiling web interface.
# pprof(; out="bvh_rays.pb.gz")


# Test for some coding mistakes
using Test
Test.detect_unbound_args(ImplicitBVH, recursive = true)
Test.detect_ambiguities(ImplicitBVH, recursive = true)


# More complete report on type stabilities
using JET
JET.@report_opt check_intersections!(intersections, bvs, points, directions)


# using Profile
# BVH(bounding_spheres, NodeType, MortonType)
# Profile.clear_malloc_data()
# BVH(bounding_spheres, NodeType, MortonType)
1 change: 1 addition & 0 deletions docs/src/bounding_volumes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ImplicitBVH.BSphere

```@docs
ImplicitBVH.iscontact
ImplicitBVH.isintersection
ImplicitBVH.center
```

Expand Down
1 change: 1 addition & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```@docs
BVH
traverse
traverse_rays
BVHTraversal
default_start_level
ImplicitBVH.IndexPair
Expand Down
1 change: 0 additions & 1 deletion prototype/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ AtomixMetal = "fc0d88fc-5db5-40d7-bf35-da84fd759def"
Cthulhu = "f68482b8-f384-11e8-15f7-abe071a5a75f"
ImplicitBVH = "932a18dc-bb55-4cd5-bdd6-1368ec9cea29"
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
Metal = "dde4c033-4e86-420c-a63e-0dd931031962"
PProf = "e4faabce-9ead-11e9-39d9-4379958e3056"
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Expand Down
46 changes: 46 additions & 0 deletions prototype/raytracing.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

using Random

using BenchmarkTools

using ImplicitBVH
using ImplicitBVH: BSphere, BBox

using Profile
using PProf


Random.seed!(0)

num_bvs = 100_000
bvs = map(BSphere{Float32}, [6 * rand(3) .+ rand(3, 3) for _ in 1:num_bvs])

options = BVHOptions(block_size=128, num_threads=8)
bvh = BVH(bvs, BBox{Float32}, UInt32, 1, options=options)


num_rays = 100_000
points = 100 * rand(3, num_rays) .+ rand(Float32, 3, num_rays)
directions = rand(Float32, 3, num_rays)


bvtt1, bvtt2, num_bvtt = ImplicitBVH.initial_bvtt(
bvh,
points,
directions,
2,
nothing,
options,
)

bvt = traverse_rays(bvh, points, directions)

for (ibv, iray) in bvt.contacts
@assert ImplicitBVH.isintersection(bvs[ibv], points[:, iray], directions[:, iray])
end


# TODO add example to README
# TODO maybe a pretty image / render?
# TODO benchmark against a standard raytracer? Check Chitalu's paper; the Stanford bunny example

6 changes: 3 additions & 3 deletions src/ImplicitBVH.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module ImplicitBVH

# Functionality exported by this package by default
export BVH, BVHTraversal, BVHOptions, traverse, default_start_level
export BVH, BVHTraversal, BVHOptions, traverse, traverse_rays, default_start_level
export ImplicitTree, memory_index, level_indices, isvirtual


Expand All @@ -23,13 +23,13 @@ using GPUArraysCore: AbstractGPUVector, @allowscalar
import AcceleratedKernels as AK


# Include code from other files
include("utils.jl")
include("morton.jl")
include("implicit_tree.jl")
include("bounding_volumes.jl")
include("bounding_volumes/bounding_volumes.jl")
include("build.jl")
include("traverse/traverse.jl")
include("raytrace/raytrace.jl")
include("utils_post.jl")

end # module ImplicitBVH
Loading

0 comments on commit c74b026

Please sign in to comment.