Building a 3D Seat for FSW

Change List

A list of changes made to this document.

Version Date Revision
 Initial document.
 1.124/11/2017 Tidied-up content.


    This tutorial demonstrates a way of creating 3D aircraft seats for FSW. It assumes the reader has a basic knowledge of the following software:

    • 3DS Max
    • Substance Painter
    • Photoshop
    • XNormal
    • ZBrush

    Blocking-Out with 3DS Max Primitives

    We begin by blocking-out the seats in 3DS Max using basic primitives. We shall build the new seats around some existing ones that need changing. However, the reader need not already have an aircraft with seats in order to follow this tutorial.

    Some useful tools during the block-out stage, are the Shell modifier and Chamfer tool (to soften hard edges). There is nothing especially complex happening at this stage. The example block-out seen above, started life as a Box primitive.

    Once we were happy with the overall shape, it is time to add some finer detail. The first thing to address is the seam separating the leather hides. 3DS Max is useful to use at this stage as we can rely heavily upon its edge-loop manipulation tools. Once an edge loop is selected, the selection can be converted to vertices and pulled inward using the Push modifier. This translates the vertices along their normals. The selection is then converted back to edges and a Chamfer modifier is added to both the inset edge and its neighbours.

    The same process is applied to the seam running around the bottom of the headrest.

    A similar method is used again for the slats running across the seat centre, ensuring edge-loops are distributed evenly.

    This edge selection workflow can also be useful when creating other interesting elements such as piping on the border of fabrics. For this example, we select the edge-loop we want to use and Right-ClickCreate Shape. This editable spline has a number of useful parameters including Enable In Viewport, thickness settings, and various types of point interpolation.

    Creating this effect manually would require hours of tweaking so this method is preferable. The same process is applied to the left side.

    The bottom part of the seat uses the same technique as the back with the exception of the leading edge curling around where the back of the pilots knees will rest. A hole has been cut from the central area, allowing room for the joystick.

    The finished block out is pictured below. This final version has a joystick and a few other extras including the seat belt and straps, taken from the old model.

    Importing into ZBrush to Add Fine Detail

    The finished block-out now needs some fine detail to improve its realism. An .obj will work fine in ZBrush, but can be slow when frequently jumping between the two pieces of software. The GoZ button can resolve this issue by directly sending the mesh between ZBrush and 3DS Max.


    Detail is added in ZBrush using an iterative, layered approach. One common mistake is to subdivide the mesh several times and then start adding fine geometrical information right after import. Lower subdivision levels should always be used while confronting the fundamental shape. Only when the potential of a given subdivision level is exhausted, should a further subdivision be made. When it comes time to add stitching and cracks (with the relevant subdivision level applied), anything courser should have already been applied. This is very important and will impact massively on the final result. It is good practice to build creases using a layered approach, larger marks using lower subdivision levels, and smaller ones using higher subdivision levels. 

    For this chair, the Inflat Brush was used on the bolsters and lumbar support. 

    Here is an exaggerated example of what the Inflat brush can do. It is most effective at low subdivision levels. Along with this tool, exists a setting to globally inflate the mesh. Using this will give the impression of foam filler pushing outward on the upholstery from within. The central pads, in particular, make good use of this approach.   

    Once happy with the general form, we start subdividing the mesh a little more to lay down some basic folds and creases, paying attention to areas prone to bunching, deformation, and stress. A few really useful tools to use at this point are:
          • Dam_Standard (hotkey D, S) - used for creating focused concave lines.
          • Standard (hotkey S, T) - used for creating larger raised areas. 
          • Smooth (hotkey SHIFT or ALT+SHIFT for a different algorithm) - used to smooth areas out.
          • Pinch (hotkey P, I) used for attracting two edges of geometry together. 

    The Dragrect option under the stroke setting can be very useful when creating folds and creases. Alphas can be created directly in ZBrush to use with the Dragrect stroke option.   


    After the High Poly model is created, we duplicate and then decimate it to generate a more performant version for 3DS Max. The reason we do this is because 3DS Max will struggle with the multi-million polygon mesh we created in ZBrush. We still want to keep the high-poly mesh's geometrical form, but with more efficient topology - Decimation Master helps us do this.

    Please note: in the screenshot below, the mesh contains almost 14,000,000 points; after decimation, it contains 17,000 points. That's three orders of magnitude less!

    This is a much more manageable mesh and can be sent back to 3DS Max using the GoZ button found in the Tools category.

    Retopologising in 3DS Max

    This stage involves creating a low-poly version of the seat which can be implemented into FSW.

    We start the low-poly version at the seat's central section. Firstly, a Box primitive is created in scene. We create this Box in order to use Step Build and can delete it after creating our first quad. Under the Surface roll-out in the Freeform tab, there is a Draw on Selection option. This will glue any polygons we create to the seat, ensuring our low-poly mesh conforms to the curvature of our high-poly. LMB will create points and Shift Clicking will build geometry between the points.

    The lumbar support and side sections of the chair are brought into scene and merged with the newly created centre piece. Unnecessary loops are then removed to keep the poly-count reasonably low.

    Smoothing Group Theory

    When it comes to smoothing groups, the seat is pretty straight-forward due to its organic shape. By rule-of-thumb, if something has a hard-edge, it should have its own smoothing group. Any edges below 45 degree, may either have faces sharing a single smoothing group or use multiple groups depending upon context. Where ever a UV border exists, should be a split in smoothing groups, for example.

    Here is an example of this principle in use. There are 3 separate smoothing groups, 2 with 90 degree angles, and 1 with multiple 30 degree angles.

    This second example shows the same cylinder with smoothing group 3 split-up into 3 and 4. This is fine provided the UV islands are separated along this seam.

    Another study to demonstrate what happens when baking normal maps with incorrect smoothing groups is as follows. This should be used on areas of mesh greater than 45 degrees when trying to conserve polygons. If feasible, the edge can be Chamfered and put into the same smoothing group as its neighbours.

    All of the examples below have been baked with a Cage, which is essential to creating artefact free normal maps. Without a Cage, the artist has no control over normal data is projected across meshes.

    Example 1: 
    • 6 Sided Cube
    • 1 Smoothing Group
    • Connected UV Map.

    The cube looks pretty good overall. There are no artefacts on the edges. There is one issue however: because right-angled edges are lumped into one group, there is a strange, wobbly shading anomaly across the object.

    Example 2:
    • 6 Sided Cube
    • 6 Smoothing groups
    • Connected UV Map

    This one shades more nicely than example 1. The wobbly shading artefact is gone as each face has its own smoothing group. However, we are now faced with an anomalous line running along the face edges.

    Example 3:
    • 6 Sided Cube
    • 1 Smoothing Group
    • Split UV Islands

    This is similar to example 1. If we baked this one without a Cage, we wouldn't get artefacts as the UV's are on separate islands to each other. Again, the only issue is the strange shading anomaly caused by the single smoothing group. 

    Example 4: 

    • 6 Sided Cube
    • 6 Smoothing Groups
    • Split UV Islands

    This example is the perfect balance of quality and efficiency. There are no shading issues, no artefacts, and no anomalous lines running along the edges. If polygons need to be conserved, this is definitely the best option.       

    Example 5:

    • 54 Sided Cube
    • 1 Smoothing Group
    • Combined UV Islands

    This cube achieves the best quality, but at 9 times the cost of example 4. This is an example of an important asset the player will see frequently and up-close. Most of the time, this level of quality is unnecessarily.

    In summary, these are how the examples should be used:
    • Example 1: use if the angle of a neighbouring face is less than 45 degrees. A Cage should always be used. 
    • Example 2: never use.
    • Example 3: use if the angle of a neighbouring face is less than 45 degrees. A Cage should always be used. 
    • Example 4: is the perfect balance of quality and efficiency.
    • Example 5: is the best quality, but at the greatest cost. Use on important, large areas requiring detail. Avoid on small features such as fixings and rivets.      
    We shall mostly use examples 3 and 5 in this tutorial as the organic form lends to smaller angles between faces. However, given the intricacies of the chair, different sections of geometry will be split into separate UV islands, allowing efficient texture map packing, and minimal texel distortion.

    UV Unwrapping and Layout 

    Here's what I use to UV map.
    This next stage is very important to achieving a good final result and needs to be done correctly. This is not only to maximise space, but to balance neat and organised UV layout against good texel distribution. 

    A very important step at this stage is to find or create a numbered UV layout grid and load it into 3DS Max.  Alternatively, 3DS Max's built-in chequed pattern can be used.

    We start by applying a planar projection to the entire mesh in order to generate some UV's. We then plan where to place UV borders by inspecting the seat's curvature. It's generally good practice to place seams in areas hidden from the player's view, or lacking prominence. It's also appropriate to place UV seams along an geometrical seams in the object being portrayed, such as along the seat's leather stitch-work.

    On this seat, seams have been placed along the back, underneath and around the beading that will be baked on from the high poly.

    After the planar projection is added to the seat, there is some pretty bad stretching across the entire object.  

    The seams are selected and broken into separate UV islands by using the Break function.   

    The islands are selected and relaxed by either edge angles or polygon angles depending upon the shape to ensure the best UV distribution across the texture map.   

    This example shows the UV islands at their most relaxed point. This means the texture map will look best with minimal stretching or distortion. This is not always ideal though as there are some strange shapes that do not fit neatly together on the map, therefore compromising UV space.   

    Where we can, it's best practice to straighten the edges, allowing UV's to be packed together better. It's preferable to tolerate slight distortion towards UV island edges by straightening their boundaries.

    This method has to be balanced though. In the two examples, you can see this principle in practice. The squarer of the shapes have straightened UV island boundaries with minimal distortion. However, this wouldn't work for the back of the seat given the extreme stretching this would produce. There is no perfect solution so discretion should be exercised at all times. The checkered pattern in scene will immediately highlight any problem areas.

    When packing UV's, it's important to use the maximum space available. The Packing tool helps scale UV islands correctly and can be used as a starting point. The numbered square texture should be uniform across the entire object. Finally these seats have to be packed into an existing interior map so figuring out the location and rotation was challenging.


    Cages are not only essential for avoiding normal map projection artefacts, but also to ensure all information from the high-poly mesh is captured in a bake correctly and without distortion. We set up assets for baking with 4 meshes in total:
    • The low-poly retopologised mesh with correct UV's and smoothing groups
    • The high-poly mesh (exported from ZBrush)
    • The decimated high-poly mesh (used in 3DS Max )
    • The cage mesh

    In order to generate the Cage mesh, we duplicate the low-polygon mesh, add a Push modifier, and increase the Push value until the entirety of the decimated HP mesh is encapsulated.  We can then fine tune the mesh by manipulating individual vertices. Using the Soft Selection tool can be useful on organic forms. The low-poly mesh and Cage are then exported to corresponding folders along with the high-poly, which is exported directly from ZBrush.

    Using XNormal to Bake   

    The meshes are loaded into xNormal, an export path is setup, and maps are generated. In terms of baking options, most things are left to default. For this 4069px x 4096px example, the Padding is set to 16, Bucket Size to 32, and Antialiasing to 4x. Renderer should use Default bucket renderer. We created 2 texture maps: a Normal Map and an Ambient Occlusion Map.

    Importing into Substance Painter 

    When setting up a new scene, we ensure the following settings are used.

    The resolution is mutable, meaning it can be changed at any time. In other words, scaling is non-destructive.

    FSW expects Albedo and Emissive maps to be Gamma-encoded, and all other maps to be in Linear-space (see: Map Formats). Care should be taken to ensure textures are setup accordingly in Substance Painter's TextureSet Settings window, and in any real-time engine used to preview the results.

    As described in the Aircraft Livery Tutorial, the 2 textures created in xNormal (Normal Map and Ambient Occlusion Map) can be drag-and-dropped into the Project section of the Shelf. After they have been loaded into the appropriate slots of the TextureSet Settings, the remaining textures are baked. Another Ambient Occlusion Map can also be created here without loading any high poly meshes into the baker. This bake will highlight occluded areas more clearly and has other uses such as providing the basis for a dirt mask. Other items such as Curvature, Thickness, Position and WSN should be baked with the high-poly and Cage loaded into the Substance Baker

    When creating textures in Substance Painter, it's recommended to work in 2K, as a 4K document can be very performance hungry especially when layers start building up.

    This next section is a breakdown of the textures used in the layer tree.

    The first material is a beige leather base. This gives us some leathery grain which diffuses the light and portrays a leather surface perturbation pattern.

    A folder is created with a cracked, grungy leather. Within this folder, we have 3 elements: the Colour, Roughness, and Height. A mask is then applied to the folder and areas prone to cracking are painted white. A mask editor is then added to all 3 of the elements inside the folder. This is used to soften the effect on the edges; the Curvature Map helps us do this.         

    The centre of the seat is coloured white-ish to create some visual contrast between the two distinct materials. This is setup with a colour fill, mask and face selection. It's still looking quite flat so to break things up further, another black fill layer is added with a MG Mask editor. This generator uses an Ambient Occlusion Map to determine where the fill colour is going to show through. This can also be controlled further by setting the generator to Multiply and painting on the actual mask. The Ambient Occlusion Map will still conform to the occluded areas of the mesh, but we now have control over where it appears.

    A slight colour variation is added to create some more contrast.

    A procedural scratch mask is added to a Height Layer, mimicking marks created when people move around on the seat. Scratches and marks are often created where sharp objects may impact the surface. Examples of sharp objects include pocket zippers, bag straps, and keys.

    More AO Grunge is added.

    Finally, a white beading is painted along the piping running along of the side of the bottom-most section.

    Exporting the Textures to Photoshop®

    Next we export the final textures from Substance Painter and arrange them in Photoshop® within allocated folders. Refer to Map Formats for more information on generating .dds files FSW can use.

    Integrating the Seats into the 3DS Max Source File

    The final seat model is integrated into the master 3DS Max file and added to the LOD tree, ready for exporting to engine. Aircraft setup and export procedures are covered in the FSW Aircraft Primer section.