原文链接: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
- }
- }
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
- }
- }
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
- }
- }
- }
- }
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;
- }
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;
}