Public Functions:
normalBlend
normalBlendOriented
normalFade
normalUnpack
normalFromBaseNormal
normalFromNormal
normalFromHeight
All engine parameters useful for normal-centric operations.
//: param auto channel_height
uniform sampler2D height_texture;
//: param auto channel_normal
uniform sampler2D normal_texture;
//: param auto channel_normal_is_set
uniform bool normal_texture_is_set;
//: param auto channel_height_size
uniform vec4 height_size; // width, height, width_inv, height_inv
//: param auto texture_normal
uniform sampler2D base_normal_texture;
Used to invert the Y axis of the normal map
//: param auto normal_y_coeff
uniform float base_normal_y_coeff;
Empirically determined by our artists...
const float HEIGHT_FACTOR = 400.0;
Perform the blending between 2 normal maps
This is based on Whiteout blending http://blog.selfshadow.com/publications/blending-in-detail/
vec3 normalBlend(vec3 baseNormal, vec3 overNormal)
{
return normalize(vec3(
baseNormal.xy + overNormal.xy,
baseNormal.z * overNormal.z));
}
Perform a detail oriented blending between 2 normal maps
This is based on Detail Oriented blending http://blog.selfshadow.com/publications/blending-in-detail/
vec3 normalBlendOriented(vec3 baseNormal, vec3 overNormal)
{
baseNormal.z += 1.0;
overNormal.xy = -overNormal.xy;
return normalize(baseNormal * dot(baseNormal,overNormal) -
overNormal*baseNormal.z);
}
Returns a normal flattened by an attenuation factor
vec3 normalFade(vec3 normal,float attenuation)
{
if (attenuation<1.0 && normal.z<1.0)
{
float phi = attenuation * acos(normal.z);
normal.xy *= 1.0/sqrt(1.0-normal.z*normal.z) * sin(phi);
normal.z = cos(phi);
}
return normal;
}
Unpack a normal w/ alpha channel
vec3 normalUnpack(vec4 normal_alpha)
{
// Attenuation in function of alpha
vec3 normal = normal_alpha.a==0.0 ?
vec3(0.0,0.0,1.0) :
normal_alpha.xyz/normal_alpha.a * 2.0 - vec3(1.0);
normal = normalize(normal);
normal = normalFade(normal,normal_alpha.a);
return normal;
}
Return the tangent space normal from mesh's base normal map
vec3 normalFromBaseNormal(vec2 tex_coord)
{
// Base normal from normal imported for the mesh
vec3 baseNormal = texture2D(base_normal_texture, tex_coord).xyz * 2.0 - vec3(1.0);
baseNormal.y *= base_normal_y_coeff;
return baseNormal;
}
Return the tangent space normal from document's normal map channel
vec3 normalFromNormal(vec2 tex_coord)
{
// Normal from normal document's normal channel if present
return normal_texture_is_set ?
normalUnpack(texture2D(normal_texture, tex_coord)) :
vec3(0.0,0.0,1.0);
}
Compute the tangent space normal from document's height channel
vec3 normalFromHeight(vec2 tex_coord, float height_force)
{
vec2 dudv = height_size.zw * 0.25;
// Normal computation using height map
float h_right = texture2D(height_texture, tex_coord + vec2(dudv.x, 0.0) ).r;
float h_left = texture2D(height_texture, tex_coord + vec2(-dudv.x, 0.0) ).r;
float h_top = texture2D(height_texture, tex_coord + vec2(0.0, dudv.y) ).r;
float h_bottom = texture2D(height_texture, tex_coord + vec2(0.0, -dudv.y) ).r;
vec2 dh_dudv = vec2(
h_left - h_right,
h_bottom - h_top
) / dudv;
return normalize(vec3(
dh_dudv * height_force,
HEIGHT_FACTOR
));
}