D3DXVECTOR3 ComputeTangentVector( D3DXVECTOR3 pVtxA_p, D3DXVECTOR3 pVtxA_n, FLOAT pVtxA_tu, FLOAT pVtxA_tv,
D3DXVECTOR3 pVtxB_p, D3DXVECTOR3 pVtxB_n, FLOAT pVtxB_tu, FLOAT pVtxB_tv,
D3DXVECTOR3 pVtxC_p, D3DXVECTOR3 pVtxC_n, FLOAT pVtxC_tu, FLOAT pVtxC_tv)
{
D3DXVECTOR3 vTangent, vAB, vAC, n, vProjAB, vProjAC;
FLOAT duAB, duAC, dvAB, dvAC;
vAB = pVtxB_p - pVtxA_p;
vAC = pVtxC_p - pVtxA_p;
n = pVtxA_n;
vProjAB = vAB - ( D3DXVec3Dot( &n, &vAB ) * n );
vProjAC = vAC - ( D3DXVec3Dot( &n, &vAC ) * n );
duAB = pVtxB_tu - pVtxA_tu;
duAC = pVtxC_tu - pVtxA_tu;
dvAB = pVtxB_tv - pVtxA_tv;
dvAC = pVtxC_tv - pVtxA_tv;
if( duAC*dvAB > duAB*dvAC )
{
duAC = -duAC;
duAB = -duAB;
};
vTangent = duAC*vProjAB - duAB*vProjAC;
D3DXVec3Normalize( &vTangent, &vTangent );
return vTangent;
};
и бинормаль
struct TDoublePoints
{
D3DXVECTOR3 pnt1, pnt2;
};
...
TDoublePoints * a_pnt;
...
sdr_.shader->Lock( 0, sdr_.f_count * 3*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0 );
for(int i=0; i<sdr_.f_count; i++){
pVtxA_p = D3DXVECTOR3(pVertices->x, pVertices->y, pVertices->z);
pVtxA_n = D3DXVECTOR3(pVertices->nx, pVertices->ny, pVertices->nz);
pVtxA_tu = pVertices->tu1;
pVtxA_tv = pVertices->tv1;
pVertices++;
pVtxB_p = D3DXVECTOR3(pVertices->x, pVertices->y, pVertices->z);
pVtxB_n = D3DXVECTOR3(pVertices->nx, pVertices->ny, pVertices->nz);
pVtxB_tu = pVertices->tu1;
pVtxB_tv = pVertices->tv1;
pVertices++;
pVtxC_p = D3DXVECTOR3(pVertices->x, pVertices->y, pVertices->z);
pVtxC_n = D3DXVECTOR3(pVertices->nx, pVertices->ny, pVertices->nz);
pVtxC_tu = pVertices->tu1;
pVtxC_tv = pVertices->tv1;
if(! ( (i==sdr_.f_count-1) ) ) pVertices++;
a_pnt = new TDoublePoints;
a_pnt->pnt1 = ComputeTangentVector( pVtxA_p, pVtxA_n, pVtxA_tu, pVtxA_tv,
pVtxB_p, pVtxB_n, pVtxB_tu, pVtxB_tv,
pVtxC_p, pVtxC_n, pVtxC_tu, pVtxC_tv);
tbn->Add(a_pnt);
a_pnt = new TDoublePoints;
a_pnt->pnt1 = ComputeTangentVector( pVtxB_p, pVtxB_n, pVtxB_tu, pVtxB_tv,
pVtxA_p, pVtxA_n, pVtxA_tu, pVtxA_tv,
pVtxC_p, pVtxC_n, pVtxC_tu, pVtxC_tv);
tbn->Add(a_pnt);
a_pnt = new TDoublePoints;
a_pnt->pnt1 = ComputeTangentVector( pVtxC_p, pVtxC_n, pVtxC_tu, pVtxC_tv,
pVtxA_p, pVtxA_n, pVtxA_tu, pVtxA_tv,
pVtxB_p, pVtxB_n, pVtxB_tu, pVtxB_tv);
tbn->Add(a_pnt);
};
sdr_.shader->Unlock();
sdr_.shader->Lock( 0, sdr_.f_count * 3*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0 );
if (tbn->Count>0){
for(int i=0; i<tbn->Count; i++){
a_pnt = (TDoublePoints *)tbn->Items[i];
D3DXVec3Normalize( &a_pnt->pnt1, &a_pnt->pnt1 );
vct_ = D3DXVECTOR3(pVertices->nx, pVertices->ny, pVertices->nz);
D3DXVec3Cross( &a_pnt->pnt2, &vct_, &a_pnt->pnt1 );
...
if(! ( (i==sdr_.f_count-1) ) ) pVertices++;
};
};
sdr_.shader->Unlock();
...Код отрисовки с эффектом bump следующий:
...
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0);
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, DWORD (False));
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, sdr_.f_count);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, DWORD (True));
g_pd3dDevice->SetTexture (0, NULL);
g_pd3dDevice->SetTexture (1, NULL);
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
...
Данный алгоритм функционирует за счет того, что в поле diffuse каждой вершины обновляется информация о характере освещения - затенения. Соответственно, при каждом обновлении сцены выполняем процедуру:
void __fastcall TSpace3d::bump_shader(D3DXVECTOR3 light_pos)
{
TNamedShader sdr_;
CUSTOMVERTEX * pVertices;
D3DXVECTOR3 vct_;
TDoublePoints * a_pnt;
D3DXMATRIX worldInverse, invTangentMatrix;
D3DXVECTOR3 vCurrentVertex, vLightPosMS, vVertToLightMS, vVertToLightTS;
D3DXMatrixInverse(&worldInverse, NULL, &matWorld);
D3DXVec3TransformCoord(&vLightPosMS, &light_pos, &worldInverse);
sdr_ = shader_library->get_full_shader(mesh_name, n_clone);
sdr_.shader->Lock( 0, sdr_.f_count * 3*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0 );
if (tbn->Count>0){
for(int i=0; i<tbn->Count; i++){
a_pnt = (TDoublePoints *)tbn->Items[i];
vVertToLightMS.x = vLightPosMS.x - pVertices->x;
vVertToLightMS.y = vLightPosMS.y - pVertices->y;
vVertToLightMS.z = vLightPosMS.z - pVertices->z;
D3DXVec3Normalize(&vVertToLightMS, &vVertToLightMS);
invTangentMatrix._11 = a_pnt->pnt1.x;
invTangentMatrix._12 = a_pnt->pnt2.x;
invTangentMatrix._13 = pVertices->nx;
invTangentMatrix._14 = 0.0f;
invTangentMatrix._21 = a_pnt->pnt1.y;
invTangentMatrix._22 = a_pnt->pnt2.y;
invTangentMatrix._23 = pVertices->ny;
invTangentMatrix._24 = 0.0f;
invTangentMatrix._31 = a_pnt->pnt1.z;
invTangentMatrix._32 = a_pnt->pnt2.z;
invTangentMatrix._33 = pVertices->nz;
invTangentMatrix._34 = 0.0f;
invTangentMatrix._41 = 0.0f;
invTangentMatrix._42 = 0.0f;
invTangentMatrix._43 = 0.0f;
invTangentMatrix._44 = 1.0f;
D3DXVec3TransformNormal(&vVertToLightTS, &vVertToLightMS, &invTangentMatrix);
vct_ = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
D3DXVec3Add(&vVertToLightTS, &vVertToLightTS, &vct_);
D3DXVec3Normalize(&vVertToLightTS, &vVertToLightTS);
pVertices->color = VectortoRGBA( vVertToLightTS, 1.0f );
if(! ( (i==sdr_.f_count-1) ) ) pVertices++;
};
};
sdr_.shader->Unlock();
};
DWORD VectortoRGBA( D3DXVECTOR3 v, FLOAT fHeight )
{
DWORD r, g, b, a;
r = (DWORD)( 127.0f * v.x + 128.0f );
g = (DWORD)( 127.0f * v.y + 128.0f );
b = (DWORD)( 127.0f * v.z + 128.0f );
a = (DWORD)( 255.0f * fHeight );
return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
};