天天看點

Ogre中将法線貼圖和硬體蒙皮結合

原文連結:http://www.ogre3d.org/tikiwiki/Normal+Mapping+with+Hardware+Skinning+and+Specular&structure=Cookbook

原本标題:Normal Mapping with Hardware Skinning and Specular - Combined normal mapping and hardware skinning

官網中關于法線貼圖(Normal Mapping)和置換貼圖(Displacement Mapping)的例子有很多,但是它們都不能與硬體蒙皮(Hardware Skinning)一起發揮作用。為了幫助遇到同樣問題的人,我寫了這篇文章。

使用(Usage)

隻需将animatedNormalSpecular賦予你的物體。硬體蒙皮設定為每個頂點(Vertex)綁定三個骨骼(Bone),但你可以根據自己的需要進行更改。

材質中使用了Ogre例子中的陰影片段程式(Shadow Program),如果你的資源路徑中已經包含了Ogre SDK中的media檔案夾就不必考慮這個問題,否則找到它并添加到你的資源路徑中。

材質檔案(Material File)

vertex_program AnimatedNormalSpecular_VP hlsl
 {
    source animatedNormalSpecular.hlsl
    entry_point main_vp
    target vs_2_0
    column_major_matrices false		//required for hlsl skinning
 
    includes_skeletal_animation true
 
    default_params
    {
       param_named_auto worldviewprojmatrix worldviewproj_matrix
       param_named_auto light_position light_position_object_space 0
       param_named_auto eye_position camera_position_object_space
 
       param_named_auto worldMatrix3x4Array world_matrix_array_3x4
       param_named_auto viewProjectionMatrix viewproj_matrix
       param_named_auto invworldmatrix inverse_world_matrix
    }
 }
           
fragment_program AnimatedNormalSpecular_FP hlsl
 {
 	source animatedNormalSpecular.hlsl
 	entry_point main_fp
 	target ps_2_0
 
 	default_params
 	{ 
 		param_named_auto lightDiffuse light_diffuse_colour 0
 		param_named_auto ambientLight ambient_light_colour
 		param_named_auto specularLight light_specular_colour 0
 		param_named specular_power float 64
 		param_named bumpiness float 1
 	}
 }
           
material animatedNormalSpecular
 {
 	technique
 	{
 		pass Single Pass
 		{
 			vertex_program_ref AnimatedNormalSpecular_VP
 			{
 			}
 
 			fragment_program_ref AnimatedNormalSpecular_FP
 			{
 			}
 			shadow_caster_vertex_program_ref HardwareSkinningFourShadow		//this part is in the ogre samples somewhere
 			{
 			}
 
 			//diffuse map
 			texture_unit
 			{
 				texture_alias base_map
 				texture diffuse.tga
 				filtering linear linear linear
 			}
 
 			//normal map
 			texture_unit
 			{
 				texture_alias bump_map
 				texture diffuse_normal.tga
 				filtering linear linear linear
 			}
 
 		            // specular map
 			  texture_unit specular_map
 			  {
 				texture_alias specular_map
 				texture specular.png
 			  }
 
 		}
 
 	}
 }
           

animatedNormalSpecular.hlsl

