📄 csdn_文档中心_alpha 闪烁效果.htm
字号:
HRESULT Render3DEnvironment( HWND );
VOID Cleanup3DEnvironment( HWND );
</PRE>
<P>这三个函数将完成设置 Direct3D、关闭 Direct3D
和对场景进行着色的所有操作。屏幕保护程序必须完成的所有工作就是实现可以被覆盖的函数。这些函数类似于我们已经逐渐了解和喜爱的
D3Dframe 对应函数;请参见下面的函数原型。</P><PRE class=clsCode>//--------------------------------------------------------------------------
// 外部函数原型
//--------------------------------------------------------------------------
HRESULT App_ConfirmDevice( DDCAPS*, D3DDEVICEDESC* );
HRESULT App_OneTimeSceneInit();
VOID App_DeleteDeviceObjects( HWND, LPDIRECT3DDEVICE7 );
HRESULT App_InitDeviceObjects( HWND, LPDIRECT3DDEVICE7 );
HRESULT App_FrameMove( LPDIRECT3DDEVICE7, FLOAT );
HRESULT App_Render( LPDIRECT3DDEVICE7 );
HRESULT App_RestoreSurfaces();
HRESULT App_FinalCleanup();
</PRE>
<P>我使用了示例中的 screensaver.cpp,并做了最少的改动。我的确发现,从注册表中读取配置数据的调用需要将参数由:</P><PRE class=clsCode> if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER, strRegPath,
KEY_READ, NULL, &hKey ) )
</PRE>
<P>调换为:</P><PRE class=clsCode> if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER, strRegPath,
NULL, KEY_READ, &hKey ) )
</PRE>
<P>该示例也未能对着色窗口可能的移动进行处理,因此我在调用 <B><FONT
face=arial>TestCooperativeLevel()</FONT></B> 之后把以下程序块加入了 <B><FONT
face=arial>Render3Denvironment()</FONT></B> 函数。</P><PRE class=clsCode> //请确保在屏幕控制面板中进行操作,监视事物的移动
RECT rTmp;
GetWindowRect( hWnd, &rTmp );
g_pFramework->Move(rTmp.left, rTmp.top );
</PRE>
<P>Direct3D 屏幕保护程序框架确实给出了 ConfigureDialog
函数的开始部分以及一种用于存储配置数据的方法,但我尚未针对 MSDNSparkles 对其进行扩充,因为它不是一个关键细节。</P>
<P>样例屏幕保护程序的另一个“特征”是:它使用 WM_TIMER 对着色进行控制。在基于 Windows 2000
的操作系统上,这会产生一个适当的帧速率,但基于 Windows9<I>x</I> 的操作系统并不具有这样一个允许使用良好帧速率的
WM_TIMER
间隔尺寸。考虑到这种情况,我重新编写了这个屏幕保护程序,使其使用线程对着色进行控制。我没有将这部分代码包括进来,因为它是一个简单明了的线程实现。有兴趣的程序员可以考虑增加多监视器功能、电源管理和口令,因为
Direct3D 屏幕保护程序框架没有提供这些功能。</P>
<P><B><FONT class=105v><FONT size=3>高级别视图</FONT></B></FONT>
<P>既然这些细节已不成为问题,我们就可以开始了。图 3 显示了 Visual Studio Workspace 窗口针对
MSDNSparkles 示例的内容。该项目由 screensaver.cpp 文件(它是从 Direct3D
示例中得到的,如上面的讨论所述)以及 sparkles.cpp 组成。</P><IMG alt=屏幕快照 border=0
height=286 src="CSDN_文档中心_Alpha 闪烁效果.files/directx0900-3.gif"
width=227>
<P><B>图 3. <FONT face=arial>MSDNSparkles</FONT>项目视图</B></P>
<P>Sparkles.cpp
包含两组函数。第一组是可以覆盖的函数,我会在后面对其进行考查。第二组包含了闪烁效果函数。为了对闪烁效果函数进行处理,MSDNSparkles
定义了它自己的小型 API,它们是 <B><FONT
face=arial>RandomTexture</B>、<B>RandomSparkle</B>、<B>InitSparkles</B>、<B>UpdateSparkle</B>
和 <B>DrawSparkle</FONT></B>。</P><PRE class=clsCode>// 闪烁效果函数
Int RandomTexture(int overflow);
Sparkle RandomSparkle(void);
Void InitSparkles(void);
Void UpdateSparkles(void);
BOOL DrawSparkles(LPDIRECT3DDEVICE7 lpDev, D3DVECTOR from, D3DVECTOR at);
</PRE>
<P>除了 <B><FONT face=arial>RandomTexture</FONT></B> 以外,所有这些函数都对
<B><FONT face=arial>Sparkle</FONT></B> 结构进行操作。<B><FONT
face=arial>Sparkle</FONT></B>
结构包含用于每个粒子的外观和行为的信息,而每一个粒子都作为粒子系统的一部分。</P><PRE class=clsCode>//闪烁效果的结构
typedef struct t_sparkle {
int texture;
int age, cur_age; // start at age and tick down to 0
float scale, delta_scale;
D3DVECTOR position;
D3DVECTOR velocity;
D3DVECTOR color;
} Sparkle;
</PRE>
<P>元素 <B><FONT face=arial>position</B> 和 <B>velocity</FONT></B>,随同
<B><FONT face=arial>scale</B> 和 <B>delta_scale</FONT></B>
一起由粒子系统使用,用于生成粒子的各个位置。元素 <B><FONT face=arial>texture</B> 与
<B>color</FONT></B> 定义作为外观随机化算法一部分的粒子外观。</P>
<P>外观随机化通过使用一个衰老系统对转换进行控制,其中,元素 <B><FONT face=arial>age</B> 与
<B></FONT><FONT face=新宋体><CODE>cur_age</CODE></FONT></B>
给出了一个倒计时系统。转换发生的方式有三种:</P>
<UL type=disc>
<LI>当某纹理的时限到期时,从列表中随机选择一种纹理。<BR><BR>
<LI>color_mode 用来生成一种基色。<BR><BR>
<LI>color_modifier_mode 用来以一些有趣的方式对基色进行修改。 </LI></UL>
<P>这些随机纹理和色彩随后会对粒子的外观进行完整定义。某些精巧的随机数学方法所生成的内容确实相当奇妙。</P>
<P><B><FONT face=arial>RandomTexture</FONT></B>
用来帮助从纹理列表中选择一种纹理。</P><PRE class=clsCode>int RandomTexture(int texture, int overflow)
{
int retVal;
if (texture == NumTextures)
{
retVal = overflow;// init to random from the n case, overflow
}
else
{
retVal = texture; // init to current in the 0..n-1 case
}
return retVal;
}
</PRE>
<P><B><FONT face=arial>RandomSparkle</FONT></B>
通过生成一些颜色增量值开始。它随后开始着手置入一个 Sparkles
结构,该结构用时限、标度和位置值来表示粒子。闪烁效果的纹理是通过调用 <B><FONT
face=arial>RandomTexture</FONT></B> 选择的。随后,<B><FONT
face=arial>color_mode</B> 和 <B>color_modifier_mode</FONT></B>
被用来生成该粒子的颜色。</P>
<P><B><FONT face=arial>Color_mode</FONT></B> 确定哪一种方法被用于生成基本颜色,随机模式还是
rgb 颤动模式。随机模式只是随机地选取一种颜色。而 RGB
颤动模式则进行一些精巧的颜色增量计算,在某一颜色范围内平滑地移动。<B><FONT
face=arial>Color_modifier_mode</FONT></B>
控制着基色的修改。可以选择四种变量:饱和色、宝石色、柔和色或亮色。这些模式中的每一种都执行一种略微不同的计算,借以对基色进行修改。</P><PRE class=clsCode>Sparkle RandomSparkle(void)
{
Sparkle ret;
static float red = 1.0f, grn = 1.0f, blu = 1.0f;
static float d_red = -(min_color_delta + rnd()*max_color_delta);
static float d_grn = -(min_color_delta + rnd()*max_color_delta);
static float d_blu = -(min_color_delta + rnd()*max_color_delta);
ret.age = min_age + (int)(rnd() * (max_age-min_age));
ret.cur_age = ret.age;
ret.scale = start_scale;
ret.delta_scale = min_delta + rnd() * (max_delta - min_delta);
ret.position = D3DVECTOR(world_size * (rnd()-rnd()),
world_size * (rnd()-rnd()),
world_size * (rnd()-rnd()));
ret.velocity = D3DVECTOR(0.0f);
ret.texture = RandomTexture(rand() % (NumTextures-1));
switch (color_mode) {
case 0 : //随机
ret.color = D3DVECTOR(rnd(), rnd(), rnd());
break;
case 1 : //rgb 颤动
red += d_red;
if (red > 1.0f) {
red = 1.0f;
d_red = -(min_color_delta + rnd()*max_color_delta);
} else if (red < 0.0f) {
red = 0.0f;
d_red = min_color_delta + rnd()*max_color_delta;
}
grn += d_grn;
if (grn > 1.0f) {
grn = 1.0f;
d_grn = -(min_color_delta + rnd()*max_color_delta);
} else if (grn < 0.0f) {
grn = 0.0f;
d_grn = min_color_delta + rnd()*max_color_delta;
}
blu += d_blu;
if (blu > 1.0f) {
blu = 1.0f;
d_blu = -(min_color_delta + rnd()*max_color_delta);
} else if (blu < 0.0f) {
blu = 0.0f;
d_blu = min_color_delta + rnd()*max_color_delta;
}
ret.color = D3DVECTOR(red, grn, blu);
break;
default :
ret.color = D3DVECTOR(0.0f, 0.5f, 1.0f);
break;
}
switch (color_modifier_mode) {
case 0 : // 无变化
break;
case 1 : // 饱和色
ret.color /= Max(ret.color);
break;
case 2 : // 宝石色
ret.color -= Min(ret.color);
ret.color /= Max(ret.color);
break;
case 3 : // 柔和色
ret.color -= Min(ret.color);
ret.color /= Max(ret.color);
ret.color = D3DVECTOR(0.6f) + 0.4f * ret.color;
break;
case 4 : // 亮色和冷色,并可用于大多数情况
ret.color *= 1.2f;
break;
default :
break;
}
return ret;
}
</PRE>
<P><B><FONT face=arial>InitSparkles</FONT></B>
选择起始纹理,然后为粒子列表分配内存。一个粒子基本上是由两个三角形构成的四边形。对粒子的说明,请参见图 4。</P><IMG
alt=粒子示意图 border=0 height=300
src="CSDN_文档中心_Alpha 闪烁效果.files/directx0900-4.gif" width=300>
<P><B>图 4. 粒子</B> </P>
<P>接下来,每个闪烁效果都通过 <B><FONT face=arial>RandomSparkle</B></FONT>
被随机地初始化。最后,为每个粒子生成索引绘图的下标。</P><PRE class=clsCode>void InitSparkles(void)
{
texture = 1;// 以 dx7 位图开始
sparkle = (Sparkle *)malloc(nMaxNumSparkles * sizeof(Sparkle));
for (UINT i=0; i<nCurNumSparkles; i++) {
sparkle[i] = RandomSparkle();
}
// 设置下标
for (i=0; i<nMaxNumSparkles; i++) {
s_indices[i*6+0] = 4*i + 0;
s_indices[i*6+1] = 4*i + 1;
s_indices[i*6+2] = 4*i + 2;
s_indices[i*6+3] = 4*i + 0;
s_indices[i*6+4] = 4*i + 2;
s_indices[i*6+5] = 4*i + 3;
}
} // InitSparkles() 结束
</PRE>
<P><B><FONT face=arial>UpdateSparkles</B> 将
<B>texture_age</B>、<B>color_age</B> 和
<B>color_modifier_age</B></FONT> 的当前值递减。随后,如果时限值已经倒数至 0,则会生成
<B><FONT face=arial>texture</B></FONT> (使用 <B><FONT
face=arial>RandomTexture</B></FONT>)、<B><FONT
face=arial>color_mode</B></FONT> 以及 <B><FONT
face=arial>color_modifier_mode</B></FONT> 的新的随机值。此操作一旦完成,<B><FONT
face=arial>RandomSparkle</B></FONT>
将被再次用来随机生成每个粒子下一帧的位置、纹理和颜色。最后对标度进行调整。</P><PRE class=clsCode>void UpdateSparkles(void)
{
UINT i;
//0..n 0..n-1==当前,n==随机
texture_age--;
if (texture_age == 0) {
texture_age = min_texture_age + (unsigned int)(rnd() *
(max_texture_age - min_texture_age));
texture = rand() % (NumTextures);
texture = RandomTexture(rand() % (NumTextures-1));
}
//0..1 0==随机,1==rgb 颤动
color_age--;
if (color_age == 0) {
color_age = min_color_age + (int)(rnd()*(max_color_age –
min_color_age));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -