Clayman的专栏

It's all about XNA & GPU Programming

用户操作
[即时聊天] [发私信] [加为好友]
孙凌峰ID:soilwork
191910次访问,排名382好友0人,关注者12
soilwork的文章
原创 85 篇
翻译 15 篇
转载 0 篇
评论 329 篇
clayman的公告
嘿嘿 ^o^....
最近评论
jym5596337:我也不知道我怎么就走到了你的路上来了呵呵...
太晕了,我们专业就学的C#... 那我就凑合着用它学习MDX喽,但到了2008你的这个时期,感觉形式有点尴尬,以前的人说 在中国搞软件是 前有微软,后有盗版。
现在是 前有XNA后有C++ ... MDX 学习资料太太太难找了。。太太太少了。 师兄给介绍下你学历路途中的资料目录咯。。。我好找来学习咯。。 感谢哦感谢。。
jym5596337:好象没有继续哇 ...
shapin:ATI的网站有个支持HLSL语法高亮的vs插件,可以支持其他版本,只要修改相应的那个注册表就行
flip:To linxv :
貼圖座標有用投影嗎?
linxv:我用了你上面的基本技术,确实实现了纹理扰动,非常感谢!但是有一个问题是那张被扰动的图会跟着摄象机动,不知道是什么原因!
文章分类
收藏
    相册
    blogs
    David Weller
    nVidia Developer blog
    Rico Mariani
    Shawn Hargreaves
    XNA Team blog
    XNA资源
    XNA Creators Club
    ZBuffer
    Ziggyware XNA Resources
    中国XNA开发网
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 XNA教程(二)—— Into the 2D World收藏

    新一篇: be patient~~~ | 旧一篇: XNA教程(一)

      作者:Mike Fleishauer & clayman
    本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
    由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。欢迎大家和我多多交流。
    Blog:
    http://blog.csdn.net/soilwork
    clayman_joe@yahoo.com.cn 
    special thanks to Mike Fleishauer ^_^

            在第一章里,我们介绍了关于XNA的一些基础知识。但坦白的说,至今为止,我们还没有编写任何代码,而且只创建了一个单调的蓝色屏幕。
             这一章,我们将尝试在屏幕上绘制一些东西,简单的2D图形。虽然2D游戏的时代已经渐渐远去,但即使你编写一个全3D的游戏,也不得不处理处理一些2D图形,比如简单的选项菜单、HUDhead up displays)等等。好了让我们开始把。
             打开上一章创建的项目,当然,你也可以创建一个新XNA项目。把解决方案改名为“Chapter2,把工程和Game1.cs都重命名为“Sprite”,当弹出确认更改文件名的对话框时,点击确认。
             接下来,我们将在屏幕上绘制一张2D图片。但在这之前,需要介绍一点关于Sprite的概念。
     
    什么是Sprite
    Sprite,也称为精灵,是一个直接绘制到屏幕上的2D图形。在传统的2D游戏中,你所看到的一切几乎都是sprite。但在3D游戏中,比如Halosprite逐渐演变为了用于增加3D图形视觉效果的纹理。在讨论3D图形时我们会详细讲解它。现在,简单的把sprite认为是2D图形就可以了。
            
             继续,我们将把一些外部资源添加到工程中,为了方便管理,统一把资源放到一个单独的文件夹中。在Solution Explorer邮件点击Add->New Floder,命名为Graphics。接下来,邮件点击新创建的文件夹 Add->Existion Item….在弹出窗口中,导航到安装MC2源代码的目录下,在\Source\Data\Art中,选择mcl_splashscreen_planet_2.tga.文件。(当然,可以选择一张任何你喜欢的图片)。
             接下来,编写代码:
    namespace Chapter2
    {
        partial class Sprites : Microsoft.Xna.Framework.Game
        {
            private Microsoft.Xna.Framework.Graphics.SpriteBatch _sb;
            private Microsoft.Xna.Framework.Graphics.Texture2D _sprite;
            public Sprites()
            {
                InitializeComponent();
                _sb = new SpriteBatch(this.graphics.GraphicsDevice);
                _sprite = Texture2D.FromFile(this.graphics.GraphicsDevice, "../../Graphics/mcl_splashscreen_planet_2.tga");
            }
     
            protected override void Update()
            {
                float elapsed = (float)ElapsedTime.TotalSeconds;
                UpdateComponents();
            }
     
            protected override void Draw()
            {
                  if (!graphics.EnsureDevice())
                    return;
                graphics.GraphicsDevice.Clear(Color.Black);
                graphics.GraphicsDevice.BeginScene();
     
                _sb.Begin();
                _sb.Draw(_sprite, new Vector2(0.0f, 0.0f), Color.Red);
                _sb.End();
     
                DrawComponents();
                graphics.GraphicsDevice.EndScene();
                graphics.GraphicsDevice.Present();
            }
        }
    }
    (加粗部分为我们添加的代码)
             这些代码是什么意思呢?
             首先,我们为Sprite类添加了两个全新的成员:
    private Microsoft.Xna.Framework.Graphics.SpriteBatch _sb;
    private Microsoft.Xna.Framework.Graphics.Texture2D _sprite;
         _sb是一个SpriteBatch对象。SpriteBatch对象代表了一批sprite,并且将在同样的状态设置下,绘制他们。大多数情况下,几乎所有的sprite都在同一个批次中。
         _sprite实际上是一张2D的纹理。它代表了一张将要绘制到屏幕上的图片。我们稍后将讨论不同类型的纹理,现在,只需知道2D纹理储存了在X和Y方向上,每个像素的颜色信息。也可以就把Texture2D认为是一张图片。XNA直接支持jpg,tga,dds,bmp,png格式的文件作为纹理。
    _sb = new SpriteBatch(this.graphics.GraphicsDevice);
         使用GraphicsDevice对象作为参数,实例化SpriteBatch。这里,参数的含义表示以后将用哪一个(一个程序中可以有多个GraphicsDevice)GraphicsDevice对象绘制_sb。
    _sprite = Texture2D.FromFile(this.graphics.GraphicsDevice, "../../Graphics/mcl_splashscreen_planet_2.tga");
             这行代码把图片加载到内存中,实例化Texture2D对象。同样把当前的graphics device和图片的路径作为参数。如果在给定路径没有找到所要的图片,那么这个方法将抛出一个异常。
    graphics.GraphicsDevice.Clear(Color.Black);
             把屏幕清理为黑色。上一节已经介绍过如何使用这个方法。现在我会告诉你为什么需要调用这个方法。如果把渲染比作绘图,那么显存就是我们的画板,通常把用于绘图的显存称为帧缓冲,如何不清理帧缓冲,那么上次在帧缓冲中绘制的图形仍然会保留在其中,并且这些数据处于一种不确定的状态。假设我们下次只在屏幕的左上角绘制图形,那么显示时,除了进行绘制的区域,其他部分可能会显示一些随机数据,相当于我们在一块绘制了大量图形的旧画板上绘图。因此,需要用Clear方法对帧缓冲进行初始化,填充为某个我们希望的背景颜色。
    _sb.Begin();
    _sb.Draw(_sprite, new Vector2(0.0f, 0.0f), Color.Red);
    _sb.End();       
             和之前提到的BeginScenneEndScene一样,_sb.Begin_sb.End方法告诉图形设备我们将要绘制sprite,所有绘制sprite的代码都必须在这两个方法之间。Draw方法是真正绘制图形的地方。这里的参数告诉显卡从坐标位置为(00)的地方开始绘制sprite。注意,绘制sprite的,所使用的是屏幕坐标系,这意味着屏幕中的每个像素对应一个(xy,屏幕左上角的坐标总是(00),而右下的坐标则取决于屏幕分辨率,如果分辨率为1024 x 768那么右下的坐标就是(1024768)。绘制sprite的位置应该在这两个坐标之间。
             运行程序看看吧:

             虽然依旧很单调,但总是有了进步。
             这里你可能会有一些问题:为什么原来蓝色的天空,现在“燃烧”了起来。
             注意看绘制sprite的代码,最后一个参数表示了绘制sprite时的色调。如果我们把它改为Color.White那么将获得和原图一样的效果。你看,使用XNA轻易就能实现一些特效。
             再绘制几个sprite
             现在我们有4个相同大小的sprite了。你已经掌握了2D绘图的基础,足够完成一个2D游戏的背景渲染。再次提醒,所有的2D绘图操作都因该在Begin()End()方法之间,而SpriteBatch方法调用又必须在BeginScene()EndScene()方法之间。简单的说,应该按照以下顺序:
    --       开始渲染3D图形
    l        渲染3D场景
    l        开始渲染2D图形
    n        渲染2D图片
    l        结束2D渲染
    --      结束3D渲染
             需要记住,2D图形的渲染和绘制他们的顺序有关系。在叠加区域,先渲染的图形总是会被后渲染的图形挡住,和在普通画布上绘图的原理一样。这也带领我们进入下一个话题,透明。
     
    Transparent Blits
             首先,如果你要问我Blits是什么含意,那么我要告诉你,实际上你不必知道它是什么意思=.=Blit的含义来自于BLT,表示Block Transfer,意思是把一个平面的一部分复制到另一个平面。好了,关键的问题就在于我们如何把图片中,不透明的部分复制到已有图片上。
             为了渲染一个带透明效果的sprite,先来做一些辅助工作。首先,打开windows中的绘图板,任意绘制一个图形:
             哈哈,我绘制图形的能力确实很惊人,不是吗^_^。接下来,再创建一张同样大小的图片。上一张图片是我们希望显示的部分,而现在这张图片则作为它的透明遮罩:
             一般情况下,遮罩里白色部分是不透明的,而黑色部分则表示透明区域。把两张图片分别保存为uglyStar.jpguglyStarMask.jpg。为了方便使用,把他们都添加到Grahics文件夹中。
             现在打开DirectX SDK中的DxTex.exe程序(它位于sdk安装路径的Utilities\Bin\x86件夹下)。选择File->New Texture…,在弹出的窗口中,把纹理尺寸设置为32x32,把Surface/Volume格式设置为Unsigned 32-bit: A8R8G8B8,如图所示:
             选择“Open onto this surface”,打开我们之前创建的红色星星uglyStar.jpg
             选择“Open onto Alpha Channel of this Surface”,打开uglyStarMask.jpg
             最后把文件保存为star.dds,并添加到Graphics文件夹。
             好了,现在有了一张带透明通道的图片,如何使用他呢。把它绘制到之前的天空上吧。添加如下代码:
    ………………….
    private Microsoft.Xna.Framework.Graphics.Texture2D _spriteStar;
    ………………….
    public Sprites()
    {
         ………………………
         _spriteStar = Texture2D.FromFile(graphics.GraphicsDevice, "../../Graphics/star.dds");
    }
    protected override void Draw()
    {           
         ……………..
         graphics.GraphicsDevice.BeginScene();          
        _sb.Begin(SpriteBlendMode.AlphaBlend);
         _sb.Draw(_sprite, new Vector2(0.0f, 0.0f), Color.White);
         _sb.Draw(_sprite, new Vector2(_sprite.Width, 0.0f), Color.White);
         _sb.Draw(_sprite, new Vector2(_sprite.Width, _sprite.Height), Color.White);
         _sb.Draw(_sprite, new Vector2(0.0f, _sprite.Height), Color.White);
        _sb.Draw(_spriteStar, new Vector2(50.0f, 50.0f), Color.Yellow);
         _sb.End();
     ……………………………
    }
             运行程序,你因该可以看到下图所示的结果:

             注意到我们只显示了红色的部分没有?这都是透明遮罩的功劳。简要来说,你使用DirectX纹理工具,告诉了图片哪些部分需要渲染,哪些部分是透明的,注意这里使用了dds格式的文件,而不是bmp格式。
             你因该对这行代码比较感兴趣:
    _sb.Begin(SpriteBlendMode.AlphaBlend);
             使用AlphaBlend作为SpriteBlendMode参数,会告诉XNA将要渲染一些带透明效果的图片。还记得我先前说过“大多数情况下,几乎所有的sprite都在同一个批次中”吗,好吧,我撒谎了-_-b。Alpha混合通常需要进行额外的计算,因此,应该把需要进行Alpha混合的sprite单独作为一个批次。一个批次用来绘制(静态)背景图片,另一个用来绘制带透明效果的前景物品。作为一条规则,你应该总是把需要alpha混合的sprite作为一个批次:
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Components;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
     
    namespace Chapter2
    {
        partial class Sprites : Microsoft.Xna.Framework.Game
        {
            private Microsoft.Xna.Framework.Graphics.SpriteBatch _sbBackground;
            private Microsoft.Xna.Framework.Graphics.SpriteBatch _sbForeground;
            private Microsoft.Xna.Framework.Graphics.Texture2D _sprite;
            private Microsoft.Xna.Framework.Graphics.Texture2D _spriteStar;
     
            public Sprites()
            {
                this.AllowUserResizing = true;
                this.IsMouseVisible = true;
                InitializeComponent();
                _sbBackground = new SpriteBatch(this.graphics.GraphicsDevice);
                _sbForeground = new SpriteBatch(this.graphics.GraphicsDevice);
                _sprite = Texture2D.FromFile(this.graphics.GraphicsDevice, "../../Graphics/mcl_splashscreen_planet_2.tga");
                _spriteStar = Texture2D.FromFile(graphics.GraphicsDevice, "../../Graphics/star.dds");
            }
     
            protected override void Update()
            {
                 float elapsed = (float)ElapsedTime.TotalSeconds;
                UpdateComponents();
            }
     
            protected override void Draw()
            {
                 if (!graphics.EnsureDevice())
                    return;
                graphics.GraphicsDevice.Clear(Color.Black);
                graphics.GraphicsDevice.BeginScene();
                _sbBackground.Begin();
                _sbBackground.Draw(_sprite, new Vector2(0.0f, 0.0f), Color.White);
                _sbBackground.Draw(_sprite, new Vector2(_sprite.Width, 0.0f), Color.White);
                _sbBackground.Draw(_sprite, new Vector2(_sprite.Width, _sprite.Height), Color.White);
                _sbBackground.Draw(_sprite, new Vector2(0.0f, _sprite.Height), Color.White);          
                _sbBackground.End();
                _sbForeground.Begin(SpriteBlendMode.AlphaBlend);
                _sbForeground.Draw(_spriteStar, new Vector2(50.0f, 50.0f), Color.White);
                _sbForeground.End();
                DrawComponents();
                graphics.GraphicsDevice.EndScene();
                graphics.GraphicsDevice.Present();
            }
        }
    }
             好了,第二部分到次结束,下一章,我们将让sprite动起来~~。
     

    发表于 @ 2006年09月17日 01:51:00|评论(loading...)|编辑

    新一篇: be patient~~~ | 旧一篇: XNA教程(一)

    评论

    #xnacn.net 发表于2006-09-17 15:12:00  IP: 222.125.137.*
    clayman,谢谢啦!我们都是爱好者而已。另外我也是看到mike在微软论坛上的留言才找到你这里的,他好象看到他的文章被翻译成中文版本很是激动,所以我想他也是支持我们的做法的。再次谢谢你的辛苦工作。你翻译真的很不错!我也在翻译一些文章,以后多交流!接下来的第三章我就不趁人之美,期待你接下来的文章。
    #Lynx 发表于2008-02-02 12:27:54  IP: 58.63.93.*
    没3D 图型计算基础看这个还是理解有点困难啊!
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © clayman