The Diffuse Map (RGB 24 bit):

The Normal Map (RGB 24 bit):

The Specular Map (Grey Scale 8 bit):

The final result as rendered in Ogre using a GLSL single pass shader:

The GLSL Vertex Shader:

**offsetmapping.vert**

Code: Select all

```
/* Bump mapping with Parallax offset vertex program
In this program, we want to calculate the tangent space light end eye vectors
which will get passed to the fragment program to produce the per-pixel bump map
with parallax offset effect.
*/
/* Vertex program that moves light and eye vectors into texture tangent space at vertex */
// outputs
varying vec2 UV;
varying vec3 LightDir;
varying vec2 EyeDir;
varying vec3 HalfAngle;
varying vec3 Position;
// user supplied parameters
uniform vec3 lightPosition; // object space
uniform vec3 eyePosition; // object space
uniform float textureScale;
void main(void)
{
// calculate output position
gl_Position = ftransform();
Position = gl_Vertex.xyz;
// pass the main uvs straight through unchanged
UV = gl_MultiTexCoord0.st * textureScale;
// calculate tangent space light vector
// Get object space light direction
vec3 lightDir = lightPosition - gl_Vertex.xyz;
vec3 eyeDir = eyePosition - gl_Vertex.xyz;
// Calculate the binormal (NB we assume both normal and tangent are
// already normalised)
vec3 tangent = gl_MultiTexCoord1.xyz;
vec3 binormal = normalize(cross( tangent, gl_Normal ));
// Form a rotation matrix out of the vectors
mat3 rotation = mat3(tangent, binormal, gl_Normal);
// Transform the light vector according to this matrix
lightDir = normalize( lightDir * rotation );
eyeDir = normalize( eyeDir * rotation );
LightDir = lightDir;
EyeDir = eyeDir.xy;
HalfAngle = normalize(eyeDir + lightDir);
}
```

**TS_NormalSpecMapping.frag**

Code: Select all

```
// inputs from vertex shader
varying vec3 LightDir;
varying vec3 HalfAngle;
varying vec2 UV;
// user settings
uniform sampler2D normalMap;
uniform sampler2D diffuseMap;
uniform sampler2D specMap;
vec4 diffuse(vec3 N)
{
return gl_FrontMaterial.diffuse * max(dot(normalize(LightDir), N), 0.0);
}
vec4 specular(vec3 N, float spec)
{
return gl_FrontMaterial.specular * pow(max( dot( normalize(HalfAngle), N), 0.0), gl_FrontMaterial.shininess ) * spec;
}
vec3 expand(vec3 v)
{
return (v - 0.5) * 2.0;
}
void main(void)
{
// get the new normal and diffuse values
vec3 N = normalize(expand(texture2D(normalMap, UV).xyz));
vec4 texdiff = texture2D(diffuseMap, UV);
float spec = texture2D(specMap, UV).x;
gl_FragColor = texdiff * (gl_FrontMaterial.ambient + diffuse(N)) + specular(N, spec);
}
```

Code: Select all

```
// GLSL offset bump mapping
vertex_program GLSLDemo/OffsetMappingVS glsl
{
source offsetmapping.vert
}
fragment_program GLSLDemo/TSNormalSpecMappingFS glsl
{
source TS_NormalSPecMapping.frag
}
material GLSL/TSNormalSpecMapping
{
technique
{
pass
{
ambient 0.1 0.1 0.1
diffuse 0.7 0.7 0.7
specular 0.5 0.5 0.5 128
vertex_program_ref GLSLDemo/OffsetMappingVS
{
param_named_auto lightPosition light_position_object_space 0
param_named_auto eyePosition camera_position_object_space
param_named textureScale float 1.0
}
fragment_program_ref GLSLDemo/TSNormalSpecMappingFS
{
param_named normalMap int 0
param_named diffuseMap int 1
param_named specMap int 2
}
// Normal map
texture_unit
{
texture NormalMapTUT.png
tex_coord_set 0
filtering trilinear
}
// Base diffuse texture map
texture_unit
{
texture NormalMapTUTDiff.png
filtering trilinear
tex_coord_set 1
}
// spec map for shinnines
texture_unit
{
texture specMapTUT.png
filtering trilinear
tex_coord_set 2
}
}
}
}
```