XNA Kick Start (三)

来源:互联网 发布:迅雷mac历史版本下载 编辑:程序博客网 时间:2024/04/19 15:16

第二章  XNA程序员手中的画笔——GraphicsDevice

本文版权归我所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
由于本人水平有限,难免出错,欢迎大家和我交流。
作者:clayman
Blog:
http://blog.csdn.net/soilwork
clayman_joe@yahoo.com.cn

 

       看过艺术家如何绘画吗?无论绘制油画或水彩画,他们总需要一只画笔作为工具。实时渲染和绘画相当类似,不同之处在于我们的画笔是图形加速器,而画布则是一块显存。从OOP的观点来看,我们需要一个类来抽象显卡,这个类就是GraphicsDevice

       这一章,我们将编写计算机图形世界中的“Hello World”程序,学习控制GraphicsDevice的初步技术。

 

魔法的源泉——GraphicsDevice

       GraphicsDevice类位于Microsoft.Xna.Framework.Graphics名称空间下,它代表了我们系统中的图形加速设备,在XNA中,无论2D还是3D,最终所有的绘图工作都由它来完成,可以说是整个类库中最重要的类之一。相当于DirectX中的IDirect3DDevice9接口,或者Managed DirectX中的Device类。

       在阅读本教程时,你应该把XNA的帮助文件打开,以便随时查阅相关内容。希望你现在已经导航到了GraphicsDevice的成员列表,可以看到这是一个相当大的类,有数十个属性,方法和事件。哦,不要被那些陌生的成员名称吓倒了,我们会逐步学习他们。先来看看构造函数吧。

 

       public GraphicsDevice (GraphicsAdapter adapter, DeviceType deviceType, IntPtr renderWindowHandle,

       CreateOptions creationOptions, PresentationParameters presentationParameters)

 

       注意,与MDX不同,GraphicsDevice只有一个构造函数,不过这已经足够我们学习好一阵了。在编写winFormweb程序时,你也许很容易就猜出某个陌生构造函数中参数的含义,不过对于XNA中的函数,你恐怕就很难猜出其中含义了。一个一个来看这些参数:

 

GraphicsAdapter示使用哪一个图形硬件创建GraphicsDevice对象。系统中可能会有多块显卡,你必须指定使用其中的哪一个。就像画家可能有很多画笔,但每次只使用一支。计算机中的每个图形加速器都有一个唯一的适配器标示符,它通常是一个32位的整数,并且从0开始计数。比如你的计算机中有2块显卡,那么它们的标示符就分别为01GraphicsAdapter类中的静态成员Adater集合包含了系统中所有可用的图形加速器标示符。集合中的第一个元素,也就是Adapter[0]总代表默认的图形设备。

       此外,GraphicsAdapter对象还能提供一些有用的信息,比如所支持的显示模式,显卡的驱动程序文件和版本,芯片类型,制造商ID等等。

 

DeviceType:表示所创建的GraphicsDevice类型。DeviceType枚举共有三个值,其中最常用的就是Hardware,他表示将充分利用硬件的图形加速功能来绘图。Reference则意味着所有操作都由软件来模拟,完全放弃图形硬件的加速功能。通常只有在调试程序,或者使用图形硬件所不支持的功能时才使用这个选项。注意,用Reference设备来绘图将相当,相当慢。此外,终端用户所安装的DirectXXNA运行时是不支持Reference设备的。至于另外一个枚举值,你暂时可以忽略它了。

 

IntPrt是一个指向windows form控件的句柄。把GraphicsDeivce绑定到一个特定控件上,并且在这个控件上绘图。可以使用formpanel或其他类型的控件,但大多数情况下都使用form

 

CreateOptions:用来GraphicsDevice创建之后的工作行为。最常见的值是HardwareVertexProcessing,表示所有顶点变换都由硬件来进行。你可以把合适的值组合起来使用,比如CreateOptions.HardwareVertexProcessing | CreateOptions.SingleThreaded。更多信息请参考帮助文件。

 

