天天看点

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;
 }