在前面几篇博文中,已经陆续讲解了光照处理,和纹理映射的内容。现在来讲解一些更有趣的东西。Alpha混合,总是出现在各种各样的游戏中。我们无时无刻都在和它进行打交道,所以很有必要掌握如何进行Alpha混合,以及如何通过Alpha混合来做到透明效果。
进行Alpha混合时,我们总是会利用混合方程来进行混合。一般来说,混合方程总是如下所示:
OutputPixel = SourcePixel * SourceBlendFactor + DestPixel * DestBlendFactor
这个方程很简单,而且其中的"+"操作符,也能够在DirectX中,通过设置渲染状态来改变这个值。我们进行Alpha混合的时候,就是设置这些值来对Alpha混合进行控制。
在默认情况下,Alpha混合方程中的操作符总是“+”,它在DirectX中使用如下的常量来定义:
D3DBLENDOP_ADD
除了这个操作符之外,还有下面的一些操作符:
D3DBLENDOP_SUBTRACT 表示操作符是“-”, 即混合方程为 OutputPixel = SourcePixel * SourceBlendFactor - DestPixel * DestBlendFactor ;
D3DBLENDOP_REVSUBTRACT, 混合方程为 : OutputPixel = DestPixel * DestBlendFactor - SourcePixel * SourceBlendFactor ;
D3DBLENDOP_MIN , 混合方程为 : OutputPiexl = min(SourcePixel * SourceBlendFactor, DestPixel * DestBlendFactor) ;
D3DBLENDOP_MAX, 混合方程为: OutputPiexl = max(SourcePixel * SourceBlendFactor, DestPixel * DestBlendFactor) ;
我们可以通过调用下面的函数来设置这些混合操作符:
m_pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT) ;
这些操作符的具体含义很难察觉,它们只是定义了进行混合计算时的不同操作,使用不同的操作符可以达到不同的效果,需要读者自己积累经验来使用。
在默认情况下,DirectX 9.0是不进行Alpha混合操作的,所以我们可以通过如下的代码来开启Alhpa混合:
m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true) ;
在上面的混合公式中,SourceBlendFactor和DestBlendFactor称为混合因子。我们可以通过调用下面的两个函数来设置这两个不同的因子:
m_pDevice->SetRenderState(D3DRS_SRCBLEND, source) ;
m_pDevice->SetRenderState(D3DRS_DESTBLEND, dest) ;
上面的source和dest可以是下面的任何值:
除了上面讲述的,还有很多其他的混合因子,具体的可以查看DirectX附带的文档。
我们来讲解下,如果通过Alpha混合来实现透明效果。
一个物体想要透明,在计算机图形学上,就是依靠于将需要进行透明处理的物体与背景上的像素值进行Alpha混合,从而达到透明的效果。而为了达到这样的效果,我们必须确保,不透明的物体要先被绘制出来,然后才能够绘制透明物体。因为不透明的物体后绘制出来的话,就没有办法进行Alpha混合,从而达到透明效果。
进行透明效果的Alpha混合公式如下:
OutputPiexl = SourcePiexl * SourceAlphaChannel + DestPiexl * (1 - SourceAlphaChannel)
所以,我们只要对需要进行Alpha混合的物体,调用上面讲述的方法,开启Alpha混合,并且将混合因子设置为D3DBLEND_SRCALPHA, 和 D3DBLEND_INVSRCALPHA,就可以了。
下面就是进行Alpha混合的绘制代码:
void CubeDemo::draw() { //Set the vertex declaration HR(m_pDevice->SetVertexDeclaration(VertexPNT::_vertexDecl)); //Set the vertex buffer HR(m_pDevice->SetStreamSource(0,m_pVertexBuffer,0,sizeof(VertexPNT))); //Set the index buffer HR(m_pDevice->SetIndices(m_pIndexBuffer)); //Create the world matrix D3DXMATRIX _worldM ; D3DXMatrixIdentity(&_worldM); //Set the technique HR(m_pEffect->SetTechnique(m_hTechnique)); //Set the gWVP matrix D3DXHANDLE _hWVP = m_pEffect->GetParameterByName(0, "gWVP"); HR(m_pEffect->SetMatrix(_hWVP, &(_worldM* m_ViewMatrix* m_ProjMatrix))); //Set the gWorld matrix HR(m_pEffect->SetMatrix(m_gWorld, &_worldM)); //Set the gInverseTranspose D3DXMatrixInverse(&_worldM,NULL, &_worldM); D3DXMatrixTranspose(&_worldM, &_worldM); HR(m_pEffect->SetMatrix(m_gInverseTranspose, &_worldM)); //Set the gPower static float power = 5.0f; HR(m_pEffect->SetValue(m_gPower,&power,sizeof(float))); //Set the gMaterial HR(m_pEffect->SetVector(m_gMaterial,&D3DXVECTOR4(0.5, 0.7, 0.0, 0.5))); //Set the gLightColor HR(m_pEffect->SetVector(m_gLightColor, &D3DXVECTOR4(0.8, 0.8, 0.8, 1.0))); //Set the gLightVector D3DXVECTOR4 lightVector ; D3DXVec4Normalize(&lightVector, &D3DXVECTOR4(1,1,1,0)); HR(m_pEffect->SetVector(m_gLightVector, &lightVector)); //Set the gSpecularLightColor HR(m_pEffect->SetValue(m_gSpecularLightColor, &D3DXCOLOR(1.0,1.0,1.0,1.0), sizeof(D3DXCOLOR))); //Set the gSpecularMaterial HR(m_pEffect->SetValue(m_gSpecularMaterial, &D3DXCOLOR(0.2,0.2,0.2,1.0), sizeof(D3DXCOLOR))); //Set the gAmbientLightColor HR(m_pEffect->SetValue(m_gAmbientLightColor, &D3DXCOLOR(1.0,1.0,1.0,0.0),sizeof(D3DXCOLOR))); //Set the gAmbientMaterial HR(m_pEffect->SetValue(m_gAmbientMaterial, &D3DXCOLOR(0.5,0.5,0.5,0.0), sizeof(D3DXCOLOR))); //Set the gTex HR(m_pEffect->SetTexture(m_gTex, m_pTexture)); //Begin pass UINT _pass = 0 ; HR(m_pEffect->Begin(&_pass, 0)); HR(m_pEffect->BeginPass(0)); //Draw the primitive drawCube(); //Draw the teapot drawTeapot(); //End pass HR(m_pEffect->EndPass()); HR(m_pEffect->End()); }
void CubeDemo::drawCube() { m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,24,0, 12); } void CubeDemo::drawTeapot() { //Enable the alpha blend HR(m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true)); HR(m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA)); HR(m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA)); D3DXMATRIX _worldM; D3DXMatrixTranslation(&_worldM,0,0,-5); HR(m_pEffect->SetMatrix(m_gWVP, &(_worldM* m_ViewMatrix* m_ProjMatrix))); //Set the gWorld matrix HR(m_pEffect->SetMatrix(m_gWorld, &_worldM)); //Set the gInverseTranspose D3DXMatrixInverse(&_worldM,NULL, &_worldM); D3DXMatrixTranspose(&_worldM, &_worldM); HR(m_pEffect->SetMatrix(m_gInverseTranspose, &_worldM)); //Commit the changes HR(m_pEffect->CommitChanges()); HR(m_TeaportMesh->DrawSubset(0)); HR(m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false)); }
//--------------------------------------------------------------------------- // declaration : Copyright (c), by XJ , 2014 . All right reserved . // brief : This file will define the Texture_Direction Shader. // date : 2014 / 5 / 29 //---------------------------------------------------------------------------- uniform float4x4 gWVP ; //这个变量将会保存世界变换矩阵*相机变换矩阵*透视投影矩阵的积 //用这个矩阵,将点转化到裁剪空间中去 uniform float4x4 gInverseTranspose; //这个变量将会保存世界变换矩阵的逆矩阵*转置矩阵,用来对法向量进行变换 uniform float4 gMaterial; //这个变量用来保存顶点的材质属性,在本Demo中,将对所有的顶点使用相同的 //材质 uniform float4 gLightColor; //这个变量将用来保存一个平行光的颜色 uniform float3 gLightVector; //这个变量用来保存平行光的光照向量 uniform float4x4 gWorld; //这个变量保存世界变换,用来对模型坐标进行变换,从而计算视向量 uniform float3 gEye; //这个变量保存视点的位置,也就是相机的位置 uniform float gPower ; //这个变量将会控制反射光的衰减速度 uniform float4 gSpecularLightColor; //反射光颜色 uniform float4 gSpecularMaterial; //物体对反射光的材质属性 uniform float4 gAmbientLightColor; //环境光颜色 uniform float4 gAmbientMaterial; //物体对环境光的材质属性 uniform extern texture gTex ; //定义纹理 //定义采样器 sampler TexS = sampler_state { Texture = <gTex> ; MinFilter = LINEAR ; MagFilter = LINEAR ; MipFilter = LINEAR ; }; //定义顶点着色的输入结构体 struct OutputVS { float4 posH : POSITION0 ; float2 tex0 : TEXCOORD0 ; float3 normalW : TEXCOORD1 ; float3 posW : TEXCOORD2 ; }; OutputVS TextureVS(float3 posL: POSITION0, float3 normalL: NORMAL0, float2 tex:TEXCOORD0) { //清空OutputVS OutputVS outputVS = (OutputVS) 0 ; //对顶点的法向向量进行变换 normalL = normalize(normalL); float3 normalW = mul(float4(normalL, 0.0f), gInverseTranspose).xyz; normalW = normalize(normalW); //保存法相向量 outputVS.normalW = normalW ; //保留顶点的世界坐标 float3 posW = mul(float4(posL, 1.0), gWorld).xyz ; outputVS.posW = posW ; //使用gWVP将世界坐标转化为裁剪坐标 outputVS.posH = mul(float4(posL, 1.0f), gWVP); //保存纹理坐标 outputVS.tex0 = tex ; //返回结果 return outputVS ; }// end for Vertex Shader float4 TexturePS(float2 tex0:TEXCOORD0, float3 normalW:TEXCOORD1, float3 posW:TEXCOORD2): COLOR { //-------------------------------------------------- // 光照计算 //-------------------------------------------------- //进行插值后,法相向量不再是归一化的,重新进行归一化操作 normalW = normalize(normalW); //根据漫反射公式: // Color = max(L * Normal, 0)*(LightColor*Material) float s = max(dot(gLightVector,normalW), 0); float3 diffuse = s*(gMaterial*gLightColor).rgb ; //根据环境光公式: // Color = AmbientColor * AmbientMaterial float3 ambient = (gAmbientLightColor * gAmbientMaterial).rgb ; //根据反射光公式: // Color = pow((max(dot(r,v),0)),p) * (SpecularLightColor*SpecularMaterial) float3 view = gEye - posW ; view = normalize(view); float3 ref = reflect(-gLightVector, normalW); float t = pow(max(dot(ref,view),0),gPower); float3 specular = t * (gSpecularLightColor * gSpecularMaterial).rgb ; //-------------------------------------------------------------------- // 获取纹素 //-------------------------------------------------------------------- float3 pixel_color = tex2D(TexS, tex0).rgb; diffuse = (diffuse + ambient) * pixel_color ; return float4(diffuse + specular, gMaterial.a) ; }// end for Pixel Shader technique TextureTech { pass P0 { vertexShader = compile vs_2_0 TextureVS(); pixelShader = compile ps_2_0 TexturePS(); } }
好了,今天就到此结束了!!!