Introduction

This site covers rendering related topics for the Xenoblade Chronicles Switch games. This includes Xenoblade Chronicles 1 Definitive Edition, Xenoblade Chronicles 2, and Xenoblade Chronicles 3.

The various pages provide a high level overview of important rendering techniques found in game. The goal is to provide enough information to suitably approximate these techniques in other applications and make informed decisions for modding. Some pages may briefly mention implementation details if they have important implications for what effects are possible with modding. No graphics programming experience is necessary, but some familiarity with graphics terminology like "texture" or "shader" is assumed. For specific implementation details reverse engineered from in game, see the source code for xc3_wgpu.

If you encounter any issues using or understanding the information on this site or want to request new information, please open an issue. Contributions can be made by opening a pull request on xenoblade-rendering-research.

Deferred Rendering

All of the Xenoblade games for the Switch use a rendering technique known as "deferred shading" or "deferred rendering" common in modern game engines.

In a traditional "forward" renderer, all the lighting calculations are performed upfront when drawing the object. Forward rendering is simple to implement and works well with traditional alpha blending and multisample antialiasing (MSAA). Forward rendering is common in older games with simpler graphics or games that need to target 60 fps like Smash Ultimate.

Deferred rendering, on the other hand, writes important shading parameters to screen textures or a "G-Buffer" and "defers" the actual lighting to a separate postprocessing pass. This has the advantage of only needing to calculate lighting once per pixel. This can noticeably improve performance compared to forward rendering in scenes with many lights or complex shading. Deferred rendering tends to be more memory intensive and makes it more complicated to implement effects like transparency or antialiasing. In spite of this, many modern game engines use deferred rendering for the advantages of lighting in screenspace.

Deferred rendering also has practical applications when analyzing rendering and shader code used in game. Shaders assigned to each model tend to be rather short but highly specialized since each shader only needs to write out the basic outputs in the G-Buffer for that model like color or normals. The shaders in the deferred pass are much more complex since they contain the actual lighting calculations. These shaders in the deferred pass apply to all models in the scene since they work in screenspace on the G-Buffer textures. How the game can still render different material types is explained in the Material Types page.

GBuffer

The G-Buffer or GBuffer contains all the screenspace textures used for the deferred lighting pass. This usually contains basic parameters like color and normals but can also contain more obscure values like material ID maps or motion vectors. The following sections describe the GBuffer texture layout used for all of the Xenoblade games for the Switch.

Color

GBuffer Color

Color (RGB)

The color defines the model's albedo or base color. Albedo is the overall color of an object. Surfaces with higher albedo reflect more light and appear brighter than surfaces with low albedo. This corresponds to the base color input of Blender's Principled BSDF.

??? (Alpha)

??? (Alpha)

EtcBuffer

GBuffer EtcBuffer

The EtcBuffer contains material shading parameters as well as various additional material values packed into the remaining channels.

Metalness (Red)

Metalness determines whether a surface is metallic or not and affects both specular and diffuse shading. In general, materials should be either fully metallic (1.0) or non metallic (0.0). Values in between 0.0 and 1.0 enable smoother blending between metallic and non metallic regions of a model. Non metals have a white specular color and the diffuse component is colored by the albedo. Metals have no diffuse component and specular intensity is controlled entirely by albedo.

Glossiness (Green)

The glossiness of a material is the inverse of roughness and affects the size and intensity of specular highlights. This value in game is referred to as "shininess" abbreviated to "shy" or "shiness".

Material ID (Blue)

Bit Info (Alpha)

The bit info stores a 32-bit unsigned integer flags as (float(flags) + 0.1) / 255.0.

FlagMaskDescription
matId0x3Determines material type like PBR or toon.
bSSR0x8
bSpecularCol0x10Enables the specular color texture input
bMatFlag0x20
bHatchingFlag0x30

The material type or "matType" is also referred to as "matID" in game code. In this site, "material type" will always refer to the value used to select the lighting shader and "material ID" will always refer to the value written to the etc blue channel to avoid any confusion.

Normal

GBuffer Normal

View Normal X+, Y+ (Red, Green)

The red and green channels encode the XY directions of the viewspace normals into the range 0.0 to 1.0. The actual XY values are unpacked in the deferred shading pass. The Z component can be inferred since x^2 + y^2 + z^2 = 1 for a unit normal.

Ambient Occlusion (Z)

The blue channel contains the ambient occlusion values. Ambient occlusion maps often look similar to the Z channel of a normal map, but the actual normal Z component is calculated from the normal's XY components.

??? (W)

Velocity

The velocity texture contains an encoded version of the difference in position between the current frame and the previous frame. The RGB colors are often too dark to make out clearly if the camera isn't actively moving.

Depth

GBuffer Depth

LgtColor

Material Types

Each model specific shader writes a hardcoded value to the EtcBuffer G-Buffer texture representing the material type for the shader. Each of the material types has its own shader and draw call in the deferred lighting render pass. The deferred lighting pass uses the material type to mask each shader to only affect the pixels with the appropriate material type like PBR or Toon. This means that each pixel on screen can only be assigned one of the material types below. Changing the material type for a material requires changing the assigned compiled shader code and is not configurable from material parameters.

