Intro, and materials you can get from this page
Offset -> fast, multipass, unlimited-light, method
Offset_Limited3 -> fast, 1-pass, 3-light limited, method
Both support ambient, diffuse, specular lighting with 1 diffuse texture and 1 normal texture which has height info in its alpha-channel.
See Perpixel II on what "fast, nice" refers to as well as some theory.
Table of contents
Shaders: Offset mapping stuff
Copy to clipboard
//**************************************************************************************// // // // BUMP - NORMAL - OFFSET/PARALLAX - RELIEF // // MAPPING COMES NOW // // // //**************************************************************************************// // General functions // Expand a range-compressed vector float3 expand(float3 v) { return (v - 0.5) * 2; } void Offset_Vert( float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, float3 tangent : TEXCOORD1, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float3 oLightDir : TEXCOORD1, out float3 oEyeDir : TEXCOORD2, out float3 oHalfAngle : TEXCOORD3, uniform float scale, uniform float4 lightPosition, // object space uniform float3 eyePosition, // object space uniform float4x4 worldviewproj) { //why normalize lightDir if don't normalize eyeDir? both will be mul-ed //by matrix! oPosition = mul(worldviewproj , position); oUv = uv * scale; float3 eyeDir = eyePosition - position.xyz; float3 binormal = cross(tangent, normal); float3x3 rotation = float3x3(tangent, binormal, normal); eyeDir = normalize(mul(rotation, eyeDir)); float3 lightDir = normalize(lightPosition.xyz - (position * lightPosition.w)); lightDir = normalize(mul(rotation, lightDir)); oHalfAngle = normalize(eyeDir + lightDir); oLightDir = lightDir; oEyeDir = eyeDir; //changing these variables to calculate with output value and not use them doesn't yield any //boost } void Offset_Frag( float2 uv : TEXCOORD0, float3 lightVec : TEXCOORD1, float3 eyeDir : TEXCOORD2, float3 halfAngle: TEXCOORD3, out float4 oColor : COLOR, uniform float4 lightDiffuse, uniform float4 lightSpecular, uniform float exponent, uniform float4 scaleBias, uniform sampler2D normalHeightMap : register(s0) ) { float height = tex2D(normalHeightMap, uv).a; float scale = scaleBias.x; float bias = scaleBias.y; float displacement = (height * scale) + bias; float3 uv2 = float3(uv, 1); float2 newTexCoord = ((eyeDir * displacement) + uv2).xy; float3 bumpVec = expand(tex2D(normalHeightMap, newTexCoord ).xyz); float3 N = normalize(bumpVec); float NdotL = dot(normalize(lightVec), N); float NdotH = dot(normalize(halfAngle), N); float4 Lit = lit(NdotL,NdotH,exponent); oColor = lightDiffuse * Lit.y + lightSpecular * Lit.z; //do I need to normalize here the normal (=bumpvec)? } void Offset_Lim3_Vert( float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, float3 tangent : TEXCOORD1, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float3 oLightDir0 : TEXCOORD1, out float3 oLightDir1 : TEXCOORD2, out float3 oLightDir2 : TEXCOORD3, out float3 oHalfAngle0 : TEXCOORD4, out float3 oHalfAngle1 : TEXCOORD5, out float3 oHalfAngle2 : TEXCOORD6, out float3 oEyeDir : TEXCOORD7, uniform float scale, uniform float4 lightPosition0, // object space uniform float4 lightPosition1, // object space uniform float4 lightPosition2, // object space uniform float3 eyePosition, // object space uniform float4x4 worldviewproj ) { oPosition = mul(worldviewproj , position); oUv = uv * scale; float3 eyeDir = eyePosition - position.xyz; float3 binormal = cross(tangent, normal); float3x3 rotation = float3x3(tangent, binormal, normal); eyeDir = normalize(mul(rotation, eyeDir)); oEyeDir = eyeDir; float3 temp_lightDir = normalize(lightPosition0.xyz - (position * lightPosition0.w)); oLightDir0 = normalize(mul(rotation, temp_lightDir)); oHalfAngle0 = normalize(eyeDir + oLightDir0); temp_lightDir = normalize(lightPosition1.xyz - (position * lightPosition1.w)); oLightDir1 = normalize(mul(rotation, temp_lightDir)); oHalfAngle1 = normalize(eyeDir + oLightDir1); temp_lightDir = normalize(lightPosition2.xyz - (position * lightPosition2.w)); oLightDir2 = normalize(mul(rotation, temp_lightDir)); oHalfAngle2 = normalize(eyeDir + oLightDir2); } void Offset_Lim3_Frag( float2 uv : TEXCOORD0, float3 LightDir0 : TEXCOORD1, float3 LightDir1 : TEXCOORD2, float3 LightDir2 : TEXCOORD3, float3 HalfAngle0 : TEXCOORD4, float3 HalfAngle1 : TEXCOORD5, float3 HalfAngle2 : TEXCOORD6, float3 EyeDir : TEXCOORD7, out float4 oColor : COLOR, uniform float4 lightDiffuse0, uniform float4 lightDiffuse1, uniform float4 lightDiffuse2, uniform float4 lightSpecular0, uniform float4 lightSpecular1, uniform float4 lightSpecular2, uniform float exponent0, // uniform float exponent1, // uniform float exponent2, uniform float4 ambient, uniform float4 scaleBias, uniform sampler2D normalHeightMap, //: register(s0) uniform sampler2D diffuseMap ) { float height = tex2D(normalHeightMap, uv).a; float scale = scaleBias.x; float bias = scaleBias.y; float displacement = (height * scale) + bias; float3 uv2 = float3(uv, 1); float2 newTexCoord = ((EyeDir * displacement) + uv2).xy; float3 bumpVec = expand(tex2D(normalHeightMap, newTexCoord ).xyz); float3 diffusetex = tex2D(diffuseMap, newTexCoord).xyz; float3 N = normalize(bumpVec); float NdotL0 = dot(normalize(LightDir0), N); float NdotH0 = dot(normalize(HalfAngle0), N); float4 Lit0 = lit(NdotL0,NdotH0,exponent0); float NdotL1 = dot(normalize(LightDir1), N); float NdotH1 = dot(normalize(HalfAngle1), N); float4 Lit1 = lit(NdotL1,NdotH1,exponent0); float NdotL2 = dot(normalize(LightDir2), N); float NdotH2 = dot(normalize(HalfAngle2), N); float4 Lit2 = lit(NdotL2,NdotH2,exponent0); oColor = float4(diffusetex,1) * (lightDiffuse0 * Lit0.y + lightDiffuse1 * Lit1.y + lightDiffuse2 * Lit2.y) + lightSpecular0 * Lit0.z + lightSpecular1 * Lit1.z + lightSpecular2 * Lit2.z + ambient; }
Materials: Offset mapping stuff
Copy to clipboard
//**************************************************************************************// // // // BUMP - NORMAL - OFFSET/PARALLAX - RELIEF // // MAPPING COMES NOW // // (WITH TEXTURING) // //**************************************************************************************// vertex_program Offset_Vert cg { source ARNOLD.cg default_params { param_named_auto lightPosition light_position_object_space 0 param_named_auto eyePosition camera_position_object_space param_named_auto worldviewproj worldviewproj_matrix } entry_point Offset_Vert profiles vs_1_1 arbvp1 } fragment_program Offset_Frag cg { source ARNOLD.cg default_params { param_named_auto lightDiffuse light_diffuse_colour 0 param_named_auto lightSpecular light_specular_colour 0 param_named exponent float 127 param_named scaleBias float4 0.04 -0.02 1 0 //why use a float4 is I only use x and y of it? } entry_point Offset_Frag profiles ps_2_0 arbfp1 } vertex_program Offset_Lim3_Vert cg { source ARNOLD.cg default_params { param_named_auto lightPosition0 light_position_object_space 0 param_named_auto lightPosition1 light_position_object_space 1 param_named_auto lightPosition2 light_position_object_space 2 param_named_auto eyePosition camera_position_object_space param_named_auto worldviewproj worldviewproj_matrix } entry_point Offset_Lim3_Vert profiles vs_1_1 arbvp1 } fragment_program Offset_Lim3_Frag cg { source ARNOLD.cg default_params { param_named_auto lightDiffuse0 light_diffuse_colour 0 param_named_auto lightDiffuse1 light_diffuse_colour 1 param_named_auto lightDiffuse2 light_diffuse_colour 2 param_named_auto lightSpecular0 light_specular_colour 0 param_named_auto lightSpecular1 light_specular_colour 1 param_named_auto lightSpecular2 light_specular_colour 2 param_named exponent0 float 127 // param_named exponent1 float 127 // param_named exponent2 float 127 //If changed, needs adjusting in Fragshader's every lit!!!!! param_named ambient float4 0.0 0.0 0.0 1.0 param_named scaleBias float4 0.04 -0.02 1 0 } entry_point Offset_Lim3_Frag profiles ps_2_0 arbfp1 } //Any lights, offset with specular //Apart from being slow, this sax, 'cuz diffuse texture's uv's cannot be offsetted //due to the iteration (or at least I can't do it easily) //(and due to I cannot transfer data beetwen Fragshaders of different passes) material Offset { technique { pass { vertex_program_ref Ambient { } } pass { // do this for each light iteration once_per_light scene_blend add // Vertex program reference vertex_program_ref Offset_Vert { param_named scale float 5 } // Fragment program fragment_program_ref Offset_Frag { } // Base bump map texture_unit { texture CC-slateb_NH.dds filtering trilinear //filtering anisotropic //max_anisotropy 3 //colour_op replace } } //Decal pass pass { lighting off vertex_program_ref OneTexture { param_named scale float 5 } scene_blend modulate texture_unit { //filtering anisotropic //max_anisotropy 3 filtering trilinear texture CC-slateb.dds } } } } material Offset_Limited3 { technique { // pass // { // vertex_program_ref Ambient // { // } // } pass { // do this for each light // iteration once_per_light // scene_blend add // Vertex program reference vertex_program_ref Offset_Lim3_Vert { param_named scale float 5 // param_named lightnum float 2 } // Fragment program fragment_program_ref Offset_Lim3_Frag { // param_named lightnum float 2 } // Base bump map texture_unit { texture CC-slateb_NH.dds filtering trilinear //filtering anisotropic //max_anisotropy 3 //colour_op replace } texture_unit { //filtering anisotropic //max_anisotropy 3 filtering trilinear texture CC-slateb.dds } } } }