Offset (parallax) mapping - am I doing it right?

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
Post Reply
SuperNess
Kobold
Posts: 39
Joined: Wed Feb 12, 2014 12:52 am
x 9

Offset (parallax) mapping - am I doing it right?

Post by SuperNess »

So I followed this awesome tikiwiki http://www.ogre3d.org/tikiwiki/tiki-ind ... x)+Mapping to get my parallax shader working, and I made some changes to it:

1. made distance affecting the light strength (without attenuation, something simple and hard-coded)
2. made optimization to reduce passes - takes two lights every pass instead of one

anyway I'm a little new to Ogre materials system so what I'm basically asking is if someone would review it and tell me if there is room for improvement or if I'm doing something stupid there. basically it works, but I'd be happy to improve it.

also, feel free to use it.

here it is -
parallax.cg:

Code: Select all


 void OneTexture_vp(float4 position : POSITION,
           float2 uv          : TEXCOORD0,
 
           out float4 oPosition : POSITION,
           out float2 oUv       : TEXCOORD0, 
 
           uniform float4x4 worldViewProj,
           uniform float scale)
 {
     oPosition = mul(worldViewProj, position);
     oUv = uv * scale;
 }
 
 void Ambient_vp(float4 position : POSITION, 
 
           out float4 oPosition : POSITION,
           out float4 colour    : COLOR,
 
           uniform float4x4 worldViewProj,
           uniform float4 ambient)
 {
     oPosition = mul(worldViewProj, position);
     colour = ambient;
 } 
 
 
 // Expand a range-compressed vector
 float3 expand(float3 v)
 {
     return (v - 0.5) * 2;
 }
 

 
 // optimize version of the offset vertex shader which takes two lights every pass
  void Offset_Vert_Optimized(
          float4 position    : POSITION,
          float3 normal        : NORMAL,
           float2 uv        : TEXCOORD0,
           float3 tangent         : TEXCOORD1,
 
          out float4 oPosition    : POSITION,
          out float2 oUv        : TEXCOORD0,
          out float3 oLightDir1    : TEXCOORD1,
		  out float3 oLightDir2    : TEXCOORD2,
          out float3 oEyeDir     : TEXCOORD3,
          out float3 oHalfAngle1    : TEXCOORD4,
		  out float3 oHalfAngle2    : TEXCOORD5,
		  out float2 oDistanceFactor : TEXCOORD6,		// x = distance factor for light1, y = distance factor for light2
 
          uniform float scale,
          uniform float4 lightPosition1, // object space
		  uniform float4 lightPosition2, // 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;
 
	// LIGHT 1
	 oDistanceFactor.x = 1.0f / distance(position, lightPosition1);
	 if (oDistanceFactor.x > 0.001f)
	 {
		 lightDir = normalize(lightPosition1.xyz -  (position * lightPosition1.w));
		 lightDir = normalize(mul(rotation, lightDir));
		 oHalfAngle1 = normalize(eyeDir + lightDir); 
		 oLightDir1 = lightDir;
	 }
	 else
	 {
		oHalfAngle1 = 0;
		oLightDir1 = 0;
		oDistanceFactor.x = 0;
	 }
	 
	 // LIGHT 2
	 oDistanceFactor.y = 1.0f / distance(position, lightPosition2);
	 if (oDistanceFactor.y > 0.001f)
	 {
		 lightDir = normalize(lightPosition2.xyz -  (position * lightPosition2.w));
		 lightDir = normalize(mul(rotation, lightDir));
		 oHalfAngle2 = normalize(eyeDir + lightDir); 
		 oLightDir2 = lightDir;
	 }
	 else
	 {
		oHalfAngle2 = 0;
		oLightDir2 = 0;
		oDistanceFactor.y = 0;
	 }
	 
     oEyeDir = eyeDir;
 
 }
 
 
 
 // this version takes two lights every time so we'll have less passes
 void Offset_Frag_Optimized(
           float2 uv    : TEXCOORD0,
           float3 lightVec1 : TEXCOORD1,
		   float3 lightVec2 : TEXCOORD2,
           float3 eyeDir : TEXCOORD3,
           float3 halfAngle1: TEXCOORD4,
		   float3 halfAngle2: TEXCOORD5,
		   float2 distanceFactor : TEXCOORD6,
 
           out float4 oColor    : COLOR, 
 
           uniform float4 lightDiffuse1,
           uniform float4 lightSpecular1,
		   uniform float4 lightDiffuse2,
           uniform float4 lightSpecular2,
           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 spec = scaleBias.z;
     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;
	 float NdotH; 
	 float4 Lit;
 
	// LIGHT 1
	if (distanceFactor.x > 0)
	{
		 NdotL = dot(lightVec1, N);
		 NdotH = dot(normalize(halfAngle1), N); 
		 Lit = lit(NdotL,NdotH,exponent);
		 oColor = lightDiffuse1 * distanceFactor.x * Lit.y + (lightSpecular1 * spec * distanceFactor.x) * Lit.z ;
	 }
	 else
	 {
		oColor = 0;
	 }

	 
	 // LIGHT 2
	 if (distanceFactor.y > 0)
	{
		 NdotL = dot(lightVec2, N);
		 NdotH = dot(normalize(halfAngle2), N); 
		 Lit = lit(NdotL,NdotH,exponent);
		 oColor += lightDiffuse2 * distanceFactor.y * Lit.y + (lightSpecular2 * spec * distanceFactor.y) * Lit.z ;
	 }

 }
 

 
