Skip to content

Implement basic ray intersection testing#8

Open
terrence2 wants to merge 7 commits into
WildPixelGames:masterfrom
terrence2:just-intersect
Open

Implement basic ray intersection testing#8
terrence2 wants to merge 7 commits into
WildPixelGames:masterfrom
terrence2:just-intersect

Conversation

@terrence2

Copy link
Copy Markdown
Contributor

Thank you for building and publishing Voxelis: it's a fantastic piece of technology! I saw in the PDF that ray-intersection is missing, so went ahead and built it. The new ray_cast method is now successfully powering visibility testing to load an infinite world in my bevy project.

The code is currently a very basic implementation of Amanatides-Woo ray/voxel intersection. I left it basic for the first pass to get some feedback before pushing further. The singular new VoxChunk method is the most flexible potential variant, supporting arbitrary rays and returning full collision data suitable for physics or rendering.

Currently, testing a ray against a MaxDepth(5)/LOD(0) chunk takes about 90ns on my machine and scales to 160ns for a MaxDepth(6)/LOD(0) chunk. If we modify the algorithm to only support internal rays and return only a hit boolean, we can shave about 20ns off of those numbers. Further optimization could potentially take advantage of the LOD tree directly, however, given that the current algorithm has a max of O(3*64) steps, it's hard to imagine that more complexity will pay for itself easily.

I would appreciate any feedback and am more than happy to make improvements to get this merged.

@aljen aljen self-assigned this Dec 8, 2025
@aljen aljen self-requested a review December 8, 2025 20:54
@aljen aljen removed their request for review December 19, 2025 20:53
@aljen

aljen commented Dec 19, 2025

Copy link
Copy Markdown
Member

Hi,

thanks for the kind words and for this PR!

Sorry it took me that long to respond, had a lot on my plate lately. I did a quick review and I'm impressed, great job!

Major issue:

  • glam bump to 0.30 - this breaks bevy (vtm-viewer and others)
  • with glam on 0.29 - build errors:
error[E0599]: no method named `min_position` found for struct `Vec3` in the current scope
   --> voxelis/src/world/voxchunk.rs:514:31
    |
514 |             let i = next_dist.min_position();
    |                               ^^^^^^^^^^^^ method not found in `Vec3`

error[E0308]: mismatched types
   --> voxelis/src/world/voxchunk.rs:523:31
    |
422 | impl<T: VoxelTrait> VoxOpsRayIntersection<T> for VoxChunk<T> {
    |      - expected this type parameter
...
523 |             if voxel_pos[i] < 0 || voxel_pos[i] >= voxels_per_side {
    |                               ^ expected type parameter `T`, found integer
    |
    = note: expected type parameter `T`
                         found type `{integer}`

error[E0308]: mismatched types
   --> voxelis/src/world/voxchunk.rs:523:52
    |
422 | impl<T: VoxelTrait> VoxOpsRayIntersection<T> for VoxChunk<T> {
    |      - expected this type parameter
...
523 |             if voxel_pos[i] < 0 || voxel_pos[i] >= voxels_per_side {
    |                                                    ^^^^^^^^^^^^^^^ expected type parameter `T`, found `i32`
    |
    = note: expected type parameter `T`
                         found type `i32`

Minor issues:

  • missing t in RayCastHit - would be useful for sorting later
  • curr_pos += direction * next_dist[I] - could be affected by float drift
  • no tracy span

After fixing the glam issue I can merge it as is, or maybe you want to fix minor issues too? :)

@terrence2

Copy link
Copy Markdown
Contributor Author

Thank you for the review! No worries about the delay, the end of the year is always extremely busy.

I think it will be easier to iterate on the patch in place, given that most of the minor issues are small.

  1. Adding t to RayCastHit is a great idea.
  2. Float drift is definitely a potential problem; did you have a solution in mind? There are at most 64 voxels per axis, so I wasn't too worried about errors accumulating, but my intuition could certainly be off. On reflection, I think as soon as I chose to make the API world-space, there was some guaranteed precision loss, either to compute a large curr_pos with small inputs or to transform a large ray origin into and back out of local coordinates. 🤔
  3. I did forget the tracy span. I had made a note to figure out how to use them in my game and never circled back. I'll copy one from somewhere else.

As to the glam build errors, you are quite correct! At some point I got tired of adding --all to all of my cargo interactions and switched to always using a Justfile, so must have gotten out of the habit. My game is using Bevy 0.17, which requires glam 0.30, so that's a hard requirement for me. I suppose there are a couple strategies we could use here. The simplest is probably to make the glam dependency >= 0.29. I'll see if I can get that working.

@terrence2

Copy link
Copy Markdown
Contributor Author

Okay, so using a version dep for glam of ">= 0.29" does allow users to select a higher version; however, since vtm-viewer is in the same workspace, it breaks again if you ever run a cargo update. I don't really think that's an acceptable state to leave things in.

I've seen two different mechanisms in the wild for how projects support multiple bevy versions, either of which we could adopt pretty easily.

  1. Pin each voxelis release to support a specific version of bevy. Most bevy-ecosystem crates do it this way.
  2. Add feature flags to allow a voxelis user to select any supported glam they want, like nalgebra does. This is technically more flexible as any version of voxelis could be used with any version of glam, but it's also more work, more complexity, and more cognitive burden for anyone adding voxelis to their project.
  3. Something else I haven't learned about yet?

My preference would be option (1), but I'd be happy to implement any of them. @aljen, which of those options would the project prefer?

Regardless, for now, I think the first step is going to be to land this patch against bevy 0.16 and glam 0.29 and upgrade from there. I'll get to work on fixing up the minor nits.

@terrence2

Copy link
Copy Markdown
Contributor Author

I see what you mean now about fixing the precision issue: if we accumulate on t instead of the world position, we are working solely in the t domain, which is small because we fast-forwarded origin to the chunk edge. I was thinking that t would also be large at long distances, but I forgot about the fast-forward.

And now that I've pointed that out, I think the t_hit I introduced above is actually useless because it's relative to the projected origin. We need to carry forward the t from the aabb intersection too. Probably worth adding a test for that as well. Let me fix that up too before we land this.

@terrence2

Copy link
Copy Markdown
Contributor Author

The test was (as always) a good idea: I found an edge case I hadn't thought about and manually verified that t_hit is correct.

I think I'm happy with the current state now and am ready to land. Thanks again for the helpful review!

@aljen

aljen commented Dec 22, 2025

Copy link
Copy Markdown
Member

Nice progress! I'll try to review it today :)

And sorry about the glam confusion. Instead of worrying about it breaking the build, I should just port to bevy 0.17 and move on. Lost track that it was released, my bad 😅

@terrence2

Copy link
Copy Markdown
Contributor Author

Oh! I probably would have just updated vtm-viewer in this patch if I'd known. I assumed you had other code behind the scenes that was on 0.16 still. I've had a couple "I'll just bump Bevy's version this morning before I get to the real work" turn into weeks long slogs before, so I'd hate to pressure someone to rush an update!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants