tekacs 22 hours ago

For anyone who – like me – was hoping for a video to see what it looks like:

https://youtu.be/h2V8YyfKCVs?t=4421

  • cubefox 9 hours ago

    I'll note that the above is based on an impressive paper presented at the same conference in the previous year, "Real-time rendering of animated meshless representations" (2025):

    https://youtube.com/watch?v=JzWYo-t4do4

    https://hal.science/hal-05095359/file/Real_time_rendering_of...

    What they did in the 2025 paper is that they used a tetrahedral mesh ("cage") to animate meshless geometry like voxel or SDF objects, which are (by themselves) notoriously hard to deform and animate, which is one of the reasons they have been used relatively rarely so far compared to meshes.

    Now the new paper instead uses a low resolution tetrahedral mesh to animate a high resolution skinned triangle mesh, which greatly speeds up ray tracing of animated triangle meshes, which is normally quite expensive.

    Also a notable: the 2025 paper was also based on a paper from the previous year at the same conference, "Interval Shading: using Mesh Shaders to generate shading intervals for volume rendering" (2024): https://youtube.com/watch?v=BbMGtfMei10

PcChip 1 day ago

what is it about raytraced animation that makes it more expensive to update the BVH mesh vertices every frame, compared to old-school bone animation where you send the info to the vertex shader every frame?

  • juancn 23 hours ago

    To make ray tracing practical, you need to update the ray-tracing accelerating structures when you animate.

  • modeless 23 hours ago

    Massively simplifying here but when doing one rasterization pass you process a flat list of triangles, in order, once. When raytracing a camera view you query a database of triangles, at least once for each pixel. To avoid scanning the whole list of triangles for every pixel, the database needs a fancy 3D spatial index whose structure depends on the exact position of each vertex. When you modify the position of vertices you have to fix up or rebuild the fancy spatial index too.

  • Keyframe 22 hours ago

    it's a global visibility problem, unlike rasterization which is a mostly localized problem.

    apart from all the updates and acceleration structures you have to do, you are also battling cache coherency during ray traversal, or as the saying goes: Primary rays cache, secondary trash.

  • socalgal2 20 hours ago

    > compared to old-school bone animation where you send the info to the vertex shader every frame?

    If I understand correctly this really isn't a thing anymore. Instead most modern engines copy the original vertices to a temp or skinned vertex buffer with a compute shader and then use normal non-skinned rendering techniques to display them. This means you don't need 2 copies of every shader, one with skinning and one without so less combinations.

    That doesn't change the other answers to your question.

  • dahart 20 hours ago

    It’s not always more expensive, but generally speaking for games and assuming some simplistic & straightforward approaches on both sides…

    With raster, you don’t necessarily have a BVH to update, you evaluate your rig, e.g., bone animation, which means re-calculating all the vertices in your animated object/character, and then drawing the resulting mesh.

    With ray tracing, you have to evaluate the rig (do everything above) and then also update the BVH, so the BVH update is extra. It’s also sometimes expensive because if you rebuild a BVH from scratch, that means sorting the triangles, sometimes multiple times. You can sometimes get away with a BVH “refit” for animated stuff, which is faster, but has tradeoffs. Even in the best case, you still have to read all the animated verts a second time after computing them, which costs memory bandwidth.

    Sometimes games with raster engines do have a BVH, but it’s likely to be a small BVH over objects in the scene, whereas ray tracing usually builds a large BVH over triangles and is a much bulkier acceleration structure.

    BTW, the linked paper here saves on both rig evaluation and BVH rebuild - in other words, this would help save time even if you weren’t ray tracing. This is essentially building a lattice rig so you don’t have to do the bone animation. Assuming the lattice rig has fewer verts than the bone rig, you save on rig evaluation time. It’s also meant to build a smaller BVH - you need a BVH over the lattice cells, and the BVH inside each lattice cell can stay static and contain multiple triangles. Only the lattice moves, and you only need to update the lattice BVH, so the ratio of lattice cells to triangles in the lattice gives you the approximate BVH build speedup.

  • forrestthewoods 19 hours ago

    Updating a BVH is expensive. Lots of work. Generally speaking acceleration structures like this are “do one large expensive computation upfront and then re-use the results”. And then you cast rays against it every frame.

    The old school approach is effectively the same cost frame to frame. It doesn’t cost more to render frame 17 of an animation than frame 16 or 18.

    In a sense your question is “why is one function more expensive than a completely separate and unrelated function”. And the answer is… because it is? It’s not a bad question. But you may not get a satisfying answer.

    • boulos 11 hours ago

      As aek and dahart said, updating a BVH (refitting) is not expensive. If anything, it's bandwidth limited.

      The challenge is minimizing the cost of (selectively) rebuilding.

      • forrestthewoods 55 minutes ago

        That’s just another way of saying “updating a BVH is expensive therefore spend effort to minimize the amount of updating it”.

        The fastest code is the code that never runs.

        • dahart 49 minutes ago

          There’s a material algorithmic difference between rebuild and refit. Not sure if that point was clearly understood.

  • a_e_k 18 hours ago

    Disclosure: I work with the authors of this paper.

    I'm going to answer this in two parts.

    First, you absolutely can update the BVH, keeping the tree topology the same, and just updating the internal bounding as the triangles and other primitives move around. It's essentially a bottom-up walk of the tree where you figure out where the triangles now are, update the bounding boxes to contain them tightly, then update the boxes of the parent nodes, then the parents of those parents, etc., all the way back up to the root node of the tree. The tree structure stays the same and the bounding boxes around each node just update. This is often called "refitting", as you just refit the bounding boxes around everything in the tree below them like a rubber band.

    For simple animation where things only move slightly between frames, this works just fine. And if you're using the DirectX Ray tracing (DXR) API, you can do this via what it calls "acceleration structure updates" [1]. You have to tell the API that you plan to do this when you first build the BVH, and then pass another flag when you actually do it. And there are rules that you have to keep the triangles, the same and only move the vertices. But you can do it pretty easily. And in fact, it's usually nice and fast, often much faster than building a BVH from scratch.

    Where it can fall apart, however, is in the performance of the ray tracing itself. As a super-simple example, let's say we have a little BVH of three triangles (A, B, and C) and three nodes (1, 2, and 3), something like this:

         +-------------------------+
         |1                 +-----+|
         |                  |3 *  ||
         |                  | /C\ ||            1
         |                  |*---*||           / \
         |                  +-----+|          2   3
         |+---------+              |         / \   \
         ||2 * *---*|              |        A   B   C
         || /A\ \B/ |              |
         ||*---* *  |              |
         |+---------+              |
         +-------------------------+
    

    If, during animation, triangle B moves differently than A and C, e.g., B moves toward the right while A and C stay mostly in place, then after refitting/updating your BVH looks more like this:

         +-------------------------+
         |1                 +-----+|
         |                  |3 *  ||
         |                  | /C\ ||            1
         |                  |*---*||           / \
         |                  +-----+|          2   3
         |+-----------------------+|         / \   \
         ||2 *               *---*||        A   B   C
         || /A\               \B/ ||
         ||*---*               *  ||
         |+-----------------------+|
         +-------------------------+
    

    Still the same tree topology, but look how large the bounding box around node 2 has grown! If a ray happens to hit node 1 and we trace into this bit of the tree, there's a good chance that it will pass through all that empty space in node 2, without actually hitting triangles A or B. We'll pay the cost of intersection testing node 2, traversing into it and then doing intersection testing against triangles A and B, even though we'll likely miss them. That's going to slow down your tracing, and the more the boxes have to deform and bloat like this to fit your animated geometry, the worse the ray tracing performance will get.

    Instead, for something like the above, you'd want a tree that looks more like this:

         +-------------------------+
         |1                 +-----+|
         |                  |3 *  ||
         |                  | /C\ ||            1
         |                  |*---*||           / \
         |                  |     ||          2   3
         |+-----+           |     ||         /   / \
         ||2 *  |           |*---*||        A   B   C
         || /A\ |           | \B/ ||
         ||*---*|           |  *  ||
         |+-----+           +-----+|
         +-------------------------+
    

    Now, triangles B and C which are nearer to each other are grouped together, while A is alone. And if the ray hits node 1 but just passes through the empty space between nodes 2 and 3 we won't have to do any triangle intersections. That's going to be faster. The downside is that the tree topology is different, which means this is no longer a simple refit. Instead, traditionally, we might have to build the tree from scratch. That's going to take a lot longer than doing a refit, but the trade-off is better performance for your ray tracing. So typically there's a bit of a balancing act that game developers do around deciding how long they can get away with just refitting the animation to the old BVH vs. when they need to throw the current BVH away and rebuild it from scratch. The name of the game is to optimize the sum of the BVH build and refit times plus the time to traverse and intersect them when rendering. (There are other tricks that can help, but I'm skipping in the interest of keeping this basic.)

    Now, the second part of my answer. There are 580 million triangles in the paper's demo video. Even if you only refit and never rebuild the BVHs, updating all of those vertices for animation is going to be prohibitively expensive. (And even just doing the bone animation for the vertices for 580 million triangles might be too costly, let alone the BVH updates.)

    So what's happening here is a bit of cheating. A coarse grid of tetrahedra (2 million in this video) are built around the model in rest pose, and for each tetrahedra, the triangles contained in it or touching it are determined. Then just those tetrahedra are animated and the BVHs around them updated/rebuilt. When a ray intersects an animated tetrahedron, the ray is warped back to where it would be relative to the rest pose and intersected against against the triangles that tetrahedron touches, using a little micro BVH. (I should note that this sort of "warp the ray" idea is pretty common in ray tracing. It's how instancing works so cheaply, for example.) If you look at the paper itself [2], you can see an illustration of the tetragedral grid in Figure 2 and the ray warping in Figure 5.

    But the point of the paper is that after all the initial setup, it's faster to update the BVH for those 2M tetrahedra than it is for 580M triangles, or whatever ratio you choose to use. You can choose the ratio depending on how approximate and fast or faithful and slow you want the animation cost to be (by how coarse or fine the tetrahedral mesh is, respectively), but the point is that it lets you decouple the BVH update costs from the triangle count.

    [1] https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.htm...

    [2] https://gpuopen.com/download/TetrahedralMeshes_AuthorsVersio...

    • Agentlien 15 hours ago

      This reminds me of when I worked on surgical training simulations back in 2011-2015.

      In some exercises most of the scene was made up of soft body objects containing millions of triangles which could be deformed and even destroyed - cutting any random edges.

      The simulation was handled by creating a coarser mesh of tetrahedra which were treated as deformable physical objects and skinning the triangles to these. Cutting simply removed entire tetrahedra and the triangles were reskinned to the nearest one or simply removed if none were close enough.

  • Arwill 8 hours ago

    A 3D transform is built into the BVH, which the ray follows when evaluating the BVH. This adds animation information too. The upside is i think, that the animation is evaluated on the fly, in parallel by each ray. No need to update anything on the GPU, just the timestamp.

JaRail 22 hours ago

Cool technique!