void main_vp(    
     float4 position : POSITION,
     float2 uv       : TEXCOORD0, 
     float3 normal   : NORMAL,
     float3 tangent  : TANGENT0,
 
     float4 blendIdx : BLENDINDICES,
     float4 blendWgt : BLENDWEIGHT,
 
     out float4 oPosition    : POSITION,
     out float2 oUV          : TEXCOORD0,
     out float3 oLightVector : TEXCOORD1,
     out float3 oHalfAngle   : TEXCOORD2,
 
     uniform float4x4 worldviewprojmatrix,
     uniform float4   light_position,
     uniform float4   eye_position,
     uniform float3x4 worldMatrix3x4Array[60],
     uniform float4x4 viewProjectionMatrix,
     uniform float4x4 invworldmatrix
  ) {
     // Calculate the pixel position using the perspective matrix.
     oUV = uv;   
 
     // transform by indexed matrix
     float4 blendPos = float4(0,0,0,0);
     int i;
     for (i = 0; i < 3; ++i)
     {
         blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
     }
     // view / projection
     oPosition = mul(viewProjectionMatrix, blendPos);
 
 
     // transform normal
     float3 newnormal = float3(0,0,0);
     for (i = 0; i < 3; ++i)
     {
         newnormal += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) *      blendWgt[i];
     }
     newnormal = mul((float3x3)invworldmatrix, newnormal); 
     newnormal = normalize(newnormal);
 
     // transform tangent
     float3 newtangent = float3(0,0,0);
     for (i = 0; i < 3; ++i)
     {
         newtangent += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], tangent) *      blendWgt[i];
     }
     newtangent = mul((float3x3)invworldmatrix, newtangent); 
     newtangent = normalize(newtangent);
 
 
 
 
     float3 binormal = cross(newtangent, newnormal);
     float3x3 rotation = float3x3(newtangent, binormal, newnormal);
 
     // Calculate the light vector in object space,
     // and then transform it into texture space.
     float3 temp_lightDir0 = normalize(light_position.xyz -  (blendPos * light_position.w));
     temp_lightDir0 = normalize(mul(rotation, temp_lightDir0));
     oLightVector = temp_lightDir0;
 
 
     // Calculate the view vector in object space,
     // and then transform it into texture space.
     float3 eyeDir = normalize(eye_position - blendPos);
     eyeDir = normalize(mul(rotation, eyeDir.xyz));
 
     // Calculate the half angle
     oHalfAngle = oLightVector + eyeDir;
 
 }
 
 
 
 
 
 float4 lightDiffuse ;
 float4 ambientLight;
 float4 specularLight;
 float specular_power;
 float bumpiness;
 sampler base_map;
 sampler bump_map;
 sampler specular_map;
 
 struct PS_INPUT_STRUCT
 {
    float2 uv:     TEXCOORD0;
    float3 light_vector: TEXCOORD1;
    float3 half_angle:   TEXCOORD2;
 };
 
 struct PS_OUTPUT_STRUCT
 {
    float4 color0:       COLOR0;
 };
 
 PS_OUTPUT_STRUCT main_fp( PS_INPUT_STRUCT psInStruct )
 {
    PS_OUTPUT_STRUCT psOutStruct; 
 
   float3 base = tex2D( base_map, psInStruct.uv );
   float3 bump = tex2D( bump_map, psInStruct.uv );
   float specularLevel = tex2D(specular_map, psInStruct.uv).r;
 
   //normalise
   float3 normalized_light_vector = normalize( psInStruct.light_vector );
   float3 normalized_half_angle = normalize( psInStruct.half_angle );
 
   // "Smooth out" the bump based on the bumpiness parameter.
   // This is simply a linear interpolation between a "flat"
   // normal and a "bumped" normal.  Note that this "flat"
   // normal is based on the texture space coordinate basis.
   float3 smooth = { 0.5f, 0.5f, 1.0f };
   bump = lerp( smooth, bump, bumpiness );
   bump = normalize( ( bump * 2.0f ) - 1.0f );
 
   // These dot products are used for the lighting model
   // equations.  The surface normal dotted with the light
   // vector is denoted by n_dot_l.  The normal vector
   // dotted with the half angle vector is denoted by n_dot_h.
   float4 n_dot_l = dot( bump, normalized_light_vector );
   float4 n_dot_h = dot( bump, normalized_half_angle );
 
   // Calculate the resulting pixel color,
   // based on our lighting model.
   // Ambient + Diffuse + Specular
   psOutStruct.color0.rgb =
      ( base * ambientLight) +
      ( base * lightDiffuse * max( 0, n_dot_l ) ) +
      ( specularLight * specularLevel * pow( max( 0, n_dot_h ), specular_power ) );
   psOutStruct.color0.a = 1.0f; //** Set the alpha component manually
 
   return psOutStruct;
 }