Type 0

Type 1 (PBR)

Type 1 materials use standard PBR lighting and shading. PBR materials use a base color, glossiness, and metallic inputs.

Type 2 (Toon)

Type 2 materials use a color gradient for diffuse shading. Gradients are defined globally for all models in files like monolib/shader/toon_grad.witex. Each row of the gradient texture defines a unique RGB gradient ramp. Each model specific shader writes a value to the EtcBuffer G-Buffer texture to determine which gradient to use for rendering.

Toon shaders can also have specular shading colored by the specular output of the G-Buffer. This technique is common in Xenoblade 2 for character models.

Type 3

Type 4

Type 5 (Hair)

Xenoblade 3 defines a new material type used for hair with custom shading and a special blur filter a stylized appearance. See hair for details.

Textures

The use of deferred rendering in game has important implications for how texture types are defined. The games use fixed output texture types in the G-Buffer but not fixed input texture types. The G-Buffer textures need to have a well defined layout to work properly as inputs for the final lighting and shading calculations.

This means the type of a texture has to be determined by its usage hardcoded in the shader rather than some flag or material parameter in the model file. A "normal map" is simply any texture that is assigned to the normal output by the model's shader.

The temp textures are even more complex since each temp textures packs up to 4 grayscale textures like metalness or ambient occlusion into the RGBA color channels. This may even include textures from completely different models in the case of Xenoblade 3. In practice, most non temp textures have all their color channels assigned to a single G-Buffer texture output and have a well defined texture type like color or normal.

Some common texture types and naming conventions are summarized below. These names are simply conventions and have no impact on how a texture is actually used. For accurate texture channel assignment, use an application or plugin that uses assignment information from the shader code like xenoblade_blender.

TypeDescriptionNames
ColorRGBA color_COL
NormalXY tangent space normals_NRM
TempChannel packed parameterstemp0000, _RGB
SpecularSpecular color for toon materials_SPM, _SPC, _MTL
EmissionShadeless color that doesn't actually emit light_GLO
MaskSingle channel mask for alpha or texture blending_MSK, _ALP, _A
ReflectionIntensity map for spherical map reflections_RFM

Hair Materials

Hair SNN Blur (Xenoblade 3)

Eunie hair Eunie hair blurred

The highly detailed hair textures in Xenoblade 3 help give hair the illusion of being made up of individual strands but would appear heavily aliased in game without any filtering. The game applies a post processing blur function known as symmetric nearest neighbor (SNN) to hair materials. This reduces aliasing artifacts while also giving hair a stylized or painterly look similar to the Kuwahara or "oil paint" filters found in some image editing programs.

Blur functions typically work by computing a weighted average of a pixel and its neighboring pixels. An SNN blur function compares a pair of opposite pixels to the central pixel and picks the pixel with the most similar color to blur. This blurs similarly colored regions while still preserving some edges. The in game shader code is modified from the standard formulation to only blur horizontally. This improves performance while still preserving the vertical hair strands as long as characters are standing upright.

The game masks the blur effect to only apply to hair materials using stencil testing values defined in the model's materials. This is separate from the hair material type that is defined by the model's material parameters. Most materials in Xenoblade 3 that use the hair material type also use the correct stencil values to enable the hair blur.

Fur Materials

Fur Shells

Gramps without fur Gramps with fur

Most of the fur materials for Xenoblade 1 DE, Xenoblade 2, and Xenoblade 3 use a technique known as shell-based fur. Similar to the inverted hull technique used for outlines, the game renders increasingly scaled copies of the mesh with increasingly lower transparency to approximate the fuzzy look of fur. This technique is common in older games due to its low performance cost compared to rendering individual strands.

Each shell is translated along the normal or "inflated" to adjust its thickness. The number of shells is determined by the instance count used for instanced rendering. The instance ID is used in the calculation of the shell thickness and transparency. Gramps uses 4 shell instances in the above screenshot.

Outlines

Mio without outlines Mio with outlines

Outline rendering adds a stylized border around character models in game. The effect can be subtle in game and may only be visible in some games while zoomed in. Outlines use the "inverted hull" technique that culls the back faces of the mesh and the front faces of the outline mesh. The outline mesh is scaled along the normal or "inflated" to adjust the outline thickness.

The outline color and thickness are controlled by a vertex color attribute in a special outline buffer. The RGB components of the outline vertex color control the color of the outline. The alpha component controls the thickness of the outline by scaling the distance each point is translated along its normal. An alpha of 0.0 disables the outline completely.

Resources

  • xc3_lib - libraries and tools for working with rendering related file formats
  • xc3_model_py - Python bindings for xc3_model
  • xenoblade_blender - Blender addon for working with models, maps, and animations
  • Xenoblade Data Hub - a site with various helpful links and a link to the research discord