HQ Normal Maps

From Bohemia Interactive Community
Jump to navigation Jump to search

HQ Normal Maps

This technology allows normal maps compressed by various means in diverse shaders among others in shaders with specular map. Normal maps may be represented as DXT1 or swizzled DXT5, two or three components.

Motivation picture:

HQNormalSpecular.jpg

Confrontation of HQ and non HQ normal map:

HQvsNHQNormalMap.jpg


New pixel shaders

We got several pixel shaders which can work with HQ normal maps and also with specular map:

  • NormalMapSpecularMap
  • NormalMapDetailSpecularMap // function similar to NormalMapDiffuse - yet this name fits more
  • NormalMapMacroASSpecularMap
  • NormalMapDetailMacroASSpecularMap

From theirs title results what maps they use. First two match vertex shader NormalMap, second two NormalMapAS. Examples of use are here:

specular[] = {0.5,0.5,0.5,0};
specularPower = 10;
PixelShaderID = "NormalMapSpecularMap";
VertexShaderID = "NormalMap";
class Stage1
{
  texture="temp\NormalMap\normmap_NOHQ.tga";
  uvSource="tex";
};
class Stage2
{
  texture="temp\NormalMap\specmap_SM.tga";
  uvSource="tex";
};
specular[] = {0.5,0.5,0.5,0};
specularPower = 10;
PixelShaderID = "NormalMapDetailSpecularMap";
VertexShaderID = "NormalMap";
class Stage1
{
  texture="temp\NormalMap\normmap_NOHQ.tga";
  uvSource="tex";
};
class Stage2
{
  texture="temp\NormalMap\detmap_detail.paa";
  uvSource="tex";
  class uvTransform
  {
    aside[] = {3,0,0};
    up[]    = {0,6,0};
    dir[]   = {0,0,8};
    pos[]   = {0,0,0};
  };
};
class Stage3
{
  texture="temp\NormalMap\specmap_SM.tga";
  uvSource="tex";
};
specular[] = {0.5,0.5,0.5,0};
specularPower = 10;
PixelShaderID="NormalMapMacroASSpecularMap";
VertexShaderID="NormalMapAS";
class Stage1
{
  texture="temp\domek\normmap_NOHQ.tga";
  uvSource="tex";
};
class Stage2
{
  texture="temp\domek\test02_MC.tga";
  uvSource="tex1";
};
class Stage3
{
  texture="temp\domek\TestUV2_AS.tga";
  uvSource="tex1";
};
class Stage4
{
  texture="temp\domek\specmap_SM.tga";
  uvSource="tex";
};
specular[] = {0.5,0.5,0.5,0};
specularPower = 10;
PixelShaderID="NormalMapDetailMacroASSpecularMap";
VertexShaderID="NormalMapAS";
class Stage1
{
  texture="temp\domek\normmap_NOHQ.tga";
  uvSource="tex";
};
class Stage2
{
  texture="temp\domek\detmap_detail.paa";
  uvSource="tex";
  class uvTransform
  {
    aside[] = {3,0,0};
    up[]    = {0,6,0};
    dir[]   = {0,0,8};
    pos[]   = {0,0,0};
  };
};
class Stage3
{
  texture="temp\domek\test02_MC.tga";
  uvSource="tex1";
};
class Stage4
{
  texture="temp\domek\TestUV2_AS.tga";
  uvSource="tex1";
};
class Stage5
{
  texture="temp\domek\specmap_SM.tga";
  uvSource="tex";
};

Specular map

Specular map is texture with extension "_SM" which contains material information how much specularity in what place and then also it can influence locally specular sharpness (power). Texture content is used this way:

  • R - diffusion map
  • G - specular map
  • B - power map

Specular power P which is used in the end is given by term P = specularPower * B, where specularPower is set value in material. This mean if power map should not be set then it's needed adjust it to white and then only material's specular power is used.

In order that shaders were simpler (faster), then inside them is inconsiderable multiplication of specular component with coefficient, which is derived in detail analysis (related to energy preservation of specular light) and which match term ((specularPower * B + 1)/(specularPower + 1)). Practically this mean that in places where in map B isn't set to 1 then is needed to lower also G (the lower is R thereby lower must be also G)

In order that sum of diffuse and specular component was constant (which applies on usual materials), it's imposed so called diffusion map in R component. That correspond to inversion of specular map before application of possible correction mentioned in previous paragraph.

From two above mentioned paragraphs results that for specular maps (SM also SMDI) it is necessary to use following TexView filter:

comment "define specular power";
sp = 10;
p = src pixel [u,v];
x = 1 - green p;
y = green p * ((sp * blue p + 1) / (sp + 1));
c = color[x,y,blue p,1];

Example of specular map:

Specmap SM.jpg

Optimized specular map onto bit depth

New texture arisen with extension _SMDI which replaces _SM. DI means that diffusion component (formerly in R) si here derived from specular inversion (DiffuseInverse). _SMDI then writes constant 1 into R component.

This texture is possible to use in case when difusse map is just inversion of specular one. It's application provides in part better compression and afterward diffusion component will have better bit depth (G is by one bit more precise). It's necessary to use corresponding shaders to the component.

  • NormalMapSpecularDIMap
  • NormalMapDetailSpecularDIMap
  • NormalMapMacroASSpecularDIMap
  • NormalMapDetailMacroASSpecularDIMap