Dunkirk Gunshots FX Recreation - Current Progress

For my graduating semester at the Bass school of Arts and Humanities, I worked directly under professor Nelson Lim for my capstone project. The goal of these projects is to encapsulate the skills we’ve learned through our time at UTDallas, typically serving as competent portfolio pieces that help graduates secure jobs in the industry. As for me specifically, the aim is to highlight skills that can be applied to a Junior FX role.

For this project, I had chosen to recreate a lovely shot from the film Dunkirk, in which the main character is being shot at through a wooden fence. I feel that this is a wonderful opportunity to gain experience with RBD, combining multiple layers of FX, as well as working with live action footage. Specifically, I was aiming to blend the wood fracturing, bullet dust, as well as the numerous debris and secondary FX required to make these FX realistic. The shot I’ve mentioned can be found below at about the 1:30 mark.

When I began this project, it seemed like it’d be a moderate challenge that would be simple enough that I could really focus on the details and not have to stress too much. Unfortunately, I was completely wrong. Immediately off the bat, Nelson saw my very first WIP and advised for me not to use the prepackaged RBD material fracture node. Instead he suggested that I build my own dynamic fracture patterns that are built upon the fracture points.

To begin, I used a Boolean fracture to separate a front layer for each plank. This would allow for the bullets to simply shave off flakes of the wood rather than always blow off entire chunks of uniform depth. This is also varied so that some flakes do actually penetrate completely whereas others might only run a few splinters deep. Then, I used VEX to measure the axis of each plank separately to determine the grain direction. This allows for the grain to run horizontal/vertical/diagonal based on the dimensions of each plank, dynamically accounting for rotation.

Moving forward, I copied cutting planes randomly within a radius around every bullet. For the sake of this explanation, I’ll refer to these as ‘knives’. These knives are sampled per bullet - per plank, which means a single knife cannot go across multiple planks: Every plank has it’s own unique wood pattern and a bullet can’t affect a plank it didn’t directly impact. Using the grain directions I defined before, I designated some knives for the actual grain and some for the cut - parallel and perpendicular to the length of the plank, respectively.

Beginning with the grain knives, I initially copied them facing directly away from the main bullet, resulting in ‘rings’ that form around the impact source. From this, I used linear interpolation to blend this directionality with the grain direction defined previously*. In doing so, the knives run parallel to the length of the plank but still universally buckle around the bullet that they are sourced from. I also added some additional masked peaking based on proximity to the impact source, resulting in a more localized warping. This is all, of course, parametrized to be more or less impactful as needed. Additionally, I also use the typical noises and shape adjustment techniques universally to make these knives more realistic.

I also do all of the above to the cut knives, with a few additions. These are masked by intersection with the grain knives and the resulting pattern is used to pull these along the length of the grains. In doing so, the cut knives are warped by the grain so that they don’t simply run perpendicular without any sort of interference. This helps bring in some of the expected splinter shapes that flaking wood would have rather than the previous rectangular blocky pieces. Additionally, the sheared sections are fused with the grain knives so that the blend between these knives is organic, while still retaining the jagged sharp look.

  • *I mentioned that I blend the two directions using a linear interpolation. Unfortunately, though, it isn’t quite that simple. Remember that the grain direction is based on the axis directions of the plank itself, with no consideration for where each knife is. For example, If the grain vector is pointing to {0,0,1}, and the radial direction is close to {0,0,-1}, then the linear interpolation is completely flipping the knife, resulting in awkward angles rather than the subtle warping I want. To get around this, the grain vector needs to first be flipped based on whether the radial vector is closer to it than it’s inverse. I did this by implementing a cool math concept I found here.

At this point, I had finished the fracture shaping and needed to begin preparing my geometry for simulation. Initially, I was going to use pop forces and constraints to drive my bullet simulation: The idea was that the constraints would be holding the pieces together until broken upon impact. However, Nelson quickly advised me against this and warned me that an effect like this would be primarily done with simple velocity manipulation. And so I began.


First, I masked the fractured fence based on intersection analysis with rods representing the bullets impact path. These rods were varied in radius and jittered so that the impact ‘force’ is dispersed slightly randomly. This masking prevents the entirety of the fracture from being simulated and instead controls the impact, resulting in more random looking splintering. Then, I referenced this same masking system inside a solver that creates the impact rods only on the bullet’s designated impact frame. Within this solver, I have a switch node that only allows this masking to run when there is a bullet impact on the current frame. All unimpacted frames simply transfer the mask attribute from the previous frame, resulting in a highly optimized solver that builds up the mask, only updating when needed. The reference mask still exists outside of the solver so I can adjust the final mask pattern as needed and the solver will build it up automatically.


To this masked geometry, I then used a similar impact instancing system to add velocity. Because this will be activated in the bullet simulation dynamically using the ‘animated’ and ‘active’ attributes, I don’t have to worry about velocity overlapping onto previously activated flakes. Additionally, the mask itself takes care of potential overlap with not-yet active flakes. In creating these velocities, I added all the expected controls such as proximity-based magnitude tapering, radial focus, direction and magnitude variation, and piece-size factor. I also added z axis limits to separately control the focus vertically. Lastly, I created a similar system for an angular spin attribute. By taking the cross product of the forward axis with a vector from the closest impact point to the center of each piece, I was able to make radially fanned vectors that make the activated pieces spin outwards from their respective impact source.

With all of this preparation combined with the right amount of POP drag and POP spin drag, the destruction effect comes out pretty decent. However, this is where the complexities of this shot come in: I need to use constraints to simulate the hinging that’s seen in the reference. I’ve set up a system already, but the constraints adjust the way the velocity of my flakes feel. This means I’m going back and forth adjusting values for my constraints, velocities, and drag forces all in tandem with each other. This is definitely a non-issue, but this aspect is currently WIP.

Moving forward, Nelson had also advised that I use Vellum to simulate the peeling and bubbling effects of the paint separately from the fracture of the wood itself. This took a ton of time to set up in a way that doesn’t behave abnormally. At this point, the planks (excluding the pieces that are marked to activate) are wrapped with cloth and welded to the activated flakes. This way, I can texture the cloth as paint and the planks themselves with a raw wood material. Most of these cloth points are pinned besides a rim around the activated flakes, resulting in some varied peeling only around the edges. This unpin mask shape is also altered by the grain direction so that the paint peels according to the fiber of the planks. All that’s left on this end is to scale the plasticity and substep count of the vellum so that the unpinned paint is stiff and doesn’t keep flapping after the initial rip.

As for the smoke and dust effects, I’ve created a very similar system to the flakes themselves. After using the pyro burst source node for so long, I realized the effect was much more accurate if I just manually built the sources myself. At this point, the pyro effects are about done, I just may need to dial in density based on how compositing goes.

That’s where I’m at for now. Aside from the things mentioned above, I still have more work to do in regards to overall scene buildout, material matching, rotoscoping the actor, etc. However, I feel that I’m at a good documentation checkpoint in terms of the FX and technical aspects. I’ll be continuing this project after a much-needed break from working on it pretty much all day every day for a while. In the meanwhile, I’ll be doing some fun learning involving deep learning. :)