PresentationParameters:这是一个比较复杂的参数,用来设置许多基本的显示属性,包括刷新率,分辨率,是否以全屏模式绘图,抗锯齿模式,以及后备缓冲和深度/模板缓冲的属性。

       这里有必要介绍后备缓冲(BackBuffer的概念。如前所述,如果把GraphicsDevice比作画笔,那么后备缓冲就是画板。它是显卡中的一块显存,每一帧画面中所要渲染的图形都先保存到后备缓冲中,所有图形绘制完毕以后,再把整块内存提交给显示器,因此,有时也把它称为帧缓冲。提交给显示器的,当前正在显示的缓冲则称为前缓冲(FrontBuffer)。因为需要连续绘图,所以可能有一块以上的后备缓冲,以便把其中一块提交给显示器之后,可以继续在另一块缓冲中绘图,这样就形成了一个缓冲链。

       缓冲链的大小和所选择的缓冲交换模式SwapEffect有关。这个枚举有三个成员:copy模式下,将把当前后备缓冲中所储存的数据进行复制,然后显示。所以缓冲链中只需要一块缓冲,使用它进行重复绘制。Filp模式下,缓冲链将成为一个环,当前进行绘制的后备缓冲将成为下一帧的前缓冲,而当前的前缓冲则变为下一帧的后备缓冲。Discard是默认的交换模式,允许驱动选择最高效的交换方式来管理缓冲交换。它是一个队列,其中的0号元素总代表下一帧将要显示的后备缓冲,而这块缓冲一旦成为前缓冲后,就从队列中移出。

       特别需要注意的是,在全屏和窗口模式下,PresentationParameters成员值的行为是不同的。这里不再逐一讨论,详细的介绍已经甚至可以单独成文了,请仔细参考帮助文档中个成员用法。

 

Hello XNA

       哦,仅仅一个构造函数就讲了那么多,你是否已经对学习xna有些退缩了。不要担心,对于初学来说,通常使用参数的默认值就行。是时候来编写一些代码了。

       安装了XNA Game Studio Express之后,你大概已经尝试过使用XNA模板生产的程序了,Game类非常简便易用,不是吗。可惜这个类太过于高级了,以至于隐藏了太多XNA的基础知识。所以我们将暂时忽略这个高级类,重新发明轮子,编写一个最简单的XNA程序。

       首先,打开XNA Game Studio Express,新建一个windows应用程序,是的,你没有看错,普通的Windows Application项目。之后,添加对XNA程序集的引用:


       Solution Explorer窗口中右键点击References项,在弹出菜单中选择Add Reference。在弹出的窗口中选中以下三个程序集,点击OK

       Solution Explorer窗口中,打开Form1.Designer.cs文件,编写代码添加对xna名称空间的引用:

 

     using Microsoft.Xna.Framework;

     using Microsoft.Xna.Framework.Graphics;

 

       为了使用XNA绘图,首先要创建GraphicsDevice对象。把它作为Form1的一个私有成员,添加如下代码:

 

     private GraphicsDevice graphicsDevice;

 

       接下来,把创建GraphicsDevice对象的实例的代码放到一个名为“InitializeGraphics”的函数中:

 

        public void InitializeGrahics()

        {

            PresentationParameters presentParsms = new PresentationParameters();

            presentParsms.IsFullScreen = false;

            presentParsms.SwapEffect = SwapEffect.Discard;

 

            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, CreateOptions.HardwareVertexProcessing , presentParsms);

        }

 

       这里先创建PresentationParameters参数,并设置了几个重要的参数值,当然,你也可以根据需要,选择设置其它成员的值。使用默认的图形加速器来创建graphicsDevice对象,注意GrahicsAdapter.DefaultAdapterGraphcisAdapter.Adapters[0]是相等的。第二和第四个参数表示将充分使用图形硬件的加速功能。之后,this.Handle把当前窗口,也就是Form1绑定到了graphicsDevice对象上,表示我们只能对这个窗口进行绘图。

       打开Program.cs文件,把Main()函数修改为以下代码:

 

     static void Main()

     {

         using (Form1 frm = new Form1())

        {

            frm.Show();

            frm.InitializeGrahics();

            Application.Run(frm);

          }

      }

 

       虽然对原来的代码稍稍做了改变,但它仍然是相当标准的winForm程序初始化代码。需要提醒的是必须在Run方法之间调用InitializeGraphics方法。后面我会告诉你这样做的原因。

       好了,现在运行程序,可以看到和普通的winForm程序完全一样。显然,我们只是创建了graphicsDevice对象,还没使用它来绘图,绘图任务仍然是由GDI+来完成,因此,我们必须重载Form1OnPaint方法。程序运行之后,每次需要重新绘制窗口,都会调用这个函数绘图,也就是为什么必须确保在程序运行前创建graphicsDevice对象。在Form1中添加以下代码:

 

     protected override void OnPaint(PaintEventArgs e)

     {

         graphicsDevice.Clear(ClearOptions.Target, Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue, 1.0f, 0);

         graphicsDevice.Present();

     }

 

       还记得我们把后备缓冲比做画板吗,显存中可能包含着一些随机的数据,所以如果我们只是在后备缓冲中的部分区域绘图,那么显示时,未绘制过的部分中的随机数据也会被呈现出来,就像在一张不干净的画板上绘图一样。这当然不是我们想要的效果,应该在绘图前把画板“清洗”,或者说填充为预期的背景颜色。这就是Clear()方法的任务。它的第一个参数代表我们希望对哪种缓冲进行清洗,目前只需要使用Target参数就可以了,在后面的内容中会讨论其他选项。第二个参数则是我们预期的背景颜色。画家通常钟情于白色,而图形开发者更加偏爱黑色或者蓝色,当然,也可以是任何你喜欢的颜色,后面两个参数用来初始化深度和模板缓冲值,暂时可以忽略它们。

       至于Present()函数,它的任务就是在绘图结束之后,把后备缓冲提交给显示器,也就是完成前面所说的把后备缓冲变为前缓冲的任务。

       再次运行程序,可以看到窗口已经变为淡蓝色了。恭喜,你完成了第一个XNA程序。目前,只清洗了后备缓冲,并没有绘制其他图形,因此,窗口只显示一片实心蓝色。如果删除Clear(),并且你还运行过其他3D程序,那么再次运行Form1,则有可能看到一些混乱的图形。


~~~~~~~~~~~未完待续~~~~~~~~~~~


^_^

 

原创粉丝点击