and here's my material:

Code: Select all

 
 vertex_program Offset_Vert_Optimized cg
 {
      source parallax.cg
 
      default_params
     {
         param_named_auto lightPosition1 light_position_object_space 0
		 param_named_auto lightPosition2 light_position_object_space 1
         param_named_auto eyePosition camera_position_object_space
         param_named_auto worldviewproj worldviewproj_matrix
     }  
 
     entry_point Offset_Vert_Optimized
     profiles vs_1_1 arbvp1
 }
 
 vertex_program OneTexture cg
 {
     source parallax.cg
 
     default_params
     {
         param_named_auto worldViewProj worldviewproj_matrix
     }
 
     entry_point OneTexture_vp
     profiles vs_1_1 arbvp1
 }
 
 vertex_program Ambient cg
 {
     source parallax.cg 
 
     default_params
     {
         param_named_auto worldViewProj worldviewproj_matrix
         param_named_auto ambient ambient_light_colour
     }
 
     entry_point Ambient_vp
     profiles vs_1_1 arbvp1
 }
 
 vertex_program Ogre/BasicVertexPrograms/AmbientOneTexture cg
 {
     source parallax.cg
     entry_point AmbientOneTexture_vp
     profiles vs_1_1 arbvp1
 }
 



fragment_program Offset_Frag_Default_Optimized cg
 {
     source parallax.cg 
 
     default_params
     {
         param_named_auto lightDiffuse1 light_diffuse_colour 0
         param_named_auto lightSpecular1 light_specular_colour 0
		 param_named_auto lightDiffuse2 light_diffuse_colour 1
         param_named_auto lightSpecular2 light_specular_colour 1
         param_named exponent float 127
 
         param_named scaleBias float4 0.04 -0.02 4 0 
     }  
 
     entry_point Offset_Frag_Optimized
     profiles ps_2_0 arbfp1
 }  
 

// ACTUAL USAGE:

material GrassMat
 { 
     technique
     {
         pass
         {    
             vertex_program_ref Ambient
             {
             }    
         }
         pass
         {
             // do this for each light
             iteration 1 per_n_lights 2
             scene_blend add
 
 
             // Vertex program reference
             vertex_program_ref Offset_Vert_Optimized
             {
                 param_named scale float 2
             }
             // Fragment program
             fragment_program_ref Offset_Frag_Default_Optimized
             {    
             } 
 
             // Base bump map
             texture_unit
             {
                 texture grass_NH.tga
                 filtering bilinear
             }
         }
         //Decal pass
         pass
         {
             lighting off
 
              vertex_program_ref OneTexture
             {
                 param_named scale float 2
             }   
 
             scene_blend modulate
             texture_unit
              {
                 filtering bilinear
                 texture grass.png
             }            
         }
     }   
	 
	 technique fallback
     { 
		 pass
		{
			lighting on
			
			ambient 1 1 1 1
			diffuse 1 1 1 1
			specular 1 1 1 10
			emissive 0 0 0 1
			texture_unit
              {
                 texture grass.png
				 scale 0.5 0.5
             }     
		}  
	 }	
 } 

what do you think?
I'm especially interested in ways to optimize this (although fps are pretty good, looking for something faster).

thanks :)


PS this is how it looks:
Image
Post Reply