下面哪个组合对象类型可以将粒子系统等对象转换成网格管理对象分类表格属性的 对象

用心创造滤镜
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
*21*&3dsmax不能按一定的间隔自动保存文件。(n)*22*&对于参考复制对象的编辑修改一定不影响原始对象(n)&*25*&在3dsmax中渲染器不可以生成IFL文件(y)*26*&SurfaceMapper编辑器是根据表面确定贴图坐标。(y)*27*&对二维图形制作的动画效果不能够带到由它形成的三维几何体中(n)*28*&在EditSpline中,编辑节点(Vertex)中的Break命令在选择的节点处插入第二个节点,并且在这两个节点之间断开样条线。(y)*29*&封闭图形上节的点是有顺序的,这个顺序是可以改变的。(y)*30*&在成为组合对象的运算对象之前,给对象指定一个确定的材质ID是非常有用的。这样便于后面选择表面和指定材质。(n)*31*&在默认状态下,可以在材质编辑器里改变弹力系数、静态阻力和滑动阻力。(y)*32*&不可以使用TrackView复制标准几何体和扩展几何体的参数。 (n)*33*&Audio Position不是3dsmax的位置控制器。(y)*34*&动力学系统是模拟物体受力后的运动效果。(y)*36*&材质编辑器中的灯光设置也影响场景中的灯光。(n)37*&自由摄象机常用于设置摄象机沿着路径运动的动画。(y)40*&可以使用Coordinates卷展栏中的Angle参数设置贴图旋转的动画(y)&Mirror复制中如果只复制物体,应选哪个参数: A) NoClone B) Instance C) Reference D) Copy (d)能够实现放大和缩小一个视图的视图工具为: A) Pan B) Arc rotate C)Zoom All D) Zoom (d)下面拿种曲线是NURBS的曲线类型? A) CV Curve B) Bezier Curve C)Spline Curve D) Mesh Curve (a)&下面哪个组合对象类型可以将粒子系统等对象转换成网格属性的对象:A) Connect B) Morph C) Mesher D) Conform (c)几何体的贴图通道最多有多少个: A) 100 B) 999 C) 99 D) 256(b)下面哪种方法可以将Conform对象转换成NURBS? A) 直接转换 B)通过Editable Poly和Editable Patch C) 通过Editable Mesh和EditablePatch D) 通过Editable Patch (d)下面哪一种是Wind的形式: A) 只能是平面的 B) 只能是球形的 C)可以是平面,也可以是球形 D) 只能是环形的 (c)下面哪个参数不是材质的动力学属性? A) Bounce Coefficient B) StaticFriction C) Sliding Friction D) Friction Coefficient(d)下面哪个控制器不属于变换层次? A) Transform Script B) PRS C) LinkConstraint D) Lookat Constraint (d)下面哪个控制器可以组合多个控制器的效果? A) Position List B) PathConstraint C) AudioPostion D) Bezier Postion (a)在使用Bitmap贴图时,Coordinates卷展栏中的哪个参数可以控制贴图的方向?A) Offset B) Tiling C) Tile D) Angle (b)UVW Map编辑修改器的哪个按钮可以用来随意指定贴图的大小? A) Fit B)Center C) Bitmap Fit D) Region Fit (d)23*&变换在堆栈中没有记录,而编辑修改器在堆栈中有记录。(n)25*&在3ds max中制作动画时只能精确到1帧。(n)*27*&CameraMap根据一个指定的摄像机应用UVW贴图坐标,当对象移动式。贴图会因背景的改变而改变(y)&*28*&在放样中如果要完全控制倾斜角,不要复选Banking,而要使用Twist变形手工调整倾斜角(y)*29*&Material不允许次对象材质的动画。 (n)30\&封闭图形上节的点是有顺序的,这个顺序是可以改变的(y)34*&采用Bezier插值类型的控制器在关键帧之间均匀插值(y)*35*&Wind模拟自然界风吹的效果。风只能是平面的。(n)*38*&使用灯光中阴影设置中的ShadowMap一定不能产生透明的阴影的效果。(n)&2&&要在所有视口中以明暗方式显示选择的对象,需要使用哪个命令:A) Views/Shade Selected B) Views/Show Transform Gizmo C) Views/Show Background D) Views/Show Key Times (a)'骨骼系统的名称为: A) Ring Array B) Bones C) Sunlight D)Wave(b)6&&下面哪些关于样条线中切线调整的叙述是不正确的?A) 当LockHandles的Alike选项作用于多个节点的时候,只有当选择的是BezierCorner节点的时候,一个节点的两边才不同。对于Bezier节点,拖曳任何一个手柄就影响两个手柄。B) 当选择LockHandles的Alike选项并按Shift键拖曳时,将所有选择的节点转换成BeizerCorner节点。 C)使用Local坐标系旋转节点就旋转切线,同时影响曲线的曲率。 D)使用Local坐标系缩放节点会改变曲线的曲率,而不影响切线的方向。(d)'&9&&MeshSmooth编辑修改器的哪个选项可以控制节点的权重?A) Classic B) NURMS C) NURBS D) QuadOutput (d)&11&&下面哪一种不是动力学系统的碰撞测试方式?A) Box B) Cylinder C) Spher D) Patch (d)
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_082065',
blogTitle:'3d论证题(附答案)1',
blogAbstract:'&1&&在默认的状态下重新绘制所有视图的快捷键是:A) M B) N C) ` D)W&&&&&(c)&2&&下面哪一种方法不能用来激活SelectObjects对话框? A) 工具栏中Select by Name按钮 B) Edit菜单下的SelectBy Name…命令 C) 键盘上的H键 D) Tools菜单下的Selection Floter命令(d)3Select and Uniform Scale的功能是: A) 旋转物体 B) 移动物体 C)非均匀比例缩放 D) 按比例缩放 (c)&4&&使用主工具栏中的哪个工具可以改变某些对象的创建参数?A) Select a',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:6,
publishTime:6,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}> 游戏开发五十浅墨DirectX教程十八雪花飞扬:实现唯美的粒子系统本篇文章中,我们将一起探讨三维游
游戏开发五十浅墨DirectX教程十八雪花飞扬:实现唯美的粒子系统本篇文章中,我们将一起探讨三维游
发布时间: & &
浏览:118 & &
回复:0 & &
悬赏:0.0希赛币
游戏开发五十 浅墨DirectX教程十八 雪花飞扬:实现唯美的粒子系统  本篇文章中,我们将一起探讨三维游戏中粒子系统的方方面面,首先对粒子系统的基本概念特性做一个全面的认知,然后我们依旧是把粒子系统封装在一个C++类中,模拟了三维游戏中唯美的雪花飞扬的景象,让我们之前的综合三维游戏场景更加炫。依旧是放出一张本篇文章的配套程序的截图:      这个帅气的大天使为我们唯美的雪花飞扬示例程序平添了几分霸气有木有?  PS:示例程序的源代码在文章末尾提供下载    大家应该记得,我们之前也用GDI实现过雪花粒子系统,那个时候由于图形库GDI的限制,实现效果或多或少显得有些拙劣,这篇文章中,我们在DirectX的帮助下,专门用粒子系统重新实现了唯美雪花的飞扬景象,算是在为强大的粒子系统正名吧。    一、对粒子系统的基本认知    1983年,奇才Reeves.V.T在它发表的论文《Particle Systems A Technique for&Modeling a Class of Fuzzy Objects》中首次提出了粒子系统的概念。从此,粒子系统就开始广泛运用于计算机中各种模糊景物的模拟。经常使用粒子系统模拟的现象有火焰、爆炸、烟、水流、火花、落叶、云、雾、雪、尘、流星尾迹或者像发光轨迹这样的抽象视觉效果等等。这些物体模型在计算机中往往很难用具体的形状、大小来描述,但是我们可以通过粒子系统的思想,去描述组成这些物体的每个元素和它的变化。  一般情况下,粒子的几何特征都十分的简单,可以采用一个像素或者是一个小的多边形来表示。需要注意的是,粒子系统的最大的缺陷是,当粒子数量达到很大的规模的时候,对运行时机器性能的要求会更加苛刻,如果机器的性能跟不上,就会显得达不到实时的运行效果,俗话说,就是粒子太多了,我们的电脑跑不动了,就会很卡。  在许多三维建模及渲染包内部就可以创建、修改粒子系统,如 3D Studio Max、Maya 以及 Blender 等。这些编辑程序使艺术家能够立即看到他们设定的特性或者规则下粒子系统的表现,另外还有一些插件能够提供增强的粒子系统效果,例如 AfterBurn 以及用于流体的 RealFlow。而2D的粒子特效软件中particleIllusion最为出色,因为他的渲染比一般的3D软件快较为平面化。Combustion 这样的多用途软件或者只能用于粒子系统的 Particle Studio 等都可以用来生成电影或者视频中的粒子系统。而目前,粒子系统技术被广泛用于大型3D游戏地制作中。首先看几张用粒子系统制作出来的效果图吧:      然后下图是DirectX SDK中自带sample一个和粒子系统相关的非常华丽的demo,推荐大家去运行一下,如果你的DirectX SDK安装在D盘,那么路径就是  D:\Program Files\Microsoft DirectXSDK (Jun 2010)\Samples\C++\Direct3D11\NBodyGravityCS11  放几张运行的截图:          粒子系统通常有三个要素:群体性、统一性和随机性。下面我们分别来简单看一下:  群体性:粒子系统是由大量的可见元素构成的。因此用粒子系统描述一团烟雾是合情合理的,但是我们所用粒子系统去描述一粒烟雾显然只有闹笑话了。  统一性:粒子系统的每个元素有具有相同的表现规律。比如,雪花粒子系统中的每一片雪花,都是白色无暇、轻盈灵动的。如果雪花粒子系统中出现了彩色的粒子,那显然就是异类了。  随机性:粒子系统中每个元素又随机表现出不同的特性。比如烟雾中每一个烟雾粒子的运动轨迹往往都是杂乱无章的,但是对于整个烟雾系统来说,这些烟雾粒子往往都有一个大体的运动方向。      二、粒子系统的基本原理    粒子通常都是一个带有纹理的四边形。我们通过这个使用了纹理映射的四边形,可以认为粒子实际上是一个很小的网格模型,只不过是纹理赋予了它特殊的外表罢了。绘制粒子就如果绘制多边形一样简单,因为一个粒子说白了就是一个可改变大小并映射了纹理的四边形罢了。  下图就是一个20个单位大小的粒子。    如果给出了粒子中心点的坐标和粒子的大小,不难计算出绘制粒子所需要的4个顶点坐标,这样往往比直接给4个顶点坐标来得直观和节省空间。  另外,很多情况下,因为一个例子是使用两个三角形组成的一个矩形来表示的,所以通常需要使粒子四边形始终面向观察者,这就用到了我们在Direct3D中的广告板(Billboard)技术,也叫公告版技术。公告版技术的基本原理在这里也提一下吧,后面有机会就专门用一次更新来讲解。公告版技术的基本原理就是在渲染一个多边形时,首先根据观察方向构造一个旋转矩阵,利用这个旋转矩阵旋转多边形让这个多边形始终是面向观察者的,如果观察方向是不断变化的,那么我们这个旋转矩阵也要不断进行调节。这样,我们始终看到的是这个多边形“最美好”的一面。这样先让多边形面向观察者,然后再渲染的技术,就是传说中的广告板(Billboard)技术。  我们知道,粒子系统都由大量的粒子构成,每个粒子都有一组属性,如位置、大小以及纹理,还比如颜色、透明度、运动速度、加速度、自旋周期,生命周期等等属性。一个粒子需要具有什么样的属性,当然是取决于具体的运用了。  另外,粒子属性的初始值常常都是随机值,而粒子的产生也常常是由位于空间中某个位置的粒子源产生的。    粒子系统在宏观和微观上都是随时间不断变化的,一套粒子系统在它生命周期的每一刻,一般都需完成以下的四步曲的工作:  1.产生新的粒子  这一步当中,我们会根据预定的要求,产生一定数目的新粒子。粒子的各项初始属性都可以用rand函数来在一定的范围内赋上随机的值。    2.更新现有粒子的属性  比如粒子有位置和移动速度,自旋速度等等属性,这就需要在每一帧当中根据原来的粒子的位置、移动速度和自旋速度重新进行计算和赋值更新。    3.删除已经消亡的粒子  这一步是可选的,具体情况具体分析,因为有些粒子系统中粒子是一直都存在的,没有消亡一说。在规定了粒子生命周期的一套粒子系统中,就需要判断每个粒子是否生命走到了尽头,如果是的话,那么它就game over,消亡了,得用相关代码把它从粒子系统中消除。    4.绘制出粒子  这步没有的话什么都不是,不显示出来叫什么粒子系统啊。人家可不管你在之前做了多少工作,算了多少东西,反正玩家是要看到最终的显示效果的。  在Direct3D 8.0以后,我们可以通过一种称为点精灵(Point Sprite)的特殊点元来描述粒子系统中的粒子。和一般点元不同的是,点精灵可以进行纹理映射并改变大小。点精灵的使用常常是伴随着SetRenderState中第一个参数取如下的几个值:  D3DRS_POINTSIZE
D3DRS_POINTSIZE_MIN
D3DRS_POINTSPRITEENABLE
D3DRS_POINTSCALEENABLE
D3DRS_POINTSCALE_A
D3DRS_POINTSCALE_B
D3DRS_POINTSCALE_C
  另外,粒子系统中的一个重要要素是保存粒子的存储结构。我们可以用数组,如果需要动态插入和删除原始的话,就进一步使用链表用或者模板了。  需要注意的是,因为粒子系统中会有很多粒子需要不断地产生、消亡,如果在每个粒子产生时都分配内存,或者在每个粒子消亡时都释放内存,这显然会造成巨大的资源开销,非常不推荐。这里我们按链表这种方案来讲解。我们通常采用的做法是,未雨绸缪,预先为所有的粒子分配内存,并将这些粒子保存到一个链表当中。当需要产生新的粒子时,从这个链表中取出所需数量的粒子,并将它们加入到渲染链表中,而当一个粒子消亡后,重新将它们放回到原链表中,并从渲染链表中删除这些粒子。最后,在程序结束时,统一一次性释放所有粒子所占的内存空间。这就是比较科学的做法。  呼,不讲概念了,太闷了,开始准备动手做些东西吧。    三、雪花粒子系统的设计  我们之前已经提到过,粒子系统可以模拟很多的现象,比如火焰、爆炸、烟、水流、火花、落叶、云、雾、雪、尘、流星尾迹或者发光轨迹。对于现象的模拟,粒子的特性往往需要根据模拟的现象的属性来具体地设计。    对于我们今天要用粒子系统来模拟的雪花飞扬场景,有两个比较特殊的地方:  1.在雪花飞扬场景中,不需要用点精灵或者公告版技术来让粒子的四个顶点所在的面始终朝向观察者,因为雪花飞舞起来是非常优雅的,会悠扬地绕着不同的轴打转,用了公告板技术反而画蛇添足,显得不那么真实了。你见过圆圆的雪花始终面朝着你转圈的吗,见鬼了吧!  2. 在雪花飞扬场景中,可以不需要粒子的动态消亡与产生,可以让雪花粒子在一定区域内下落,如果下落到Y轴的临界区域,就把粒子的Y坐标设为预定的临界最高点的Y坐标,就像粒子都是从这个地方产生的一样,这样就会模拟出源源不断地下雪景象。其实,我们又在用惯用伎俩来欺骗玩家了。  就像SisMVG童鞋在浅墨上篇文章中评论的一样“其实世界上最大的骗子团体就是程序员”。我们只是其实是在让规定数量的雪花粒子不断地在跑堂,到了终点再让他们从起点重新开始跑,一遍一遍地,只要程序不停止运行,那么就永不止息。你以为你体验了无数的雪花从你眼前呼啸而过优雅下落的样子,其实也就是那么来来回回PARTICLE_NUMBER= 8000个而已,哈哈。而这个PARTICLE_NUMBER就是下面我们要封装雪花飞扬粒子系统的类中给粒子数量规定的宏。  好了,我们开始写这个雪花粒子系统的内容吧。    首先依旧是写出这个名为SnowParticleClass类的大体轮廓。  首先当头棒喝怒写4个宏,方便宏观调控。这四个宏分别用于表示雪花粒子数量,雪花飞扬区域的长度,雪花飞扬区域的宽度,雪花飞扬区域的高度。  #define PARTICLE_NUMBER
