这节教程的架构如下:
构架其实跟”D3D11教程十四之RenderToTexture”那节教程差不多,也就是DebugWindowsClass改为BitMapClass,下面开始正题
一,ScreenFade(场景淡入淡出)是什么?
ScreenFade相当于视频剪辑的淡入淡出,想象在很多3D游戏加载完一个场景时,整个场景不会突然出现,而是慢慢由暗变亮,不会给人很突兀的感觉,这就是所谓的ScreenFade.
二,如何实现ScreenFade(场景淡入淡出)
(1) 预留一个由暗变亮的时间
FadeTotal
Time,用于从游戏(渲染)开始计算要多久才能到达完美明亮.因此也存在另外一个变量累计时间FadeAccumulatedTime,
已经开始时间百分比为FadePercent=
Fade
AccumulatedTime/FadeTotalTime
(2)若还未百分比明亮时,将整个场景渲染到一张纹理上(即RenderToTexture),而非背后缓存,这张纹理跟屏幕一样大,将这张纹理贴图用“2D Rendering”渲染到整个背后缓存(屏幕)上,刚好覆盖整个屏幕,这时在shader里利用
FadePercent实现整张纹理像素由暗变亮的效果
处理整张纹理的Shader代码如下:
Texture2D ShaderTexture:register(t0); //纹理资源
SamplerState SampleType:register(s0); //采样方式
//VertexShader
cbuffer CBMatrix:register(b0)
{
matrix World;
matrix View;
matrix Proj;
};
cbuffer CBFade:register(b1)
{
float FadeFactor; //明亮度百分比<span style="font-size: 13.3333px;">FadePercent</span>
float3 pad;
};
struct VertexIn
{
float3 Pos:POSITION;
float2 Tex:TEXCOORD0; //多重纹理可以用其它数字
};
struct VertexOut
{
float4 Pos:SV_POSITION;
float2 Tex:TEXCOORD0;
};
VertexOut VS(VertexIn ina)
{
VertexOut outa;
outa.Pos = mul(float4(ina.Pos,1.0f), World);
outa.Pos = mul(outa.Pos, View);
outa.Pos = mul(outa.Pos, Proj);
outa.Tex= ina.Tex;
return outa;
}
float4 PS(VertexOut outa) : SV_Target
{
float4 color;
color = ShaderTexture.Sample(SampleType, outa.Tex);
color = color*FadeFactor;
return color;
}
(3)当百分百明亮时,就可以直接正常的渲染整个场景到背后缓存去。
程序运行效果图如下:
刚开始完全黑暗,后面慢慢变亮
也许有同学会问:直接将3D场景直接在PixelShader最后的处理下乘以FadePercent,而直接渲染到背后缓存,这样不是更好吗?为什么多此一举先把3D场景渲染到一张纹理呢?
我是这么认为的:1,首先如果你这样做的话,会造成只有3D场景会有淡入淡出效果,而背景色不具备淡入淡出效果
2,,由于我们测试的只是一个简单的立方体,如果是复杂的场景的话,背后缓存上一个点上的颜色像素必然经过多轮的Z剔除,(这样很多被剔除的像素也乘以了FadeFactor)然而我们只需对最后一轮,或者说经过Z缓存测试而最终存在在背后缓存的那个颜色像素进行淡入淡出处理,所以我们先渲染场景到纹理上,在把纹理渲染到背后缓存上,背后缓存的每个点的像素只乘以一次FadeFactor,也算节省了一点点性能吧。
我的源代码链接如下: