现在的位置: 首页 > 综合 > 正文

DirectX9.0 (10) Alpha混合

2017年10月06日 ⁄ 综合 ⁄ 共 7862字 ⁄ 字号 评论关闭

引言

            在前面几篇博文中,已经陆续讲解了光照处理,和纹理映射的内容。现在来讲解一些更有趣的东西。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可以是下面的任何值:

  • D3DBLEND_ZERO : 表示混合因子为(0,0,0,0)
  • D3DBLEND_ONE : 表示混合因子为(1,1,1,1)
  • D3DBLEND_SRCCOLOR: 表示混合因子是(rs, gs, bs, as)
  • D3DBLEND_INVSRCCOLOR : 表示混合因子是(1 - rs, 1 - gs, 1 - bs, 1 - as)
  • D3DBLEND_SRCALPHA : 表示混合因子是( as, as, as, as)
  • D3DBLEND_INVSRCALPHA : 表示混合因子是( 1 - as, 1  - as , 1 - as, 1 - as)

          除了上面讲述的,还有很多其他的混合因子,具体的可以查看DirectX附带的文档。

Alpha混合实现透明效果

          我们来讲解下,如果通过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));
}

               在上面的代码中,我们将gMaterial的Alpha值设置为0.5,在Shader中,会使用这个变量来作为最终像素的Alpha值返回,然后交给光栅化函数自动的进行Alpha混合操作,下面是本次实例的Shader文件:

//---------------------------------------------------------------------------
// 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();
	}
}

            最后是程序运行的最终结果图:

                              好了,今天就到此结束了!!!

         

抱歉!评论已关闭.