DirectX 龙书 混合 理解

关于SetTextureStageState()这个函数,此文的理解有误,怕误导了别人,特别在这里声明一下,大家可以看最下面的那个连接,那个写的很好,我也是看了那个blog才知道我理解错了。
下面的代码可以不看了。
 
再次说说我的理解吧,一个物体是否透明,取决于它的材质,可以理解,在现实中,玻璃这种材质是透明的,而木头这种材质是不透明的,而材质中的diffuse,diffuse中的alpha就是用来调整这个材质的透明度。
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);这句话是说,现在要画的这个物体,它的alpha来自于颜色,比如这个地方的茶壶,并没有指定它使用什么纹理,而只是指定了它的材质是红色的,且材质的diffsue的alpha值是可调用的,所以它是透明的,而如果使用
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);的话,茶壶就不会有透明的效果,因为这句话是说,茶壶的透明度将来自纹理的alpha通道,因为之前设置的纹理是木板墙图片,这个图片没有alpha通道,默认值是0xffffffff,而在这个地方调整的alpha值是茶壶材质的alpha,与纹理的alpha不相干,所以,不管怎么调整这个alpha值,茶壶它都不会变的透明!
View Code
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

 

posted @ 2011-12-16 15:21  莫压枯枯地  阅读(1313)  评论(0编辑  收藏  举报