# Notes of frequency domain normal mapping vMF in The Order 1886

I have read course notes and sample codes to use frequency domain normal mapping vMF in The Order 1886.

• "Crafting a Next-Gen Material Pipeline for The Order: 1886" SIGGRAPH 2013
• Specular Antialiasing Sample by MJP

The code for adjusting roughness by length of average normal is simple. Here are some codes quoted from the course notes.

```// Quoted from "Crafting a Next-Gen Material Pipeline for The Order: 1886" SIGGRAPH 2013

float r     = length(avgNormal);
float kappa = 10000.0f;
if(r < 1.0f)
kappa = (3 * r - r * r * r) / (1 - r * r);

// New roughness
roughness = sqrt(roughness * roughness + (1.0f / kappa));```

But the tricky part is that the "roughness" parameter above code means α the "square of roughness". (α = roughness^2).

Here are some codes of frequency domain normal mapping vMF by MJP.
If you read those code, you will notice that the "roughness" parameter means α (α = roughness^2), because it is finally passed to GGX_Sppecular() and is used as α.

```// Quoted from GenerateMap.hlsl
//
// Specular Antialiasing Sample by MJP
// https://mjp.codeplex.com/releases/view/109905

...

// Pre-compute roughness map values
//
// Roughness means α (α = roughness^2)
//
vmfRoughness = sqrt(Roughness * Roughness + (1.0f / (2.0f * kappa)));
...

// Write the result to the roughness map.
// α is converted to roughness by sqrt().
// Roughness map stores roughness not α.
OutputRoughnessMap[outputPos] = sqrt(float2(vmfRoughness, toksvigRoughness));```
```// Quoted from Mesh.hlsl
//
// Specular Antialiasing Sample by MJP
// https://mjp.codeplex.com/releases/view/109905

//
#elif UsePrecomputedVMF_
// Fetch roughness from roughness map.
roughness = RoughnessMap.Sample(LinearSampler, uv).x;

// roughness to α
roughness *= roughness;
...

// Compute GGX
// roughness means α
float specular = GGX_Specular(roughness, normal, h, view, lightDir);

// the parameter m is α
float GGX_Specular(in float m, in float3 n, in float3 h, in float3 v, in float3 l)
{
float nDotH = saturate(dot(n, h));
float nDotL = saturate(dot(n, l));
float nDotV = saturate(dot(n, v));

float nDotH2 = nDotH * nDotH;
float m2 = m * m;

// Calculate the distribution term
float d = m2 / (Pi * pow(nDotH * nDotH * (m2 - 1) + 1, 2.0f));

// Calculate the matching visibility term
float v1i = GGX_V1(m2, nDotL);
float v1o = GGX_V1(m2, nDotV);
float vis = v1i * v1o;

return d * vis;
}```