//雪花粒子数量,显卡不好、运行起来卡的的童鞋请取小一点。
#define SNOW_SYSTEM_LENGTH_X
//下雪区域的长度
#define SNOW_SYSTEM_WIDTH_Z
//下雪区域的宽度
#define SNOW_SYSTEM_HEIGHT_Y
//下雪区域的高度  这里的PARTICLE_NUMBER雪花粒子数量我们取的10万,那么后面我们写出来的游戏场景中就有10万个雪花粒子,当然,前提是你的显卡是糕富帅,才禁得住10万及以上的粒子数量。如果像浅墨这样的显卡明日黄花ATI Radeon HD 5730,取八万的雪花粒子,跑起来帧数就只有10帧左右了,卡的飞起。当然,你取20万的粒子数量,在下雪区域是在x20000的区域中就是超级大暴雪了。。。建议这时候把长度和宽度调大一些,来让这20万的粒子的活动区域更大。    然后我们写出雪花粒子的FVF灵活顶点格式。顶点属性当然是顶点坐标加上纹理坐标了:  //-----------------------------------------
//点精灵顶点结构和顶点格式
//-----------------------------------------
struct POINTVERTEX
floatx, y,
//顶点位置
//顶点纹理坐标
#define D3DFVF_POINTVERTEX(D3DFVF_XYZ|D3DFVF_TEX1)    接下来是雪花粒子的属性结构体,想一想现实生活中的雪花有哪些特定的属性呢?唯美的雪花,有特定的位置,会旋转,有下降速度,样子不同,嗯,好,那么我们就这样写:  //-----------------------------------------
// Desc: 雪花粒子结构体的定义
//-----------------------------------------
struct SNOWPARTICLE
floatx, y,
//坐标位置
floatRotationY;
//雪花绕自身Y轴旋转角度
floatRotationX;
//雪花绕自身X轴旋转角度
floatFallS
//雪花下降速度
floatRotationS
//雪花旋转速度
//纹理索引数
};    好,边角废料写完了,下面正式来设计这个类吧。首先来看一看要写哪些成员变量,LPDIRECT3DDEVICE9类型的设备接口指针m_pd3dDevice不能少吧,雪花粒子数组m_Snows要有吧,顶点缓存对象m_pVertexBuffer要有吧,保存不同雪花纹理样式的雪花纹理数组m_pTexture要有吧,嗯,成员变量就这些。  然后看看要有哪些成员函数,构造函数,析构函数先显式地写出来,然后粒子系统初始化函数InitSnowParticle,粒子系统更新函数UpdateSnowParticle,粒子系统渲染函数RenderSnowParticle,嗯,成员函数也就是这些了。整体来看,这里类的轮廓就是如下,即贴出SnowParticleClass.h的全部代码:  //=============================================================================
// Name: SnowParticleClass.h
Des:一个封装了雪花粒子系统系统的类的头文件
// 2013年 3月31日 Create by 浅墨
//=============================================================================
#pragma once
#include &D3DUtil.h&
#define PARTICLE_NUMBER
//雪花粒子数量,显卡不好、运行起来卡的童鞋请取小一点。
#define SNOW_SYSTEM_LENGTH_X
//下雪区域的长度
#define SNOW_SYSTEM_WIDTH_Z
//下雪区域的宽度
#define SNOW_SYSTEM_HEIGHT_Y
//下雪区域的高度
//-----------------------------------------
//点精灵顶点结构和顶点格式
//-----------------------------------------
struct POINTVERTEX
floatx, y,
//顶点位置
//顶点纹理坐标
#define D3DFVF_POINTVERTEX(D3DFVF_XYZ|D3DFVF_TEX1)
//-----------------------------------------
// Desc: 雪花粒子结构体的定义
//-----------------------------------------
struct SNOWPARTICLE
floatx, y,
//坐标位置
floatRotationY;
//雪花绕自身Y轴旋转角度
floatRotationX;
//雪花绕自身X轴旋转角度
floatFallS
//雪花下降速度
floatRotationS
//雪花旋转速度
//纹理索引数
//-----------------------------------------
// Desc: 粒子系统类的定义
//-----------------------------------------
class SnowParticleClass
LPDIRECT3DDEVICE9
//D3D设备对象
SNOWPARTICLE
m_Snows[PARTICLE_NUMBER];
//雪花粒子数组
LPDIRECT3DVERTEXBUFFER9
m_pVertexB
//保存粒子数据的顶点缓存
LPDIRECT3DTEXTURE9
m_pTexture[6];
//雪花纹理
SnowParticleClass(LPDIRECT3DDEVICE9pd3dDevice);
//构造函数
~SnowParticleClass();
//析构函数
HRESULTInitSnowParticle();
//粒子系统初始化函数
HRESULTUpdateSnowParticle( float fElapsedTime);
//粒子系统更新函数
HRESULTRenderSnowParticle( );
//粒子系统渲染函数
};四、雪花粒子系统的实现  又到了做填空题的时候,对着上面我们写勾勒出来的SnowParticleClass类,我们有5个函数需要填上实现代码,还等什么,我们开始吧。  首先呢,构造函数:  //-------------------------------------------------------------
// Desc: 构造函数
//-------------------------------------------------------------
SnowParticleClass::SnowParticleClass(LPDIRECT3DDEVICE9pd3dDevice)
//给各个参数赋初值
m_pd3dDevice=pd3dD
m_pVertexBuffer=NULL;
for(inti=0; i&5; i++)
m_pTexture[i]= NULL;
}    接下来,粒子系统初始化函数InitSnowParticle()。首先呢,调用srand重新播种一下随机数种子。然后for循环为所有的雪花粒子赋予独一无二的各项属性值。接着,用讲烂了的顶点缓存使用五步曲的其中的三步为代表着所有雪花粒子属性的一个顶点缓存赋值,最后调用6次D3DXCreateTextureFromFile从文件加载6种不同的雪花纹理进来。这6种雪花纹理图是浅墨按照素材PS出来,分别导出的,效果图在下面,还不错,各有特点,非常漂亮:&&&&&&&&&&  经过上面的思考,InitSnowParticle()函数的实现代码我们就知道怎么写了:  //-------------------------------------------------------------
// Name: SnowParticleClass::InitSnowParticle( )
// Desc: 粒子系统初始化函数
//-------------------------------------------------------------
HRESULTSnowParticleClass::InitSnowParticle( )
//初始化雪花粒子数组
srand(GetTickCount());
for(inti=0; i&PARTICLE_NUMBER; i++)
m_Snows[i].x
=float(rand()%SNOW_SYSTEM_LENGTH_X-SNOW_SYSTEM_LENGTH_X/2);
m_Snows[i].z
= float(rand()%SNOW_SYSTEM_WIDTH_Z-SNOW_SYSTEM_WIDTH_Z/2);
m_Snows[i].y
= float(rand()%SNOW_SYSTEM_HEIGHT_Y);
m_Snows[i].RotationY
= (rand()%100)/50.0f*D3DX_PI;
m_Snows[i].RotationX
= (rand()%100)/50.0f*D3DX_PI;
m_Snows[i].FallSpeed
= 300.0f + rand()%500;
m_Snows[i].RotationSpeed
= 5.0f + rand()%10/10.0f;
m_Snows[i].TextureIndex= rand()%6;
//创建雪花粒子顶点缓存
m_pd3dDevice-&CreateVertexBuffer(4*sizeof(POINTVERTEX), 0,
D3DFVF_POINTVERTEX,D3DPOOL_MANAGED,&m_pVertexBuffer, NULL );
//填充雪花粒子顶点缓存
POINTVERTEXvertices[] =
{-20.0f, 0.0f, 0.0f,
0.0f, 1.0f, },
{-20.0f, 40.0f, 0.0f,
0.0f, 0.0f, },
20.0f, 0.0f, 0.0f,
1.0f, 1.0f, },
20.0f, 40.0f, 0.0f,
1.0f, 0.0f, }
m_pVertexBuffer-&Lock(0, sizeof(vertices), (void**)&pVertices, 0 );
memcpy(pVertices, vertices, sizeof(vertices) );
m_pVertexBuffer-&Unlock();
//创建6种雪花纹理
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow1.jpg&, &m_pTexture[0] );
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow2.jpg&, &m_pTexture[1] );
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow3.jpg&, &m_pTexture[2] );
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow4.jpg&, &m_pTexture[3] );
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow5.jpg&, &m_pTexture[4] );
D3DXCreateTextureFromFile(m_pd3dDevice, L&GameMedia\\snow6.jpg&, &m_pTexture[5] );
returnS_OK;
}  接着我们来看一下粒子系统更新函数UpdateSnowParticle怎么实现。其实非常简单,就是一个for循环遍历所有的粒子,看有哪些需要更新的就可以了,对于我们雪花粒子系统,需要更新一下每个粒子的Y坐标,然后判断是否到了“地面”,然后还要改变其自旋角度。那么,代码写出来就是这样了:  //-------------------------------------------------------------
// Name: SnowParticleClass::UpdateSnowParticle( )
// Desc: 粒子系统更新函数
//-------------------------------------------------------------
HRESULTSnowParticleClass::UpdateSnowParticle( float fElapsedTime)
//一个for循环,更新每个雪花粒子的当前位置和角度
for(inti=0; i&PARTICLE_NUMBER; i++)
m_Snows[i].y-= m_Snows[i].FallSpeed*fElapsedT
//如果雪花粒子落到地面, 重新将其高度设置为最大
if(m_Snows[i].y&0)
m_Snows[i].y= SNOW_SYSTEM_WIDTH_Z;
//更改自旋角度
m_Snows[i].RotationY
+= m_Snows[i].RotationSpeed * fElapsedT
m_Snows[i].RotationX
+= m_Snows[i].RotationSpeed * fElapsedT
returnS_OK;
}  最后来看一下最关键的粒子系统渲染函数RenderSnowParticle怎么写。首先禁用照明,然后设置纹理状态,接着设置设置Alpha混合系数,设置背面消隐模式为不剔除,然后就开始渲染了。需要注意的是设置Alpha混合系数这里依旧是我们之前没有专门花一篇文章讲,这里理解它的功能为进行透明贴图就行了。就是我们在写GDI游戏小程序的时候一直在做的纠结事情,把图片背景的黑边去掉。好了,思路有了,写代码还会难吗:  //-------------------------------------------------------------
// Name: SnowParticleClass::RenderSnowParticle( )
// Desc: 粒子系统渲染函数
//-------------------------------------------------------------
HRESULT SnowParticleClass::RenderSnowParticle(
//禁用照明效果
m_pd3dDevice-&SetRenderState(D3DRS_LIGHTING, false );
//设置纹理状态
m_pd3dDevice-&SetTextureStageState(0, D3DTSS_COLOROP,
D3DTOP_SELECTARG1);
//将纹理颜色混合的第一个参数的颜色值用于输出
m_pd3dDevice-&SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
//纹理颜色混合的第一个参数的值就取纹理颜色值
m_pd3dDevice-&SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); //缩小过滤状态采用线性纹理过滤
m_pd3dDevice-&SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); //放大过滤状态采用线性纹理过滤
//设置Alpha混合系数
m_pd3dDevice-&SetRenderState(D3DRS_ALPHABLENDENABLE,true);
//打开Alpha混合
m_pd3dDevice-&SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
//源混合系数设为1
m_pd3dDevice-&SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
//目标混合系数设为1
//设置剔出模式为不剔除任何面
m_pd3dDevice-&SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE );
//渲染雪花
for(inti=0; i&PARTICLE_NUMBER; i++)
//构造并设置当前雪花粒子的世界矩阵
staticD3DXMATRIX matYaw, matPitch, matTrans, matW
D3DXMatrixRotationY(&matYaw,m_Snows[i].RotationY);
D3DXMatrixRotationX(&matPitch,m_Snows[i].RotationX);
D3DXMatrixTranslation(&matTrans,m_Snows[i].x, m_Snows[i].y, m_Snows[i].z);
matWorld= matYaw * matPitch * matT
m_pd3dDevice-&SetTransform(D3DTS_WORLD,
&matWorld);
//渲染当前雪花粒子
m_pd3dDevice-&SetTexture(0, m_pTexture[m_Snows[i].TextureIndex] );
//设置纹理
m_pd3dDevice-&SetStreamSource(0,m_pVertexBuffer, 0, sizeof(POINTVERTEX)); //把包含的几何体信息的顶点缓存和渲染流水线相关联
m_pd3dDevice-&SetFVF(D3DFVF_POINTVERTEX);
//设置FVF灵活顶点格式
m_pd3dDevice-&DrawPrimitive(D3DPT_TRIANGLESTRIP,0, 2);
//恢复相关渲染状态:Alpha混合 、剔除状态、光照
m_pd3dDevice-&SetRenderState(D3DRS_ALPHABLENDENABLE,false);
m_pd3dDevice-&SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW );
m_pd3dDevice-&SetRenderState(D3DRS_LIGHTING, true );
returnS_OK;
}    析构函数就很简单了,就是在收拾残局,看有什么COM接口要释放的:  //-------------------------------------------------------------
// Desc: 析构函数
//-------------------------------------------------------------
SnowParticleClass::~SnowParticleClass()
SAFE_RELEASE(m_pVertexBuffer);
for(inti=0;i&3; i++)
SAFE_RELEASE(m_pTexture[i]);
    五,雪花飞扬粒子类的使用    与类打交道封装功能和我们经历的生活一样,也是一个先苦后甜的过程。  设计和实现这个类的时候或许是苦涩的,但是先苦后甜是必须的,写完这个类之后,用起来非常的方便,只用几行代码而已,一个唯美的雪花飞扬景象就加入到我们的游戏场景中了。。  也就是如下的三步:  Ⅰ.首先,定义一个SnowParticleClass类的全局指针实例:  SnowParticleClass*
