第5章05节,制作法线贴图效果.
实现法线贴图应该还是用HLSL多些,,不过这个示例还是有些东西挺有用,记下备忘.
POINT pt;
GetCursorPos( &pt ); /// 获取光标的屏幕坐标.
ScreenToClient( g_hwnd, &pt ); /// 将屏幕坐标变换为客户区坐标系.
g_vLight.x = -( ( ( 2.0f * pt.x ) / WINDOW_W ) - 1 ); /// 光标的坐标值设定为﹣1~﹢1之间的值,
g_vLight.y = -( ( ( 2.0f * pt.y ) / WINDOW_H ) - 1 );
g_vLight.z = 0.0f;
if( D3DXVec3Length( &g_vLight ) > 1.0f )
D3DXVec3Normalize( &g_vLight, &g_vLight ); /// 向量单位化
else
g_vLight.z = sqrtf( 1.0f - g_vLight.x*g_vLight.x
- g_vLight.y*g_vLight.y );
这段代码获取光源向量,也就是假想的从鼠标位置射向窗口中心的方向光,这个向量通过下面的函数被转换成颜色
DWORD VectortoRGBA( D3DXVECTOR3* v, FLOAT fHeight )
{
DWORD r = (DWORD)( 127.0f * v->x + 128.0f );
DWORD g = (DWORD)( 127.0f * v->y + 128.0f );
DWORD b = (DWORD)( 127.0f * v->z + 128.0f );
DWORD a = (DWORD)( 255.0f * fHeight );
return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
}
其中x,y的值都在[-1,1]的区间里,而z值在[0,1].返回值是一个32位的颜色
最后,在Render函数中,
0号阶段的纹理是法线贴图,1号阶段的纹理是DIFFUSE贴图
DWORD dwFactor = VectortoRGBA( &g_vLight, 0.0f ); /// 向量变换为RGB
g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, dwFactor ); /// 变换为RGB的向量登录为TextureFactor值
///0号纹理阶段
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); /// 纹理的RGB和光源向量内积运算,
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3 ); /// 运算中使用内积
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );///使用上面的TextureFactor值为第二个颜色参数
///1号纹理阶段,//把第2层纹理和上面合成的纹理乘法叠加,然后再和上面合成的纹理相加
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD ); /// 合成壁面贴图纹理和法线贴图后输出
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );//DIFFUSE贴图
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );//CURRENT表示上一阶段的纹理运算结果
//透明处理,透明度以第二层纹理的透明度为准,即DIFFUSE贴图的
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
总结:法线贴图效果的制作方法如下,应该对制作HLSL的法线贴图有帮助的.
第一步:把法线贴图和光源向量转换成的颜色贴图做DOTPRODUCT运算,
第二步:用DIFFUSE贴图和第一步得出的纹理进行MULTIPLYADD运算,也就是先乘法叠加,再加上第一步纹理