This tutorial will walk you through the details of the advanced vehicle template. When we are done, you should have a pretty good idea of how it works in theory, and how to build and configure something similar yourself. The main focus is going to be on the suspension.
All the FBX assets used in the vehicle template are available in the project directory, so you should be able to analyze the originals and experiment with your own designs in any modeling package that is capable of reading and writing FBX files.
Before we get started, you should be aware that a double wishbone suspension is quite a bit more complex to set up than the standard UE4 vehicle, so if you haven't successfully set one of those up before, you are strongly encouraged to do that first. There are some excellent videos taking you through the standard procedure over at Epic's YouTube page [links here].
Assuming that you are now a seasoned standard vehicle expert, let's go ahead and look into the double wishbone design. We'll start with some fundamental theory.
When we set up the vehicle movement component and assign wheels to it, the vertical movement of the wheels is typically updated by a WheelHandler node inside the vehicle's animation Blueprint. On each frame, the handler will move the wheels up and down along the local Z axis to simulate suspension, making sure that the wheels touch the ground whenever that is possible.
Further more, the WheelHandler also applies rotation to make the wheels spin around their Y axis, driven by the rotation speed of the simulated motor and gearbox. In addition to this, it will turn the wheels around their Z axis, driven by the current steering angle.
The default vertical suspension movement is clamped by the Suspension Max Raise and Drop settings in your VehicleWheel-derived classes. This movement is entirely linear, as illustrated below:
While not entirely realistic, this type of suspension simulation is in fact perfectly fine for most vehicles, because you cannot usually see the suspension arms or the other components such as the springs and shocks. Any car model with a full body can get typically away with this.
However, in a more open vehicle like a Buggy or a Formula 1 car, where the moving parts are in plain view, this movement can be problematic because there is no sensible real-world suspension design that would be able produce this kind of movement.
To achieve a more realistic result, we really need a type of motion that can be expressed as a rotation around some fixed pivot point on the vehicle's body:
These two different ways of moving a wheel up and down are clearly incompatible.
To solve this little conundrum, we can start by assuming that wheel management falls into two different categories: one being the simulated wheel nodes controlled by the WheelHandler, the other being the wheels that we can actually see being rendered when we drive the car. Then we could feed data supplied to us by the WheelHandler to the rest of our suspension setup to get the desired results.
In short, the visible wheel and the simulated wheel could in fact be two entirely different objects, and the simulated wheel would not even have to be visible at all.
The wheel parameters we define in the VehicleWheel class can specify the collision mesh, radius and width explicitly. Those specifications do not necessarily have to correspond to any real geometry in the vehicle's skeletal mesh, so there is really no need for the simulated wheel nodes in the mesh to have any real geometry attached to them at all. Further more, we can specify additional wheel offsets in the wheel setup section of the vehicle Blueprint, so the pivot of our wheels do not have to be aligned with the geometrical center of the visible wheel mesh.
All things considered, those are the basic insights we need to build a suspension that looks like it could realistically work from a mechanical point of view.
Before we move on, we need to take a look at two animation Blueprint nodes that will be particularly useful for our setup. The WheelHandler node has already been covered, and we will definitely want to use that, but there are other powerful tools that are crucial for this type of rigging: the CopyBone and LookAt nodes. They can both be found in the Skeletal Control category in the animation Blueprint editor, and they perform much the same tasks as standard position, rotation and aim constraints typically do in an application like Maya.
As its name suggests, the CopyBone node can copy transformation data from one bone (the source) to another bone (the target):
This means that once the WheelHandler has updated the transformation of the simulated wheels, we could for example grab only the rotation values it has produced and apply them to our visible wheels. This basic step would take care of spinning and steering the wheels, which we do want, while we avoid getting the translation (position) data, which we don't want.
The LookAt node can rotate any given bone in such a way that one of its cardinal axes ends up aiming at another bone:
This is useful for our setup, because it gives us a way to make sure that all the components of the suspension mechanism are constantly updated to point in the right direction, all driven directly or indirectly by the current position of the simulated wheels. All we have to do is to make sure that there are bones available for the LookAt nodes to aim at. This will be used for several bones in our animation Blueprint.
The information covered above is really everything you need to understand, and the rest of the setup is pure deduction based on those facts.
To recap: for each of the four wheels we will use one invisible wheel for the WheelHandler to manage, and one visible wheel that is actually rendered in game. The former is just a single bone/joint, without any part of the mesh weighted to it, while the latter is any wheel-like mesh we build in a modeling package and add to the vehicle model, which is then imported into UE4 for final setup.
For everything to work as intended, key parts of the suspension will then copy the transformation data they need from other bones, or adjust their orientation by looking at targets that we have set up in the model.
With the theory out of the way, it's time to look at how this demo vehicle is constructed. If you open Assets/FBX/vehicle_collision_S2.9.fbx in your main modeling application, you can follow along and see how everything fits together.
The vehicle prototype created for this tutorial has a suspension rig designed like this:
The key components here are the upper and lower arms (yellow), the kingpin (red) and the hub (blue). Both arms pivot around their respective hexagonal bolts seen in the far right of the image.
The most central point where everything comes together is close to the green bolt on the lower arm. That is where the simulated wheel joint, PhysWheel_[loc], is initially located. The kingpin, hub and visible wheel also have their pivots at that exact same location.
Each one of these components has a very strict responsibility and transformation range. The arms rotate only around their forward axis. The kingpin follows the position of the tip of the lower arm, but stays vertical at all times and never rotates relative to the vehicle. The hub rotates around its vertical axis only, in response to steering. The visible wheel copies its rotation from the simulated wheel, but takes its position from the tip of the lower arm. This keeps everything tightly locked together.
In any reasonably complex rig it is very important to keep the hierarchy and update order in mind. In this particular case: when the lower arm rotates it must bring with it a child mesh (lower green bolt) that the kingpin subsequently needs in order to position itself correctly using a CopyBone node. The upper arm in turn needs access to the updated position of a child mesh (near the upper green bolt) of the kingpin in order to have something to aim at using a LookAt node, and so on. As you can see, it is essential to make sure that the different components are updated in the correct order, otherwise parts of the suspension may appear to lag behind the movement of other parts.
All these frame-by-frame updates are handled by the animation Blueprint.
When building the model in a DCC application, we really only have to worry about the hierarchy and the exact position and orientation of the component pivots. A sensible orientation is particularly important for components that will have their rotation updated by LookAt nodes.
As a general note, it can be helpful to use the constraints offered by your modeling package while designing this kind of mechanisms. They will not follow the FBX into UE4 on import, but sometimes it is easier to figure out what needs to be done if you can get some basic movement going while building the model, just to ensure that different components will be able to move the way they need to without intersecting each other. However, avoid using any constraints that you will not be able to recreate inside the animation Blueprint.
Now let's see how this demo has been set up inside Unreal Engine. Load up the project file in the editor to follow along, and open the vehicle's animation Blueprint. Note that most of the operations are applied four times, once for each wheel.
While driving the vehicle, the following things happen in the animation Blueprint:
First, the WheelHandler updates the position and rotation of the simulated wheels (PhysWheel bones). The visible wheels (VisWheel bones) then update their rotation by copying the rotation from the PhysWheels:
This gives us a visually correct spin and steering, but the wheels will not change their position. That is handled separately in a later step.
Next, the lower arms (ArmLower bones) aim at the position of the PhysWheel. Arms on the right side of the vehicle use Y as the look at axis, while arms on the left side use Y Neg:
The result of a LookAt node can easily be previewed in the 3D window of the animation Blueprint editor: the current target of a selected LookAt node is marked with a red cross. This is easier to see if you set the preview viewport to wireframe mode.
When an ArmLower bone rotates to match its LookAt target, it brings with it a child component called POS_Hub. This is used in the next step to correctly position the Kingpin using a CopyBone node which grabs only the translation of the POS_Hub bone:
The Hub and VisWheel will later be set to the same position using the same method.
The next step adjusts the upper arms (ArmUpper bones) by looking at their respective targets (LAT_ArmUp bones) which have been placed in the correct position by the fact that these targets are children of the Kingpin bones, which were updated in the previous step:
After setting the position of the hubs, there is some extra work that needs to be done on the front hubs only, to account for rotation around Z caused by steering. This is handled with LookAt nodes targeting LAT_Hub bones that are children of the frontal PhysWheels:
Finally, after setting the VisWheel positions to match the POS_Hub bones, we make sure that the upper part of the shock is aimed at the lower shockmount (ShockMount_Low), and that the lower shock bone follows the position of that very same shockmount, which is a child of the upper arm:
The prototype's physics asset setup is largely the same as the standard vehicle template, with a few exceptions. The most obvious difference is a lot of small spherical bodies along the antenna, but more importantly there is custom collision shape surrounding the main vehicle frame.
Since the root component of this model is actually a joint, there is no geometry available from which to create a detailed collision volume. The main body volume was created by importing a separate static mesh equipped with a UCX mesh (Assets/FBX/vehicle_collision_S2.9.fbx).
We cannot handle this entirely inside PhAT. The first step is to build the collision asset in your 3D modeling package of choice, preferably by starting from the main body mesh itself. This collision model is then imported into UE4 as a standard static mesh, along with the UCX collision. Once that is done, we can simply copy this collision data over to the root node of the vehicle inside PhAT. This option is available when you right-click an existing body in PhATs hierarchy panel. If the target bone does not already have a body assigned, you can just add something like a sphyl first and use that. Then remove the sphyl once the custom collision has been added.
Now that you know how this setup works, you will no doubt want to start building your own model to replace this prototype. Below are some pointers that will help you do that with a minimum of headaches.
The first and most obvious thing to think about is to keep the names and the hierarchy pretty much identical to the prototype. Doing that ensures that the animation Blueprint can be reassigned and reused on a different skeletal mesh without any changes. That will save you a lot of time. All the meshes can of course be remodeled and moved to different positions. Just make sure that everything is properly aligned. Adding more mesh nodes to the model is not a problem, as long as it does not interfere with the overall hierarchy of the key suspension components.
The vehicle root should be placed at 0,0,0 in global space, and must not be rotated in any way. Making the root a simple joint object ensures that FBX export and import will work with a minimum of problems, particularly when using soft-bound components such as the deforming shock meshes.
If your modeling package allows it, set it up to use Z as the up axis. At any rate, assume that X is the forward axis even if your application of choice thinks that Y is forward. When in doubt, always test whether file exchange works as expected on a really simple 5-minute model.
The wheel meshes should touch the floor/grid in your modeling application. Always make sure that the individual components of your model have their pivots at the intended center of rotation, and that their rotation is zeroed out. The obvious exceptions are the shocks, where it makes more sense to orient the root and tip joints towards each other. Unless you know exactly what you are doing, never use any scaling other than 1,1,1, and avoid freezing transforms or equivalent functions.
The following import settings, which were used for the prototype, should be a decent guideline for importing your own custom model:
...and with that, you should have a pretty good idea about how to build your own advanced vehicle. Good luck!