g_pSnowParticles= NULL;
//雪花粒子系统的指针实例    Ⅱ.然后,在初始化阶段拿着雪花飞扬类的指针对象SnowParticleClass到处“指”,创建并初始化粒子系统:  //创建并初始化雪花粒子系统
g_pSnowParticles= new SnowParticleClass(g_pd3dDevice);
g_pSnowParticles-&InitSnowParticle();    Ⅲ.最后,就是在Render函数中依然是拿着天空类的指针对象g_pSnowParticles先指一下UpdateSnowParticle函数,更新粒子系统,然后再指一下RenderSnowParticle函数,进行渲染。  //绘制雪花粒子系统
g_pSnowParticles-&UpdateSnowParticle(fTimeDelta);
g_pSnowParticles-&RenderSnowParticle();  另外需要注意上面更新粒子系统的UpdateSnowParticle函数我们用到了一个流逝时间参数fTimeDelta,所以我们就要把我们服役多年的消息循环中改成如下含有流逝时间的更加先进的消息循环体系,然后让Direct3D_Update和Direct3D_Render各增加一个代表流逝时间的fTimeDelta参数。  //消息循环过程
MSGmsg = { 0 };
//初始化msg
while(msg.message != WM_QUIT )
//使用while循环
staticFLOAT fLastTime
=(float)::timeGetTime();
staticFLOAT fCurrTime
=(float)::timeGetTime();
staticFLOAT fTimeDelta = 0.0f;
= (float)::timeGetTime();
fTimeDelta= (fCurrTime - fLastTime) / 1000.0f;
if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
//查看应用程序消息队列,有消息时将队列中的消息派发出去。
TranslateMessage(&msg );
//将虚拟键消息转换为字符消息
DispatchMessage(&msg );
//该函数分发一个消息给窗口程序。
Direct3D_Update(hwnd,fTimeDelta);
//调用更新函数,进行画面的更新
Direct3D_Render(hwnd,fTimeDelta);
//调用渲染函数,进行画面的渲染
}& &&    嗯,既然类都写完了,用起来就是这么简单。六、详细注释的源代码欣赏  本篇文章配套的源代码在之前的基础上又增加了两个文件,也就是实现雪花飞扬粒子系统类的源文件和头文件。全部文件数量增加到了12个,它们的列表如下:    我们依旧只贴出核心代码main.cpp,其他的众多文件大家下源代码回去看就好了。  //*****************************************************************************************
//游戏开发笔记系列配套源码五十
浅墨DirectX教程十八
雪花飞扬:实现唯美的粒子系统
// 2013年 3月31日
Create by 浅墨
//图标素材出处: VAMPIRE_SWEETIE
//背景音乐素材出处:魔兽争霸3 暗夜精灵战斗曲
//人物模型素材出处:英雄无敌6
//更多内容请访问我的博客: *****************************************************************************************
//*****************************************************************************************
// Desc: 宏定义部分
//*****************************************************************************************
#define SCREEN_WIDTH 932
//为窗口宽度定义的宏,以方便在此处修改窗口宽度
#define SCREEN_HEIGHT 700
//为窗口高度定义的宏,以方便在此处修改窗口高度
#define WINDOW_TITLE _T(&游戏开发笔记系列配套示例程序五十
浅墨DirectX教程十八
雪花飞扬:实现唯美的粒子系统&) //为窗口标题定义的宏
//*****************************************************************************************
// Desc: 头文件定义部分
//*****************************************************************************************
#include &d3d9.h&
#include &d3dx9.h&
#include &tchar.h&
#include &time.h&
#include &DirectInputClass.h&
#include &CameraClass.h&
#include &TerrainClass.h&
#include &SkyBoxClass.h&
#include &SnowParticleClass.h&
//*****************************************************************************************
// Desc: 库文件定义部分
//*****************************************************************************************
#pragma comment(lib,&d3d9.lib&)
#pragma comment(lib,&d3dx9.lib&)
#pragma comment(lib, &dinput8.lib&)
// 使用DirectInput必须包含的库文件,注意这里有8
#pragma comment(lib,&dxguid.lib&)
#pragma comment(lib, &winmm.lib&)
//*****************************************************************************************
// Desc: 全局变量声明部分
//*****************************************************************************************
LPDIRECT3DDEVICE9
g_pd3dDevice = NULL;
//Direct3D设备对象
LPD3DXFONT
g_pTextFPS =NULL;
//字体COM接口
LPD3DXFONT
g_pTextAdaperName = NULL;
// 显卡信息的2D文本
LPD3DXFONT
g_pTextHelper = NULL;
// 帮助信息的2D文本
LPD3DXFONT
g_pTextInfor= NULL;
// 绘制信息的2D文本
g_FPS= 0.0f;
//一个浮点型的变量,代表帧速率
g_strFPS[50] ={0};
//包含帧速率的字符数组
g_strAdapterName[60] ={0};
//包含显卡名称的字符数组
D3DXMATRIX
//世界矩阵
LPD3DXMESH
g_pMesh = NULL;
// 网格对象
D3DMATERIAL9*
g_pMaterials= NULL;
// 网格的材质信息
LPDIRECT3DTEXTURE9*
g_pTextures = NULL;
// 网格的纹理信息
g_dwNumMtrls = 0;
// 材质的数目
LPD3DXMESH
g_cylinder = NULL;
//柱子网格对象
D3DMATERIAL9
g_MaterialC
//柱子的材质
//全局光照
DInputClass*
g_pDInput = NULL;
//DInputClass类的指针实例
CameraClass*
g_pCamera = NULL;
//摄像机类的指针实例
TerrainClass*
g_pTerrain = NULL;
//地形类的指针实例
SkyBoxClass*
g_pSkyBox=NULL;
//天空盒类的指针实例
SnowParticleClass*
g_pSnowParticles = NULL;
//雪花粒子系统的指针实例
//*****************************************************************************************
// Desc: 全局函数声明部分
//*****************************************************************************************
LRESULT CALLBACK
WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
Direct3D_Init(HWND hwnd,HINSTANCE hInstance);
Objects_Init();
Direct3D_Render( HWND hwnd,FLOAT fTimeDelta);
Direct3D_Update( HWND hwnd,FLOAT fTimeDelta);
Direct3D_CleanUp( );
Get_FPS();
HelpText_Render(HWND hwnd);
//*****************************************************************************************
// Name: WinMain( )
// Desc: Windows应用程序入口函数
//*****************************************************************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
//开始设计一个完整的窗口类
WNDCLASSEX wndClass={0} ;
//用WINDCLASSEX定义了一个窗口类,即用wndClass实例化了WINDCLASSEX,用于之后窗口的各项初始化
wndClass.cbSize = sizeof( WNDCLASSEX ) ; //设置结构体的字节数大小
wndClass.style = CS_HREDRAW | CS_VREDRAW; //设置窗口的样式
wndClass.lpfnWndProc = WndP
//设置指向窗口过程函数的指针
wndClass.cbClsExtra
wndClass.cbWndExtra
wndClass.hInstance = hI
//指定包含窗口过程的程序的实例句柄。
wndClass.hIcon=(HICON)::LoadImage(NULL,_T(&GameMedia\\icon.ico&),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE); //从全局的::LoadImage函数从本地加载自定义ico图标
wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
//指定窗口类的光标句柄。
wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
//为hbrBackground成员指定一个灰色画刷句柄
wndClass.lpszMenuName = NULL;
//用一个以空终止的字符串,指定菜单资源的名字。
wndClass.lpszClassName = _T(&ForTheDreamOfGameDevelop&);
//用一个以空终止的字符串,指定窗口类的名字。
if( !RegisterClassEx( &wndClass ) )
//设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
return -1;
HWND hwnd = CreateWindow( _T(&ForTheDreamOfGameDevelop&),WINDOW_TITLE,
//喜闻乐见的创建窗口函数CreateWindow
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH,
SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );
//Direct3D资源的初始化,调用失败用messagebox予以显示
if (!(S_OK==Direct3D_Init (hwnd,hInstance)))
MessageBox(hwnd, _T(&Direct3D初始化失败~!&), _T(&浅墨的消息窗口&), 0); //使用MessageBox函数,创建一个消息窗口
PlaySound(L&GameMedia\\NightElf1.wav&, NULL, SND_FILENAME | SND_ASYNC|SND_LOOP);
//循环播放背景音乐
MoveWindow(hwnd,200,10,SCREEN_WIDTH,SCREEN_HEIGHT,true);
//调整窗口显示时的位置,窗口左上角位于屏幕坐标(200,0)处
ShowWindow( hwnd, nShowCmd );
//调用Win32函数ShowWindow来显示窗口
UpdateWindow(hwnd);
//对窗口进行更新,就像我们买了新房子要装修一样
//进行DirectInput类的初始化
g_pDInput = new DInputClass();
g_pDInput-&Init(hwnd,hInstance,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
//消息循环过程
MSG msg = { 0 };
//初始化msg
while( msg.message != WM_QUIT )
//使用while循环
static FLOAT fLastTime
= (float)::timeGetTime();
static FLOAT fCurrTime
= (float)::timeGetTime();
static FLOAT fTimeDelta = 0.0f;
= (float)::timeGetTime();
fTimeDelta = (fCurrTime - fLastTime) / 1000.0f;
if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
//查看应用程序消息队列,有消息时将队列中的消息派发出去。
TranslateMessage( &msg );
//将虚拟键消息转换为字符消息
DispatchMessage( &msg );
//该函数分发一个消息给窗口程序。
Direct3D_Update(hwnd,fTimeDelta);
//调用更新函数,进行画面的更新
Direct3D_Render(hwnd,fTimeDelta);
//调用渲染函数,进行画面的渲染
UnregisterClass(_T(&ForTheDreamOfGameDevelop&), wndClass.hInstance);
//*****************************************************************************************
// Name: WndProc()
// Desc: 对窗口消息进行处理
//*****************************************************************************************
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
//窗口过程函数WndProc
switch( message )
//switch语句开始
case WM_PAINT:
// 客户区重绘消息
Direct3D_Render(hwnd,0.0f);
//调用Direct3D_Render函数,进行画面的绘制
ValidateRect(hwnd, NULL);
// 更新客户区的显示
//跳出该switch语句
case WM_KEYDOWN:
// 键盘按下消息
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
// 销毁窗口, 并发送一条WM_DESTROY消息
case WM_DESTROY:
//窗口销毁消息
Direct3D_CleanUp();
//调用Direct3D_CleanUp函数,清理COM接口对象
PostQuitMessage( 0 );
//向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
//跳出该switch语句
//若上述case条件都不符合,则执行该default语句
return DefWindowProc( hwnd, message, wParam, lParam );
//调用缺省的窗口过程来为应用程序没有处理的窗口消息提供缺省的处理。
//正常退出
//*****************************************************************************************
// Name: Direct3D_Init( )
// Desc: 初始化Direct3D
1.初始化四步曲之一,创建Direct3D接口对象
2.初始化四步曲之二,获取硬件设备信息
3.初始化四步曲之三,填充结构体
4.初始化四步曲之四,创建Direct3D设备接口
//*****************************************************************************************
HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance)
//--------------------------------------------------
// :创建Direct3D接口对象, 以便用该Direct3D对象创建Direct3D设备对象
//--------------------------------------------------
LPDIRECT3D9
pD3D = NULL; //Direct3D接口对象的创建
if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口对象,并进行DirectX版本协商
return E_FAIL;
//--------------------------------------------------
// :获取硬件设备信息
//--------------------------------------------------
D3DCAPS9 int vp = 0;
if( FAILED( pD3D-&GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) )
return E_FAIL;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
//支持硬件顶点运算,我们就采用硬件顶点运算,妥妥的
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,无奈只好采用软件顶点运算
//--------------------------------------------------
// :填充D3DPRESENT_PARAMETERS结构体
//--------------------------------------------------
D3DPRESENT_PARAMETERS d3
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth
= SCREEN_WIDTH;
d3dpp.BackBufferHeight
= SCREEN_HEIGHT;
d3dpp.BackBufferFormat
= D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount
d3dpp.MultiSampleType
= D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality
d3dpp.SwapEffect
= D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow
d3dpp.Windowed
d3dpp.EnableAutoDepthStencil
d3dpp.AutoDepthStencilFormat
= D3DFMT_D24S8;
d3dpp.Flags
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval
= D3DPRESENT_INTERVAL_IMMEDIATE;
//--------------------------------------------------
// :创建Direct3D设备接口
//--------------------------------------------------
if(FAILED(pD3D-&CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hwnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//获取显卡信息到g_strAdapterName中,并在显卡名称之前加上“当前显卡型号:”字符串
wchar_t TempName[60]=L&当前显卡型号:&;
//定义一个临时字符串,且方便了把&当前显卡型号:&字符串引入我们的目的字符串中
D3DADAPTER_IDENTIFIER9 A
//定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息
pD3D-&GetAdapterIdentifier(0,0,&Adapter);//调用GetAdapterIdentifier,获取显卡信息
int len = MultiByteToWideChar(CP_ACP,0, Adapter.Description, -1, NULL, 0);//显卡名称现在已经在Adapter.Description中了,但是其为char类型,我们要将其转为wchar_t类型
MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);//这步操作完成后,g_strAdapterName中就为当前我们的显卡类型名的wchar_t型字符串了
wcscat_s(TempName,g_strAdapterName);//把当前我们的显卡名加到“当前显卡型号:”字符串后面,结果存在TempName中
wcscpy_s(g_strAdapterName,TempName);//把TempName中的结果拷贝到全局变量g_strAdapterName中,大功告成~
if(!(S_OK==Objects_Init())) return E_FAIL;
SAFE_RELEASE(pD3D) //LPDIRECT3D9接口对象的使命完成,我们将其释放掉
return S_OK;
HRESULT Objects_Init()
//创建字体
D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T(&Calibri&), &g_pTextFPS);
D3DXCreateFont(g_pd3dDevice, 20, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L&华文中宋&, &g_pTextAdaperName);
D3DXCreateFont(g_pd3dDevice, 23, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L&微软雅黑&, &g_pTextHelper);
D3DXCreateFont(g_pd3dDevice, 26, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L&黑体&, &g_pTextInfor);
// 从X文件中加载网格数据
LPD3DXBUFFER pAdjBuffer
LPD3DXBUFFER pMtrlBuffer = NULL;
D3DXLoadMeshFromX(L&angle.X&, D3DXMESH_MANAGED, g_pd3dDevice,
&pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh);
// 读取材质和纹理数据
D3DXMATERIAL *pMtrls = (D3DXMATERIAL*)pMtrlBuffer-&GetBufferPointer(); //创建一个D3DXMATERIAL结构体用于读取材质和纹理信息
g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
g_pTextures
= new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
for (DWORD i=0; i&g_dwNumM i++)
//获取材质,并设置一下环境光的颜色值
g_pMaterials[i] = pMtrls[i].MatD3D;
g_pMaterials[i].Ambient = g_pMaterials[i].D
//创建一下纹理对象
g_pTextures[i]
D3DXCreateTextureFromFileA(g_pd3dDevice, pMtrls[i].pTextureFilename, &g_pTextures[i]);
SAFE_RELEASE(pAdjBuffer)
SAFE_RELEASE(pMtrlBuffer)
//创建柱子
D3DXCreateCylinder(g_pd3dDevice, 280.0f, 10.0f, 3000.0f, 60, 60,
&g_cylinder, 0);
g_MaterialCylinder.Ambient
= D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
g_MaterialCylinder.Diffuse
= D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
g_MaterialCylinder.Specular = D3DXCOLOR(0.5f, 0.0f, 0.3f, 0.3f);
g_MaterialCylinder.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
// 设置光照
::ZeroMemory(&g_Light, sizeof(g_Light));
g_Light.Type
= D3DLIGHT_DIRECTIONAL;
g_Light.Ambient
= D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
g_Light.Diffuse
= D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
g_Light.Specular
= D3DXCOLOR(0.9f, 0.9f, 0.9f, 1.0f);
g_Light.Direction
= D3DXVECTOR3(1.0f, 1.0f, 1.0f);
g_pd3dDevice-&SetLight(0, &g_Light);
g_pd3dDevice-&LightEnable(0, true);
g_pd3dDevice-&SetRenderState(D3DRS_NORMALIZENORMALS, true);
g_pd3dDevice-&SetRenderState(D3DRS_SPECULARENABLE, true);
// 创建并初始化虚拟摄像机
g_pCamera = new CameraClass(g_pd3dDevice);
g_pCamera-&SetCameraPosition(&D3DXVECTOR3(0.0f, 1400.0f, -1800.0f));
//设置摄像机所在的位置
g_pCamera-&SetTargetPosition(&D3DXVECTOR3(0.0f, 1200.0f, 0.0f));
//设置目标观察点所在的位置
g_pCamera-&SetViewMatrix();
//设置取景变换矩阵
g_pCamera-&SetProjMatrix();
//设置投影变换矩阵
// 创建并初始化地形
g_pTerrain = new TerrainClass(g_pd3dDevice);
g_pTerrain-&LoadTerrainFromFile(L&GameMedia\\heighmap.raw&, L&GameMedia\\terrainstone.jpg&);
//从文件加载高度图和纹理
g_pTerrain-&InitTerrain(200, 200, 60.0f, 8.0f);
//四个值分别是顶点行数,顶点列数,顶点间间距,缩放系数
//创建并初始化天空对象
g_pSkyBox = new SkyBoxClass( g_pd3dDevice );
g_pSkyBox-&LoadSkyTextureFromFile(L&GameMedia\\TropicalSunnyDayFront2048.png&,L&GameMedia\\TropicalSunnyDayBack2048.png&,L&GameMedia\\TropicalSunnyDayRight2048.png&,L&GameMedia\\TropicalSunnyDayLeft2048.png&, L&GameMedia\\TropicalSunnyDayUp2048.png&);//从文件加载前、后、左、右、顶面5个面的纹理图
g_pSkyBox-&InitSkyBox(50000);
//设置天空盒的边长
//创建并初始化雪花粒子系统
g_pSnowParticles = new SnowParticleClass(g_pd3dDevice);
g_pSnowParticles-&InitSnowParticle();
return S_OK;
Direct3D_Update( HWND hwnd,FLOAT fTimeDelta)
//使用DirectInput类读取数据
g_pDInput-&GetInput();
// 沿摄像机各分量移动视角
if (g_pDInput-&IsKeyDown(DIK_A))
g_pCamera-&MoveAlongRightVec(-3.0f);
if (g_pDInput-&IsKeyDown(DIK_D))
g_pCamera-&MoveAlongRightVec( 3.0f);
if (g_pDInput-&IsKeyDown(DIK_W)) g_pCamera-&MoveAlongLookVec( 3.0f);
if (g_pDInput-&IsKeyDown(DIK_S))
g_pCamera-&MoveAlongLookVec(-3.0f);
if (g_pDInput-&IsKeyDown(DIK_R))
g_pCamera-&MoveAlongUpVec( 3.0f);
if (g_pDInput-&IsKeyDown(DIK_F))
g_pCamera-&MoveAlongUpVec(-3.0f);
//沿摄像机各分量旋转视角
if (g_pDInput-&IsKeyDown(DIK_LEFT))
g_pCamera-&RotationUpVec(-0.003f);
if (g_pDInput-&IsKeyDown(DIK_RIGHT))
g_pCamera-&RotationUpVec( 0.003f);
if (g_pDInput-&IsKeyDown(DIK_UP))
g_pCamera-&RotationRightVec(-0.003f);
if (g_pDInput-&IsKeyDown(DIK_DOWN))
g_pCamera-&RotationRightVec( 0.003f);
if (g_pDInput-&IsKeyDown(DIK_Q)) g_pCamera-&RotationLookVec(0.001f);
if (g_pDInput-&IsKeyDown(DIK_E)) g_pCamera-&RotationLookVec( -0.001f);
//鼠标控制右向量和上向量的旋转
g_pCamera-&RotationUpVec(g_pDInput-&MouseDX()* 0.001f);
g_pCamera-&RotationRightVec(g_pDInput-&MouseDY() * 0.001f);
//鼠标滚轮控制观察点收缩操作
static FLOAT fPosZ=0.0f;
fPosZ += g_pDInput-&MouseDZ()*0.03f;
//计算并设置取景变换矩阵
D3DXMATRIX matV
g_pCamera-&CalculateViewMatrix(&matView);
g_pd3dDevice-&SetTransform(D3DTS_VIEW, &matView);
//把正确的世界变换矩阵存到g_matWorld中
D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ);
//以下这段代码用于限制鼠标光标移动区域
GetClientRect(hwnd,&rect);
//取得窗口内部矩形
//将矩形左上点坐标存入lt中
lt.x = rect.
lt.y = rect.
//将矩形右下坐标存入rb中
rb.x = rect.
rb.y = rect.
//将lt和rb的窗口坐标转换为屏幕坐标
ClientToScreen(hwnd,&);
ClientToScreen(hwnd,&rb);
//以屏幕坐标重新设定矩形区域
rect.left = lt.x;
rect.top = lt.y;
rect.right = rb.x;
rect.bottom = rb.y;
//限制鼠标光标移动区域
ClipCursor(&rect);
ShowCursor(false);
//隐藏鼠标光标
//*****************************************************************************************
// Name: Direct3D_Render()
// Desc: 进行图形的渲染操作
1.渲染五步曲之一,清屏操作
2.渲染五步曲之二,开始绘制
3.渲染五步曲之三,正式绘制
4.渲染五步曲之四,结束绘制
5.渲染五步曲之五,翻转显示
//*****************************************************************************************
void Direct3D_Render(HWND hwnd,FLOAT fTimeDelta)
//--------------------------------------------------
// :清屏操作
//--------------------------------------------------
g_pd3dDevice-&Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(100, 255, 255), 1.0f, 0);
//--------------------------------------------------
// :开始绘制
//--------------------------------------------------
g_pd3dDevice-&BeginScene();
// 开始绘制
//--------------------------------------------------
// :正式绘制
//--------------------------------------------------
//绘制人物
D3DXMATRIX mScal,mRot2,mTrans,mF
//定义一些矩阵,准备对大黄蜂进行矩阵变换
D3DXMatrixTranslation(&mTrans,50.0f,.0f);
D3DXMatrixScaling(&mScal,3.0f,3.0f,3.0f);
mFinal=mScal*mTrans*g_matW
g_pd3dDevice-&SetTransform(D3DTS_WORLD, &mFinal);//设置模型的世界矩阵,为绘制做准备
// 用一个for循环,进行模型的网格各个部分的绘制
for (DWORD i = 0; i & g_dwNumM i++)
g_pd3dDevice-&SetMaterial(&g_pMaterials[i]);
//设置此部分的材质
g_pd3dDevice-&SetTexture(0, g_pTextures[i]);//设置此部分的纹理
g_pMesh-&DrawSubset(i);
//绘制此部分
//绘制柱子
D3DXMATRIX TransMatrix, RotMatrix, FinalM
D3DXMatrixRotationX(&RotMatrix, -D3DX_PI * 0.5f);
g_pd3dDevice-&SetLight(0, &g_Light);
g_pd3dDevice-&SetMaterial(&g_MaterialCylinder);
g_pd3dDevice-&SetTexture(0, NULL);//设置此部分的纹理
for(int i = 0; i & 4; i++)
D3DXMatrixTranslation(&TransMatrix, -300.0f, 0.0f, -350.0f + (i * 500.0f));
FinalMatrix = RotMatrix * TransM
g_pd3dDevice-&SetTransform(D3DTS_WORLD, &FinalMatrix);
g_cylinder-&DrawSubset(0);
D3DXMatrixTranslation(&TransMatrix, 300.0f, 0.0f, -350.0f + (i * 500.0f));
FinalMatrix = RotMatrix * TransM
g_pd3dDevice-&SetTransform(D3DTS_WORLD, &FinalMatrix);
g_cylinder-&DrawSubset(0);
//绘制地形
g_pTerrain-&RenderTerrain(&g_matWorld, false);
//渲染地形,且第二个参数设为false,表示不渲染出地形的线框
//绘制天空
D3DXMATRIX matSky,matTransSky,matRotS
D3DXMatrixTranslation(&matTransSky,0.0f,-.0f);
D3DXMatrixRotationY(&matRotSky, -0.000005f*timeGetTime());
//旋转天空网格, 简单模拟云彩运动效果
matSky=matTransSky*matRotS
g_pSkyBox-&RenderSkyBox(&matSky, false);
//绘制雪花粒子系统
g_pSnowParticles-&UpdateSnowParticle(fTimeDelta);
g_pSnowParticles-&RenderSnowParticle();
//绘制文字信息
HelpText_Render(hwnd);
//--------------------------------------------------
// :结束绘制
//--------------------------------------------------
g_pd3dDevice-&EndScene();
// 结束绘制
//--------------------------------------------------
// :显示翻转
//--------------------------------------------------
g_pd3dDevice-&Present(NULL, NULL, NULL, NULL);
// 翻转与显示
void HelpText_Render(HWND hwnd)
//定义一个矩形,用于获取主窗口矩形
RECT formatR
GetClientRect(hwnd, &formatRect);
//在窗口右上角处,显示每秒帧数
formatRect.top = 5;
int charCount = swprintf_s(g_strFPS, 20, _T(&FPS:%0.3f&), Get_FPS() );
g_pTextFPS-&DrawText(NULL, g_strFPS, charCount , &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_RGBA(0,239,136,255));
//显示显卡类型名
g_pTextAdaperName-&DrawText(NULL,g_strAdapterName, -1, &formatRect,
DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
// 输出帮助信息
formatRect.left = 0,formatRect.top = 380;
g_pTextInfor-&DrawText(NULL, L&控制说明:&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255));
formatRect.top += 35;
g_pTextHelper-&DrawText(NULL, L&
W:向前飞翔
S:向后飞翔 &, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
A:向左飞翔
D:向右飞翔&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
R:垂直向上飞翔
F:垂直向下飞翔&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
Q:向左倾斜
E:向右倾斜&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
上、下、左、右方向键、鼠标移动:视角变化 &, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
鼠标滚轮:人物模型Y轴方向移动&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper-&DrawText(NULL, L&
ESC键 : 退出程序&, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
//*****************************************************************************************
// Name:Get_FPS()函数
// Desc: 用于计算帧速率
//*****************************************************************************************
float Get_FPS()
//定义四个静态变量
static float
fps = 0; //我们需要计算的FPS值
static int
frameCount = 0;//帧数
static float
currentTime =0.0f;//当前时间
static float
lastTime = 0.0f;//持续时间
frameCount++;//每调用一次Get_FPS()函数,帧数自增1
currentTime = timeGetTime()*0.001f;//获取系统时间,其中timeGetTime函数返回的是以毫秒为单位的系统时间,所以需要乘以0.001,得到单位为秒的时间
//如果当前时间减去持续时间大于了1秒钟,就进行一次FPS的计算和持续时间的更新,并将帧数值清零
if(currentTime - lastTime & 1.0f) //将时间控制在1秒钟
fps = (float)frameCount /(currentTime - lastTime);//计算这1秒钟的FPS值
lastTime = currentT //将当前时间currentTime赋给持续时间lastTime,作为下一秒的基准时间
frameCount
= 0;//将本次帧数frameCount值清零
//*****************************************************************************************
// Name: Direct3D_CleanUp()
// Desc: 对Direct3D的资源进行清理,释放COM接口对象
//*****************************************************************************************
void Direct3D_CleanUp()
//释放COM接口对象
for (DWORD i = 0; i&g_dwNumM i++)
SAFE_RELEASE(g_pTextures[i]);
SAFE_DELETE(g_pTextures);
SAFE_DELETE(g_pMaterials);
SAFE_DELETE(g_pDInput);
SAFE_RELEASE(g_cylinder);
SAFE_RELEASE(g_pMesh);
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pTextAdaperName)
SAFE_RELEASE(g_pTextHelper)
SAFE_RELEASE(g_pTextInfor)
SAFE_RELEASE(g_pTextFPS)
SAFE_RELEASE(g_pd3dDevice)
    学到目前为止,我们用学的知识写出来的游戏场景程序已经比较炫了,一些运行截图如下:        我们操纵着摄像机在雪中飞行,那种雪花铺面而来的感觉非常地舒服。      仰望天空,任雪花飘落到“身上”:      下面这张图可以明显看到雪花被我们规定了活动区域:      冒着显卡被烧的危险拍了一张10万粒子数量时的“暴雪”画面,大家看右上角的帧数,只有可怜的8帧了。。。。        扑,一朵雪花砸脸上了。。。。      大家如果觉得这雪花太大了,没事,这是浅墨为了表现力故意调大了一点。自己去调一下雪花顶点缓存POINTVERTEX vertices数组的大小即可。    我们可以发现,其实Direct3D的固定功能流水线学到目前,基础知识也就那么多,顶点缓存,索引缓存,四大变换,纹理映射,网格,模板缓存等 等,把他们其中的几个合理地组合在一起运用一下就是新的知识,这就衍生出了我们近期刚出的三篇文章中讲到的地形,天空,粒子系统。以及还 没讲到的 公告板,拾取等等知识。      文章最后,依旧是放出本篇文章配套源代码的下载:    本节笔记配套源代码请点击这里下载:    配套源代码之十八下载&&    以上就是本节笔记的全部内容,更多精彩内容,且听下回分解。  浅墨在这里,希望喜欢游戏开发系列文章的朋友们能留下你们的评论,每次浅墨登陆博客看到大家的留言的时候都会非常开心,感觉自己正在传递一种信仰,一种精神。&    文章最后,依然是栏目,今天的句子是:&    朝着梦想的方向,迈步向前,相信,总有一天,你会看到属于自己的那道彩虹。      下周一,让我们离游戏开发的梦想更近一步。  下周一,游戏开发笔记,我们,不见不散。
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&增值电信业务经营许可证湘B2-}

我要回帖

更多关于 水槽下面做网格门好吗 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信