HA, HA,
Hi, my name is Bill Rock Andbeck, and I'm an engine programmer at Sacrapage Productions in Belview, washington.
Today I'm going to talk about various techniques that we used to add wind, blown motion to our game, ghost of Sushima.
Goes to Sushima is an open world game which takes place in thirteenth century Japan, on the island of Sushima.
You play as a Jinsakai, one of the few samurai to survive an invasion by Mongol forces.
In Ghost, the guiding wind is a central gameplay mechanic, replacing the traditional heads up to Splir compass.
To show the direction towards various game play way points, this keeps the UI uncluttered and helps keep up the illusion that you're playing inside of a Samurai film.
It goes without saying, but wind itself is not actually visible.
Wind is not something extra, adding a cohesive rendering pass, like all the stuff, and then draw the wind. The wind is, of course motion built into many different rendered objects in the world.
These include particles, foliage, grass and cloth.
The wind direction is controlled by gameplay mechanics, and can change at any time.
It's not in general possible to bake the motion into a pre rendered offline animation, and we prefer procedural or simulated motion systems.
In addition to the game play aspects, all the large and small, secondary motions arising from the simulations make the game less static and make it seem more realistic and alive.
Couple of words about this presentation. I've been lucky enough to be with Sucker Punch for the whole PS, for era.
Infamous second Son was one of the first games to be released in 2014, shortly after the PS for launch, and goes to Sushima is one of the last Tripoli games to be released before the next generation came along.
The techniques described here were based on the quality performance trade offs that we needed to make on the PS, four.
As the next generation comes along, we may need to revisit some of these decisions.
That techniques all described today are not pushing the boundaries of accurate academic.
Simulation technology like you might find in a movie where the effects are all done off line or in a tech demo.
Where a large fraction of the available computing power can be used to simulate a small scene.
One more in the realm of heuristics and hacks, which allow us to blow millions of verts around using only a small fraction of the PS Fours. Computational capacity.
For the purposes of the game, these simulations don't need accuracy, per se, but they do need volume.
And for better or worse, sacra punch is a nearly entirely homegrown engine.
In this talk will describe some of the nitty gritty.
Details of how we implemented things. I'm not claiming that all the techniques we use were a shining example of the best way to do things, but they are what we actually did, and maybe that's useful. Data.
So the model we use for the wind velocity is quite simple, for the most part, it's just a single vector pointing from the hero towards a current current goal.
Or in cut scenes and other nonguiding wind situations, there's just a single authored vector, which might vary with the weather and be longer when stormy.
Um, we're not doing any real modeling the fluid dynamics.
And the main wind vector has a constant direction, but we vary the magnitude a bit from place to place, UM, using time, varying, pearl and noise.
This is visible, for example, on large fields of grass, and you can see gusts of wind blow through.
Particle systems will also often add in some higher frequency, curl noise to sort of make things swirl around more.
Particle systems also have.
Access to a system we call verticals. These are invisible, wind generating particles, which can be sampled by other particles.
They're potentially quite powerful, but we use them only in a few sort of one off places.
Particles, grass and foliage, also have access to some inputs that let us model local disturbances caused by footfalls or the passage of characters.
These aren't wind, per se but they do move things around in a similar way, so I'll talk about them as well.
Probably the most obvious thing, moved by the wind, and the game is particles. The air is usually full of leaves, just smoke, fog, pollen,
Since the very earliest days of the P-S, four soccer punch has been using a proprietary particle system.
UH, which has served us very well since we introduced it with infant, the second son.
The core architecture has changed, actually, very little, from the second Sun version. I gave a GDC Talk in twenty fourteen.
Which covered the system in detail, so this talk is going to glass over the implementation, but here's a high level overview.
Our particle system is entirely GPU based system, where each particle is touched only by a compute shaters running an async compute, so it's fairly high performance.
And its biggest advantage is that it's extremely programmable.
Instead of fixed function features that sets that you can just sort of turn switch on and off, it's based around these complex, text based expressions.
Which just get compiled into optimized GPU code.
And this lets artists mix and match features and sometimes surprising, in wonderful ways, i'm mostly going to talk about new functions We've added to this framework.
And our lead artist, matt Vino has an excellent blog post back in January about the effects, and goes to Sushua, which I suggest you look at.
There are a lot of leaves, and goes like a lot, there are thick carpets of leaves coating every surface across large areas of the island.
Obviously, we're not modeling all billion leaves at once, and in the distance, the leaf cover does just become a texture.
But most of the leaves in the immediate area around the character and the carrot camera are in fact live, and they do respond to wind and disturbances.
There's something like 10000 active leaves in a typical scene.
Here you can see how many of the leaves on the ground are actively simulating particles which react to the hear his movement, and they're kicked up when he moves past them.
There are some complicated expressions on the leaves which model them as disks, so that as they hit the ground, they rotate according to the torques and things, and they sort of touch and spin and settle down.
We switched our main train implementation during the development of Ghost to a height map based approach, with a hierarchy of tiles containing various resolutions of tight mapic.
Height map that can get paged in and out.
We gave the particles access to this height map via a terrain pause function, which just snaps the given particle down onto the ground.
We also use it for larger scale wind gusts, as I mentioned, we're not adjusting the wind direction in general to flow around mountains in a complex way. And this is fine for most things.
But for it looks bad if wind, tearing stuff is flowing straight into the side of a mountain and the stuff is just kind of disappearing into the ground.
So we are doing the most basic approximation of fluid dynamics for just this case, by taking several height map.
Samples out in front of each particle, and sort of giving it an upward velocity in advance so that it goes up over things nicely.
Yeah.
A technique we used to add a bit more.
Interactivity to the particle motion is what we call verticals. These are special flavor of particle which don't actually draw themselves, but are visible only through their effect on other particles.
They're basically like little spheres of wind. They output a position, orientation and radius, and also a vector which determines the direction of the wind.
Using a coordinate system which is attached to the surface of the sphere. So it has like East West, north, south and up down components.
So just by pointing this vector around in different directions, you can model several interesting.
Sort of shapes of wind, including circular vortexes, the near gusts and sort of outward facing blasts.
Vertical emitters atomically append these into a single small array listing all the verticals in the world.
And then regular particle admitters can access this array through a new function.
Which samples the accumulated vertical contribution at a point, and doing this in a red brute force wave is running down the whole list and adding up all of the contributions.
And it somewhat amazingly works, even up to, like, hundreds of verticals.
This isn't an automatic thing, particle emitters only opt into this in a voluntary mash fashion for relatively few places where it kind of helps.
Um, and since it's another building block, function.
Emitters decide for themselves what to do with this information.
They might just sort of, in a straightforward way, add the vertical wind under their acceleration vector, and so they sort of get blown around by it, like these leaves over a campfire where there's some upward.
Uh, facing verticals emitting from it.
But we can also use verticals spawned by sword strikes and character motion to say, extinguish.
Candle flame particles as you go near them or to scare away animals, I crabs, during an arrow shot, it shoots a little vertical to make them say, hey, I need to.
Dig myself into the sand. Now.
During the game, tushima is overrun by Mongol armies, and so there ought to be actual armies. We have all these amazing, beautifully sculpted and animated character.
Models and rigging for regular game play.
Those are pretty expensive. The CPU has to compute all the AI and animations render 100000 pollies with lots of fancy, uh materials.
And we can afford to have a few tens of these heavyweight Npcs in the game at once, but there are some scenes like the initial invasion where you'd really like to see hoard.
Enter animated particles, here's a scene from the very beginning of the game, as the Mongolls are overrunning the beach. Most of the ones you see are full and PCS.
But if I fly over here away from the main action, sort of into the distance, you can see that there's a whole crowd of Mongols there that are in green, who are actually a particle system.
Than all those green ones are super low cost. GPU. Only particles.
Here's another example, this is the samurized fortification seen in the background at the very beginning of the game, it's just kind of a little bit of set dressing.
All of the same, right here are particles up close, there are far cry from the real models, but at any distance at all, they're remarkably complex for taking basically zero CPU.
We added this feature specifically for armies of people.
It turned out to be even more useful for all kinds of critters, like butterflies, birds, crabs, dragonflies. This crane is a particle.
As are the sea gulls up on the upper left, and the whole flock of starlings.
Animations for an animated particle are compiled into a fat texture containing the local skinning matrix for each joint at each frame.
This can get large, so it's best suited for simple objects, and maybe only a few tens of joints.
Each particle can individually specify which clip and which frame within that clip it should display. At each time step.
Since Animation State is just another building block.
Artists have great freedom to use it, however they want, artists are.
Artists have done some amazing things with multiple animation clips like frogs which float on the surface of the water until the player gets near to them.
And then they swim away and spawn a little water, ripple particles ago, with our land, they hop away. So animated particles were easy to implement, and they gave a really big bang for the bug.
Me.
Ghost is set in feudal Japan, and most what you see is natural objects and especially trees and shrubs.
Nearly every vertex of all of these is in constant motion, influenced by the wind. Most of our trees are modeled in speed tree, but the run time is entirely hunger.
Motion of the trees is implemented by effectively skinning the geometry under a simple skeleton, just three levels, trunk branch and sub branch.
The actual drawn geometry is attached to the skeleton.
Uh, these aren't.
Implemented, as traditionally, skin joints, where a separate stage of computation builds up. These joint matrices.
They're actually running entirely in the Vertex shader, using only local information stored at each vertex.
So each vertex stores extra data in the vertex stream about the branches. It's attached to, basically just the beginning and end points about the branch and the sub branch.
So the vertexes are thus fairly fat. It does have the advantage that it supports an extremely large number of branches.
When you add wind, the vertex shader takes the wind vector at the tree's location into account and rotates each branch around its origin, away from the wind, to get the whole tree to bend.
And we also add a little bit of sinicidal, sinusoidal motion, each branch to make a bounce back and forth, and the phase of this motion is based on a hash.
Of its position so that the additional adjacent branches and adjacent trees don't move quite the same as one another.
This wind sway is running in pretty much every vert, in all of the greenery you see in Sushima, including most impostor level geometry for trees covering distant hillsides.
We also optionally take the displacement buffer into account, using very similar code based on the same skeleton, so that branches can get bent out of the way Jim walks through them.
Now we come to grass, which covers most of the ground, on sushi.
We have a whole GPU pipeline for specifically grass blades, we handle numerous different styles of grass, with no limit to how many different styles can be drawn in the same frame.
A typical grass, heavy scene like these will process a little more than a million separate potential grass blades.
And after we've put this number down using a variety of heuristics, like visibility, calling and distance limits, we end up drawing around 100000 blades.
Each one of these reacts to the wind.
I should note here that the pampas flowers you see so many of here are not drawn through the grass pipeline.
Actually more akin to foliage, and are drawn through the same GPU code path that we used to generate, large instanced, draw calls for trees and rocks and stuff like that.
The basic flow of grass system is this, of course, it's all done in the GPU, whose compute chair, which generates each blade of grass, each frame.
Dispatch one instance of the shader for each train tile out in front of the camera with one thread per potential blade of grass.
Each thread first does a look up into a grass kind map to figure out whether there should be grass here at all, and uses the train height map to position it.
It prunes against the view, frustum and exclusion buffer, and fades with distance.
We have a bunch of different grass in the games, there's a big array of constant data for each kind of grass.
Some blades which survive this pruning, get a bunch of parameters computed, like their height with bend, etc.
And are appended atomically onto a buffer in fast GPU memory, along with the count. So we can dispatch an indirect draw.
The draw shaters also consumed the grass parameters to place individual verts and color, the pixels.
This is arranged so that we can do most of the heavy lifting only once per blade of grass.
Since there are hundreds of thousands of blades of grass being drawn in many scenes, the blade list could get big. So we dispatched the compute and draw shaders in a pipelined Manner.
With a double buffered blade list so that one set of blades is being drawn while the next one is being set up.
The actual vertex shader for the grass is straightforward, and takes all the blade information from the purb blade, compute, pass and adjusts the birds to bend and collar, etc, of the Blade.
The motion is much like the foliage, with a sinusoidal sway added to the top of the general bias, away from the wind.
It also considers several other factors, like bending each blade away from the center of its clump, uh, and bending them downhill.
UH, wind includes both high and.
Low frequency noise based on the position. There's also a TD, displacement buffer around the camera, which we write into using a special kind of particle.
As a hero passes by, the blades will bend until accordingly.
My colleague Eric Wallab gave a GTC Talk this year, uh, it goes into much more detail about how all this works, so I recommend you see that.
Excuse me.
Being set in old Japan meant that we ended up with a lot of cloth in the game, armor, comonos, those sachomono banners that.
Foot soldiers wear.
We started off with a CPU cloth implementation left over from second Son, which could handle a few characters. Each of the few pieces of cloth.
As ghosts took form, the number of clothsums kept growing.
The result, bit of an arms race, at times with artists.
Adding more cloth and kind of tanking the purse, and then be hacking the code to try to make it run faster somehow, and so on. And what I suppose was a virtuous cycle.
Uh, in the final game, we usually have several hundred cloth sims running on screens, sometimes as many as a thousand.
In this scene, there are about 250 cloth sims for clothing banners, tent flaps, uh, for a total of around 70000 simulated vertexes.
It's taking about 2% of this P-S, four G-P.
In addition to cloth and leather, we use cloth sins for a few things, which, strictly speaking aren't cloth, like strands of human and horse hair, and even hanging bodies, in some Cases.
Our cloth Simm starts with a sin mesh authored in Maya, here it's just a nice rectangle, but in general, it's not quite so regular.
This mesh is used to generate basic, damped spring mass system, with nodes at the verts and springs in between here are the stretch springs.
Uh, and we also had springs crosswise for sheer, they're even further springs to handle bending, but we actually do this a little bit differently.
Um, we also support one dimensional chains or ropes, since meshes in my act.
Our lists of faces, you can't have a linear mesh with, just for Texas and edges. And we use this a lot for individual strands of hair.
The nodes store information about the base position, which in general can be skinned onto a skeleton.
And they also have a vertex painted, maximum distance that they're allowed to move from this position.
Most notes get a big radius so that they can move freely around, uh, but some of them, like the couple in the corners there.
Uh, have a distance of zero, which makes them stick to the underlying model, and that's how you attach them to things.
So to draw a piece of cloth in the world, we need to other two separate meshes in our system. One is the SIM mesh, which we saw before, which describes how the cloth moves and deforms.
Then we have a separate draw mesh, which also contains the shaded triangles to draw into the scene. And the draw mesh is often similar to or identical.
To the SIM Mesh, but it might have more detail, provides a place to attach, rendering specific stuff like vertex colors and Uvs, separate from the Sin.
The actual connection happens, the kind of skinning each SIM, vertex screens of joint.
Which generates a full transformation matrix.
From the point of view of the draw, mesh rendering code, these are just like regular joints.
But under the hood, they take a different code path than regular animated joints, because there are just so many of them, there are hundreds of thousands of them in the scene.
So these are generated by the cloth SIM on the GPU and are never even touch for the CPU.
As models get further away from the camera, we often switch out draw meshes for one to the simpler level of detail.
In these cases, we don't switch the cloth, sims, generally, it will replace the draw mesh, but keep the higher reds in running.
Uh, with the same, the new draw mess attached to the same SIM so that we don't get a pop when we switch from one sin to the other.
We do fade out cloth, SIM motion entirely once they get further enough in the distance.
This depends on the size of the object, so little tassels might fade away after a few meters, but a large banner that you can see in silhouette might never let out.
We had to actually push out the symbolized distance for horses really far, because their mains are actually modeled standing straight up. So as they got to the large distance, they get Mohawks.
e
The basic data flow, an organization of the GPU cloth, is this, each piece of cloth in the game gets a single computer chatter dispatch running in a single thread, group, nasing Computer.
Consume some fixed data, like the topology of the springs.
And since we're using standard for lay integration, it only needs to keep track of each node's current position and previous position. From this, it can compute the current velocity.
The shader computes the updated positions of the nodes for the next frame and writes them back to main memory. This memory is overlapped with the previous no positions and will become the next frame's current.
Is for ping pong back and forth between the two buffers.
It also computes the new joint matrices for each node and writes them into the appropriate place so that they can be picked up by the drawing code. Later in the frame.
HA,
During the solved, it also uses some fast GPU local data store to.
Store intermediate results. This includes a base skin position, uh, and as well as updated position at various stages.
Since we're using a single thread group, we can sink data across threads between stages with the simple instruction without having to do multiple dispatches or complicated cash flushes.
This doesn't mean that only 512 threads at a time are active per cloth. SIM.
And that's too small to get good resource usage, so we do rely on overlapping multiple separate cloth sims with, uh, the graphics pipe.
So that we can keep up overall performance.
Although we only run 512 threads, we can actually support more nodes than that by looping the shaters so that each thread updates multiple nodes.
The fundamental portions of simulating the cloth are reasonably straightforward.
Uh, there's usual fair lay integration to take little time steps and apply all the forces and solve where each note should be of this frame.
And taking all the constrains and forces into account in general, reduces to solving a giant N by n matrix.
Uh, which, if you have enough processing power, you can just do it, and for better or worse, we're not doing that.
A big difficulty with the spring mass model is it requires many small, small time steps for stiff material.
Fairly easy, using traditional methods to believably simulated, a bunch of, like bowling balls connected by springs or a big sheet of heavy rubber.
Uh, we integrate through these little forces, everything moves nicely.
But for real world materials like leather or ropes, these things are like stiff and don't stretch much at all.
And the way to model is accurately is to use really stiff springs.
So that, even a small offset.
From the rest length generates a large restorative force, but that starts running into numerical difficulties. Uh, we're doing this with numerical integration, taking little time steps and applying the forces.
If the time steps are too large for the accelerations involved, things go bad quickly, you might start overshooting, and, you know getting further and getting this positive feedback thing.
And eventually, things just go crazy.
You can solve this in general by taking really small time steps and taking a lot of them, but that takes a lot of computation, and we're going for fast and dirty Here.
So using a giant hack.
Um, instead of using hooks Law to calculate spring forces and integrating, as usual, we're applying springs in a separate step.
And just restoring the spring, some fraction towards its rest length. So even with a big time step.
We never overshoot the rest position of the spring, so it remains stable.
The big issue this causes is that we lose our time step in variants, you can tune the restorative percentage to get things to be more or less stiff, but if you change a number of iterations. It behaves subtly differently.
This is fine, as long as the frame rate stays the same, but it has caused us problems when we've changed the clock speed.
Uh, for cinematic effects or in running and backwards compatibility mode, and P-S, five, or we double the frame rate.
To get the same running in a fully parallel way, we want to compute many different springs at once, we could just run them all at once with one thread per spring. But this does.
Present a problem of how to combine the inputs from the different springs and avoid multiple threads, sort of stumping on each other's outputs.
The way we're dealing with this is to classify the springs into a bunch of separate spring sets.
So that.
Each no note is updated by more than one spring within each set, so we might first apply here the blue spring set, sort of, one spring for thread, up to each end point from a single thread.
And in black, orange, etcetera and sinking in between each so that they can see each other's outputs.
For this regular grid, it's really easy to find a coloring which satisfies this requirement, but most of our cloth isn't quite so simple.
This is an example of the M-P, complete graph coloring problem. It's basically just solving sedoku.
A simple greedy algorithm does a pretty decent job, but I did squeeze a few more percent out of it by writing a simple genetic algorithm to try to choose minimal sets.
The solution of computing all the nodes in parallel has some big problems.
Foremost among them is that each note is only really interacting with its immediate neighbors. It takes many iterations for change, one end of the SIM to make its way all the way to the other side.
Let's imagine the common case of a banner hanging horizontally from a bar.
When we integrate the motion of this, all of the nodes move down by some amount, according to the time step and the gravity, except for the nodes and top, which are attached to the pole. This causes the attached.
Strings to spreads. And so, as we take a step.
Pull back towards their rest positions, but only the ones attached directly to the stretched springs, feelless pull initially.
You add more iterations, the wave of spring tension moves through the cloth, and eventually things will even out and things will contract as desired.
But for a detailed sin with many short springs, it's more iterations than we're willing to compute.
This is particularly noticeable when you have cloth hanging from something.
The visible effect is that the cloth becomes superstretchy, even though the individual springs are stiff, the whole sin is very much not.
With the parallel implementation of described so far, gin's robe looks like it's made of rubber.
Especially noticeable in the white tassels at the corner of the building where they stretch unnaturally under several times longer than they were authored.
Hacky solution I used is to identify during compilation, nearby anchor points.
These are the ones who have a maximum distance of zero from their skin positions, and so are fixed in place the top row here.
Each mode remembers the index of its nearest anchor point, and the original distance to that point.
At one time, once we've applied the offset from immigration, we enforce a distance limit, so that that um.
The anchor point doesn't get farther than that from the anchor point. This can be done entirely in parallel for each node.
They allowed distance to the anchor might be slightly greater than are the initial distance led, stretching at a little bit in general, it's pretty close to unity.
In this way, we can apply the impulse from the anchors directly out to each No, directly, without having to go through all the intermeses.
Springs, I think of a kind of like, in addition to the wobbly springs and masses, there are these in elastic pieces of invisible fishing line connecting each node to its anchor.
They can't stretch any further than that, but they are free to move around within those radii, and that allows plenty of wind flapping and movement.
There are some common cases where single anchor doesn't work well enough, and so we support two anchors, and this handles like the case of a rope hanging suspended, and it gives a nice capery.
Here's the version using anchors. The cloth still moves around quite a lot and looks loose and blowing, but it doesn't stretch all like even all the way to the ground.
And the tassels are short and stiff, it's like we want, and here's a debug view showing where the anchors are attached.
There are some cases which are not well handled, bankers, which I don't have time to describe in detail. It does work quite well for the majority of cases, though,
Cloth doesn't exist in a vacuum, and it needs to interact at least somewhat with the things around it. In the important case of clothing, it needs to drap around the body of the character.
We only support a very limited form of cloth collision. It's entirely separate from our general physics model, and built up of just a couple of kinds of simple shapes.
We support a lipsoids, but most of our character, cloth collisions are built up of a particular shape we call a sphere pair. It's just a capsule consisting of a pair of spheres and a frustum connecting them.
We collide only the nodes themselves against the collision shapes, which is in sufficient to be really accurate.
Um,
Both spheres are optionally skinned on animated joints, so it's possible to attach these to the actual joints of a character, and they can build up a halfway accurate approximation to the shape of a human.
They also support a single collision plane, which can be set up to automatically match the ground beneath the character. Hear that collision volumes used by Gin and his horse.
Difficulty with collisions, especially only checking the vertexes, like we do, is preventing sudden movements from completely penetrating the cloth.
Uh, this is especially problematic because since this is a video game for combat, gameplay reason, sometimes the hero can change poses at superhuman speeds.
His arm, say, can be animated outside of the current cloth between one frame and the next, and once this happens, it's kind of difficult to know what to do. Each vertex can get pushed outside of the volume.
The collisions, but some of them are now on the wrong side.
Uh, and the volitions are working to keep them there, so we're computing each Fortex and parallels, it only has local information, but this is kind of a global problem You need to solve to get one.
Manner.
Manifold outside another, we have a trick for maintaining cloth on the same side of a collision Volume.
For some collisions, in addition to pushing the note outside the volume itself, we look at the original skin position of the mode before, in the simulation of has occurred.
We find the nearest point on that shape and construct a plain intention to that point, but in set it backwards, uh, by some amount, and we can strain the Simmo to stay on that side of that plane.
We want it to be able to deform and slide around some, but if it somehow gets too far around, we'll stop it. This works pretty well.
You won't be surprised to hear about out, we're not doing full cloth versus cloth.
Collision, doing that right is a big and squared problem, but we do support layering one piece of cloth over another in a very limited way.
We do this by making use of some machinery we already have in place. You remember that each node has a maximum distance, it can move from its skin position.
Now imagine we went to layer this light blue cloth, SIM, over the black cloth, SIM, we're going to use the same kind of MAX distance radii, but instead of centering them on the initial position.
Uh, we offset them outwards and skin them onto the base cloth layer. This means we have to remember an extra position and skinning information at each layered point.
Um, but we just have used that instead of the original radius when we're doing that next distance check.
This allows each node.
To move around and the spheres move with them. And it only works if the top cloth layer.
Doesn't move very far relative to the bottom, and if the bottom cloth doesn't to form extremely, but it's pretty effective for many common cases.
The cons costume is a good one to see this slayering in action.
The separate layers show quite a bit of movement relative to one another, but they don't usually clip through one another.
Even like the chain things on his back are layered outside of his cape.
So that's it for my talk. Thank you for coming, thank you for listening, and I'll do my best to answer questions in the chat.
Uh, or in this email address.