Fundamentals (about FaceGen) - lexlayer93/FaceSouls GitHub Wiki
To generate faces, FromSoftware's character creator uses FaceGen software. The complete documentation (though somewhat confusing and error-prone) can be found at the link above. I will summarize this documentation, focusing only on aspects relevant to character creation, using slightly modified notation that requires knowledge about linear algebra. FaceGen defines a face as a set of vertices in three dimensions, connected by a mesh of triangles and quads. Instead of storing all vertex positions, it builds faces using standard deviations, called principal components or modes, relative to an average reference face. By default, there are $N_s = 50$ symmetric modes and $N_a = 30$ asymmetric modes. The vertices $\mathbf{v}_i$ of a face are defined by:
\mathbf{v}_i = \mathbf{\bar v}_i + \sum_{j=1}^{N_s} s_j \mathbf{v}_i^j + \sum_{j=1}^{N_a} a_j \mathbf{u}_i^{j}
Where:
- $\mathbf{\bar v}_i$ are the vertices of the reference face, stored in the .TRI file.
- $\mathbf{v}_i^j$ and $\mathbf{u}_i^j$ are symmetric and asymmetric displacements for vertex $i$ and mode $j$, stored in the .EGM file.
- $s_j$ and $a_j$ are symmetric and asymmetric coefficients for each mode, defined in the .CTL file for each control.
Ignoring asymmetric components (unavailable in the character creator), a face can be considered as a column vector $\mathbf{s}$ of 50 symmetric coefficients/coordinates in an abstract face space where $\mathbf{s} = 0$ represents the reference face. Typical coordinate values range from -5 to +5 (but can exceed these) as single-precision floats. In the character creator, these coordinates are adjusted via sliders (whose range are 0–255 in UI, -10 to +10 internally) rather than directly modified.
Age and Gender controls
To calculate age (Apparent Age) and gender (Facial Aesthetic):
\begin{align}
q_a &= o_a + \mathbf{c}_a^\intercal\,\mathbf{s} \\
q_g &= o_g + \mathbf{c}_g^\intercal\,\mathbf{s}
\end{align}
Age ranges from 15–60, gender from -4 (masculine) to +4 (feminine). Here:
- $o_a$ and $o_g$ are age/gender offsets (reference values).
- $\mathbf{c}_a$ and $\mathbf{c}_g$ are age/gender control vectors.
Adjusting sliders updates the face via:
\mathbf{s}^\prime = \mathbf{s} + \lambda_a \mathbf{c}_a + \lambda_g \mathbf{c}_g
New age/gender values become:
\begin{align}
q_a^\prime &= q_a + \lambda_a \mathbf{c}_a^\intercal \mathbf{c}_a + \lambda_g \mathbf{c}_a^\intercal \mathbf{c}_g \\
q_g^\prime &= q_g + \lambda_a \mathbf{c}_g^\intercal \mathbf{c}_a + \lambda_g \mathbf{c}_g^\intercal \mathbf{c}_g
\end{align}
To set specific age/gender values without mutual interference:
\begin{bmatrix} \lambda_a \\ \lambda_g\end{bmatrix} = \begin{bmatrix}\|\mathbf{c}_a\|^2 & \mathbf{c}_a^\intercal\mathbf{c}_g \\\mathbf{c}_g^\intercal\mathbf{c}_a&\|\mathbf{c}_g\|^2 \\\end{bmatrix}^{-1}\cdot\begin{bmatrix}q_a^\prime - q_a \\ q_g^\prime - q_g\end{bmatrix}
Where it is necessary to calculate the inverse of the so-called age and gender covariance matrix.
Caricature control
The caricature (Form Emphasis) value is the Mahalanobis distance from a race-specific mean:
q_c = \frac{\|\mathbf{M}\,(\Delta\mathbf{s}-\Delta s_{ag})\|}{\sqrt{N_s-2}}
Typical range: 0.01–2. Here:
- $\mathbf{M}$: geo density matrix from .CTL.
- $\Delta\mathbf{s} = \mathbf{s}-\mu$: deviation from race-specific mean (character creator uses the generic ALL race).
- $
\Delta \mathbf{s}_{ag} = \mathbf{P}_{ag}(\mathbf{s}-\mu)
$: projection onto age/gender subspace.
Adjusting the caricature slider updates the face as:
\mathbf{s}^\prime = \mu + \frac{q_c'}{q_c}\left(\Delta\mathbf{s}-\Delta \mathbf{s}_{ag}\right)+\Delta \mathbf{s}_{ag}
The projection matrix $\mathbf{P}_{ag}$ is defined by Gram-Schmidt orthogonalization:
\mathbf{P}_{ag}= \mathbf{\hat c}_a\mathbf{\hat c}_a^\intercal+\mathbf{\hat c}_g\mathbf{\hat c}_g^\intercal
Where $\mathbf{\hat c}_a$ and $\mathbf{\hat c}_g$ are orthogonal unit vectors given by:
\begin{align}
\mathbf{\hat c}_a &= \dfrac{\mathbf{c}_a}{\| \mathbf{c}_a\|} \\
\mathbf{\hat c}_g &= \dfrac{\mathbf{c}_g-\mathbf{\hat c}_a(\mathbf{\hat c}_a^\intercal \mathbf{c}_g)}{\|\mathbf{c}_g-\mathbf{\hat c}_a(\mathbf{\hat c}_a^\intercal \mathbf{c}_g)\|}
\end{align}
Other controls
For other sliders, their values are just the dot product of face with control vector:
q_i = \mathbf{c}_i^\intercal \mathbf{s}
where $\|\mathbf{c}_i\| = 1
$ (unit vectors). Adjusting a slider updates the face via:
\mathbf{s}^\prime = \mathbf{s} + (q_i^\prime - q_i)\,\mathbf{c}_i
These controls are interdependent: modifying one affects others, including age, gender, and caricature.
Skin color
The reference face includes a base texture/picture (RGB values per pixel). As vertices, pixel colors follow:
\mathbf{v}_i = \mathbf{\bar v}_i + \sum_{j=1}^{N_s} s_j \mathbf{v}_i^j + \sum_{j=1}^{N_a} a_j \mathbf{u}_i^{j}
Texture displacements are defined in .EGT, and pixel positions in .FIM. Thus, textures are vectors $\mathbf{t}$ defined by 50 symmetric coefficients/coordinates, where $\mathbf{t} = 0$ is the base texture. Age, gender and caricature controls also affect skin color but use different vectors ($\mathbf{c}_a$, $\mathbf{c}_g$), offsets ($o_a$, $o_g$), and mean ($\mu$).