DirectX 龙书 混合 理解
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);的话,茶壶就不会有透明的效果,因为这句话是说,茶壶的透明度将来自纹理的alpha通道,因为之前设置的纹理是木板墙图片,这个图片没有alpha通道,默认值是0xffffffff,而在这个地方调整的alpha值是茶壶材质的alpha,与纹理的alpha不相干,所以,不管怎么调整这个alpha值,茶壶它都不会变的透明!
bool DXSetup()
{
/*******************************************************************************************
* 背景墙
*******************************************************************************************/
// 创建顶点
g_pd3dDevice->CreateVertexBuffer(
6 * sizeof(DX7Vertex),
D3DUSAGE_WRITEONLY,
DX7Vertex::FVF,
D3DPOOL_MANAGED,
&BkGndQuad,
0);
DX7Vertex* v;
BkGndQuad->Lock(0, 0, (void**)&v, 0);
// quad built from two triangles, note texture coordinates:
v[0] = DX7Vertex(-6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[1] = DX7Vertex(-6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[2] = DX7Vertex( 6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[3] = DX7Vertex(-6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[4] = DX7Vertex( 6.0f, 6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[5] = DX7Vertex( 6.0f, -6.0f, 5.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
BkGndQuad->Unlock();
// 设置过滤器
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); // 设置Mipmaps过滤器
// 创建并使用纹理
D3DXCreateTextureFromFile(g_pd3dDevice, "..\\Texture\\256.bmp", &BkGndTex);
BkGndMtrl = WHITE_MTRL;
/*******************************************************************************************
* 物体
*******************************************************************************************/
// 茶壶材质
::ZeroMemory(&TeapotMtrl, sizeof(TeapotMtrl));
TeapotMtrl.Ambient = RED;
TeapotMtrl.Diffuse = RED;
TeapotMtrl.Specular = RED;
TeapotMtrl.Emissive = BLACK;
TeapotMtrl.Power = 10.0f;
// 茶壶物体
D3DXCreateTeapot(g_pd3dDevice, &Teapot, NULL); // 画一个茶壶
// 灯光默认为True
//g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
// 设置摄影机
D3DXVECTOR3 position(0.0f, 0.0f, -3.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX camera;
D3DXMatrixLookAtLH(&camera,&position, &target, &up);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &camera);
/*******************************************************************************************
* 场景、灯光、摄影机&可视体设置
*******************************************************************************************/
// 设置灯光
D3DLIGHT9 dir;
::ZeroMemory(&dir, sizeof(dir));
dir.Type = D3DLIGHT_POINT;
dir.Diffuse = WHITE;
dir.Specular = WHITE * 0.3f;
dir.Ambient = WHITE * 0.6f;
dir.Position = D3DXVECTOR3(10.0f, 10.0f, -10.0f);
dir.Range = 100;
g_pd3dDevice->SetLight(0, &dir);
g_pd3dDevice->LightEnable(0, true);
g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
// use alpha in material's diffuse component for alpha
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
// set blending factors so that alpha
// component determines transparency
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
// 设置投影矩阵
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f, // 90 - degree
(float)Width / (float)Height,
1.0f,
1000.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Render()
{
// keyboard message process -->>
// increase/decrease alpha via keyboard input
if (::GetAsyncKeyState('A') & 0x8000f)
TeapotMtrl.Diffuse.a += 0.01f;
if (::GetAsyncKeyState('S') & 0x8000f)
TeapotMtrl.Diffuse.a -= 0.01f;
// force alpha to[0,1] interval
if (TeapotMtrl.Diffuse.a > 1.0f)
TeapotMtrl.Diffuse.a = 1.0f;
if (TeapotMtrl.Diffuse.a < 0.0f)
TeapotMtrl.Diffuse.a = 0.0f;
// keyboard message process <<--
static float angle = 0.0f;
angle += 0.02f;
if (angle > 6.48)
{
angle = 0;
}
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0x00,200,200,200), 1.0f, 0);
g_pd3dDevice->BeginScene();
// rendering of scene objects happens here
// 画纹理背景墙
D3DXMATRIX priCode;
D3DXMatrixIdentity(&priCode);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &priCode);
g_pd3dDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
g_pd3dDevice->SetStreamSource(0, BkGndQuad, 0, sizeof(DX7Vertex));
g_pd3dDevice->SetMaterial(&BkGndMtrl); // 设置材质
g_pd3dDevice->SetTexture(0, BkGndTex); // 设置纹理
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
// 画Mesh
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
g_pd3dDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL);
g_pd3dDevice->SetMaterial(&TeapotMtrl); // 设置材质(并没有设置纹理,但是效果却是与纹理混合的效果,因为前面设置了纹理)
Teapot->DrawSubset(0);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
g_pd3dDevice->EndScene();
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
说说我对SetTextureStageState这个函数的理解,在这个例子中只出现了下面这两种用法
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
首先关于混合,用下面的函数
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
指定了源混合因子与目标混合因子,画茶壶的时候调用
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
将混合应用打开
画茶壶的时候,用公式:OutputPixel=SourcePixel 叉乘 SourceBlendFactor + DestPixel 叉乘 DestBlendFactor来计算目标像素的值
现在,在场景中只画出一个灰色的背景墙和一个茶壶(先不画木板纹理墙),灰色的背景墙的颜色值为D3DCOLOR_ARGB(0x00,200,200,200)
使用SetRenderState()指定源与目标混合因子,但是,此时不使用SetTextureStageState()这个函数,OK,来画一个茶壶吧,像上面贴的代码中那样,使用A和S键可以控制这个茶壶的透明度。
现在,在刚才的场景中增加画一个木板纹理墙,使用SetRenderState()指定源与目标混合因子,还是不使用SetTextureStageState()这个函数,这个时候你会发现,A与S键无法控制茶壶的透明度了!
现在把SetTextureStageState()调用打开(Setup中调用,或者画茶壶之前调用都行)
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
这个时候再运行,发现A与S键又可以控制茶壶的透明度了!
OK,小结一下,SetTextureStageState(),这个函数的设置就是与那个纹理背景墙相关的!我和理解如下:
先说说不使用SetTextureStageState()这个函数的情况吧。
我的纹理背景墙的图片是没有alpha通道的,它只有24位颜色值,先画纹理背景墙,再画茶壶的时候,要用上面的那个公式来计算输出像素,可是DestPixel是24位的,没有alpha值,而公式中计算的要求是32位的,所以,计算失败!而最终使用的像素颜色值还是茶壶自身的像素颜色值。
调用SetTextureStageState()这个函数,它的用意就是:
指定DestPixel的alpha从哪里来的!
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
这句话是说,在混合的时候,如果目标像素颜色值没有alpha值话,那么,目标像素的alpha值将从它的颜色值中计算出来!这样,画茶壶的时候,用公式来计算混合出的目标颜色时,目标像素就有了alpha值,而公式计算有效!就出现了茶壶在纹理背景墙上可以调整透明度!
而g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);这句话,就是说,使用D3DTSS_ALPHAARG1指定的值,即,D3DTA_DIFFUSE.
OK,那什么,不画背景纹理墙,只画一个灰色背景的时候,在不使用SetTextureStageState()的情况下就可以调用茶壶的透明度呢,因为灰度的背景墙是有alpha值的,这个地方我设置为0x00,其实,你设置成任何数值,茶壶都是在可以在灰色背景墙上调整透明度的!
我觉得自己很罗嗦,OK,索性罗嗦到底吧。
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
这个函数就是用来指定,那个纹理背景墙中的alpha到底从哪里来的!
关于这部分内容,这个文章写的很好!
http://www.cppblog.com/kesalin/archive/2008/03/23/45183.html