Alpha混合用的就是Programming.Role.Playing.Games.with.DirectX书上的例子,因为一时想不到什么好的,还是跟以前一样,加了个Shader实现的。还是老规则,左边的是用固定管线实现的,右边是用Shader实现的。右边的变化还是比较明显的。
代码是在之前Draw2D上修改的,这样快速,不需要在关心这个初始化,那个初始化来着,之前有忘记说,如果顶点格式设置为D3DFVF_XYZRHW格式话,顶点坐标就是2D坐标,不是3D坐标,这点要搞清楚,而且坐标原点是左上角。
开启和关闭Alpha混合,很简单调用SetRenderState(D3DRS_ALPHABLENDENABLE, bIsEnable),bIsEnable是bool值,是否开启。
来看下渲染的代码:
固定管线:
void ModelClass::Render(IDirect3DDevice9* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
// Disable the alpha blending of rendering the back
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
// Enable the alpha bleding of the rendering the front
device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
// Dont't forget to disable the alpha blending
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
}
首先我们先关闭Alpha混合,渲染不透明的Square,再开启Alpha混合,渲染透明的Rectangle,记住关闭Alpha混合,不然你是感受不到Shader中是否开启AlphaBlend功能。注意SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA)和SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA),很多书上都会说源颜色和源混合因子相乘,加上目标颜色和目标混合因子相乘,就为输出结果。其实一开始会很不明白的,理解好的人会很快,我是花了很多时间才搞懂的,先看Shader,我再来简单说下。
Shader渲染:
void ShaderModelClass::Render(IDirect3DDevice9* device, float time, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
bool result;
UINT passMaxNum;
device->SetStreamSource(0, m_vertexBuffer, 0, sizeof(VertexType));
device->SetFVF(VERTEX_FVF);
result = m_colorShader->Render(device, time, worldMatrix, viewMatrix, projectionMatrix);
if (!result)
return;
m_colorShader->GetEffect()->Begin(&passMaxNum, 0);
for (UINT pass = 0; pass < passMaxNum; ++pass)
{
m_colorShader->GetEffect()->BeginPass(pass);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_colorShader->GetEffect()->EndPass();
}
m_colorShader->GetEffect()->End();
result = m_alphaBlendShader->Render(device, time, worldMatrix, viewMatrix, projectionMatrix);
if (!result)
return;
m_alphaBlendShader->GetEffect()->Begin(&passMaxNum, 0);
for (UINT pass = 0; pass < passMaxNum; ++pass)
{
m_alphaBlendShader->GetEffect()->BeginPass(pass);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
m_alphaBlendShader->GetEffect()->EndPass();
}
m_alphaBlendShader->GetEffect()->End();
}
这里我用了2个shader,一个用于渲染不透明的,另一个则用于渲染透明的,代码很简单,就不多说了。不透明渲染的shader就是之前Draw2D的shader,所以不在重复。
透明Shader:
float time;
float4x4 worldMatrix;
float4x4 viewMatrix;
float4x4 projectionMatrix;
struct VertexInputType
{
float4 vertex : POSITION;
float4 color : COLOR0;
};
struct PixelInputType
{
float4 pos : POSITION;
float4 color : COLOR0;
};
PixelInputType AlphaBlendVertexShader(VertexInputType input)
{
PixelInputType output;
output.pos = input.vertex;
output.color = input.color;
return output;
}
float4 AlphaBlendPixelShader(VertexInputType input) : COLOR
{
float4 color = input.color;
return color;
}
technique ShaderTechnique
{
pass pass0
{
AlphaBlendEnable = true;
BlendOp = ADD;
//BlendOp = Subtract;
//BlendOp = RevSubtract;
//BlendOp = Min;
//BlendOp = Max;
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha;
VertexShader = compile vs_2_0 AlphaBlendVertexShader();
PixelShader = compile ps_2_0 AlphaBlendPixelShader();
}
}
与不透明不同的地方就在于标红的地方,记得上面用固定管线渲染的时候说过要关闭Alpha混合吗?这边就是用Effect来开启Alpha混合,简不简单。
上面不是说源颜色和源混合因子相乘,加上目标颜色和目标混合因子相乘,就为输出结果。这里就来详细的介绍下。看到BlendOp = Add了吗?这里设置就是表示源颜色和源混合因子相乘,加上目标颜色和目标混合因子相乘,如果改成Subtract,就是表示源颜色和源混合因子相乘,减去目标颜色和目标混合因子相乘,可以取消注释试试。
接着说下源颜色和目标颜色,这里你可以理解为源颜色就是当前像素的颜色也就是像素着色器(PixelShader)生成的颜色,也是我们创建模型时赋予的颜色值,未做任何修改。目标颜色也就是颜色缓存中的颜色,源混合因子SrcAlpha就是像素着色器(PixelShader)生成的颜色中的Alpha值,也就是我们在创建模型时,赋予的值也就是0.5f,目标混合因子InvSrcAlpha就跟简单了,值就是1.0-源混合因子,这里源混合因子是0.5f,所以目标混合因子就是0.5f,整个公示就是模型颜色*0.5f + 颜色缓存中的颜色*0.5f,就是显示的颜色了。可以试着将混合因子改成One或者Zero试试。
源码下载:下载地址