zoukankan      html  css  js  c++  java
  • [翻译]XNA外文博客文章精选之eleven


    PS:自己翻译的,转载请著明出处

                                                              在XNA中对Sprites使用HLSL
                                                                                            Aaron T Foley
    目的
                                       这篇教程深入研究如何对XNA中的精灵使用HLSL。
    导言
                                       因为游戏变的越来越复杂,老游戏有时对新的玩家失去它们的吸引力,正因为它们缺乏影响。所以通过执行HLSL在我们的2D游戏里,我们可以创建一些惊人的视觉效果的2D游戏。

    第一步:创建一个新的工程并且包含艺术品
                                       为了开始我们需要去创建一个新的工程。
    为了创建一个新的工程
                1.打开XNA游戏的Studio Express
                2.点击File菜单,然后点击New Project去创建一个新的项目
                3.从出现的模板表单中,选择Windows Game 或者Xbox360 Game
                4.为你的游戏在Name区域输入一个名字,选择一个路径你想要这个游戏文件保存在你指定的地方
                5.点击OK

                                       现在我们有我们创建的基础工程,让我们添加我们想使用的艺术品。
    为了添加艺术品到你的项目中
                1.确保你可以看见你项目的Solution Explorer在窗口的右部。如果你不能看见它,点击View菜单,并且稍后点击Solution Explorer.当它出现时,你会看见文件在你工程的树状结构结合在一起了。
                2.右-击Content文件夹在Solution Explorer,点击Add,然后点击Existing Item.使用出现的对话框,浏览到你艺术品所在位置的路径。选择你的两个纹理。如果你不能看见这个纹理,确保你改变了文件的选择框盒子的Files of type,去读取Content Pipeline Files,点击OK.
                                       一旦你完成你应该做的就象这里。

    第二步:初始化
                                       现在好了,我们有我们的工程设置,让我们得到我们主要的游戏类的设置。首先让我们通过声明我们的变量。为了这个例子我们装备使用一个Texture2D,它代表我们之前加载的内容。为了实现这个,到我们的Game1类的声明区域,添加下面的代码在GraphicsDeviceManager和SpriteBatch的后面。
    1 Texture2D myImage;
    2 float Intensity = 0.5f;
    3 Effect myEffect;
                                       这里声明一个叫做myImage的Texutre2D类型的变量,一个浮点型的变量叫做Intensity并且设置它的默认值为0.5,一个Effect叫做myEffect,它包含我们的HLSL效果。这个Intensity变量在我们使用它去调整我们的键盘或者控制台的设置后开始活动。
                                       现在,我们有我们的基本声明,我们需要去初始化我们的图象并且加载某些东西到它里面。最好在我们的Game1类的LoadContent()方法中去做这个。添加下面的代码行。
    1 myImage = Content.Load<Texture2D>("miho");
    2 myEffect = Content.Load<Effect>("hlsl");
    3 myEffect.Parameters["Intensity"].SetValue(Intensity);

                                       好吧,我们设置我们图象和effect的这两个声明,在我们的Content目录中使用任何我们有的文件。你提供给这里的资源名字是你给你的文件名的名字一样,它是你之前添加到Content文件夹中的文件。
    注意
                                       默认的当我们添加在content它的名字成为没有扩展名的文件。
                                       正如你看见的我们使用一个涉及的资源名称,它还不存在呢。在目前这是正常的;我们马上就会得到。目前我们将使用它去设置所有我们的基础代码,这样我们可以把精力集中在后面的HLSL文件上。
                                       同样我们可以使用myEffect去设置一个没有我的HLSL文件的参数。任何参数我们想传递到HLSL文件中,我们可以用以后使用这个方法来实现它。简单的输入相同的参数名,在HLSL文件中,并且设置我们需要的值。
                                       现在我们拥有一切初始化,让我们为我们的更新添加代码。

    第三步:Update方法
                                       现在我们将继续到我们的更新方法中。这里我们将添加一对键盘和手柄命令去调整我们的动态效果,在程序运行的时候。首先我喜欢添加一些多的代码,这样Windows用户可以退出这个程序使用键盘的Escape键。然后我添加到键里去调整Intensity(译者:强度)的大小。这里是完整的Update()方法的样子。

     1 protected override void Update(GameTime gameTime)
     2 {
     3         // Allows the game to exit
     4         if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
     5         {
     6             Exit();
     7         }
     8         if (Keyboard.GetState().IsKeyDown(Keys.Q) || GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed)
     9         {
    10             Intensity = Intensity - 0.01f;
    11             myEffect.Parameters["Intensity"].SetValue(Intensity);
    12         }
    13         if (Keyboard.GetState().IsKeyDown(Keys.E) || GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed)
    14         {
    15             Intensity = Intensity + 0.01f;
    16             myEffect.Parameters["Intensity"].SetValue(Intensity);
    17         }
    18         base.Update(gameTime);
    19 }

                                        正如你看见的,依赖这个键压下我们调整Intensity上或下通过0.01,然后使用这个与前面相同的方法 去设置Intensity在我们的HLSL文件中。

    第四步:绘制方法
                                        现在我们有我们的Update()和LoadContent()方法,让我们跳入我们的最终的Game1类的代码中。

     1 protected override void Draw(GameTime gameTime)
     2 {
     3         graphics.GraphicsDevice.Clear(Color.Black);
     4         spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate,SaveStateMode.None);
     5         myEffect.Begin();
     6         myEffect.CurrentTechnique.Passes[0].Begin();
     7         spriteBatch.Draw(myImage, new Vector2(0.0f0.0f),Color.White);
     8         myEffect.CurrentTechnique.Passes[0].End();
     9         myEffect.End();
    10         spriteBatch.End();
    11 }

                                         正如你看见,让我们从上部开始。首先我们设置每一祯我们的鲜明的色彩并且清除背景。这里我使用Black去代替CornflowerBlue,因为我想我将使用它有非常动态的效果。接下来,我们设置我们的SpriteBatch开始收集我们要绘制的信息。为了HLSL去工作在SpriteBatch中,我们需要确保我们使用SpriteSortMode.Immediate在我们的Begin()参数,否则我们的效果不会显示出来。这将导致batch应用新的图形设备设置,并且在每次Draw()调用上绘制所有的精灵。接下来我们调用我们的Begin()方法为我们的Effect。任何我们的Effect在Begin()和End()方法之间将会被HLSL文件影响。接下来我们设置我们想要从我们的HLSL文件中使用它的pass。然后我们绘制我们的精灵到屏幕上。这里我刚才做了一些基础的事情。我把这个精灵放在屏幕的(0,0)并且使用白色作为它的颜色。最后我们End()我们的pass,然后End()我们的Effect,End()我们的spriteBatch.现在我们有一个完成的Draw()方法,让我继续我们的HLSL文件。

    第五步:HLSL 文件(.FX)
                                         接下来我们需要去创建我们将要使用的基础HLSL文件,这个创建类似于我们之前在content内添加。To add an Effect file(.FX)to your project(为了添加一个Effect文件到你的项目中)
                      1.确保你可以看见窗口的右边的你项目的Solution Explorer。如果你不能看见它,点击View菜单,然后点击Solution Explorer.当它出现,你将会可那件文件结合在你的树型结构中。
                      2.右-击在Solution Explorer的Content文件夹,点击Add,然后点击New Item.使用这个出现的对话框,选择模板的Effect File.命名这个Efect File不管你叫它什么作为你前面资源的名字在你的项目中,当你初始这个myEffect变量。点击OK。
                                         现在我们应该有我们的基础Effect File。这里应该给你有大量的代码,所以只有全部选择并且删除它。我们将从头开始学,去了解做更多的事情。
                                         就象所有的C程序语言,我们需要一个起始点。所以让我们看起始点象这样。

    1 technique myEffect
    2 {
    3     pass p0
    4     {
    5         PixelShader = compile ps_2_0 Brightness();
    6     }
    7 }
                                         由于我们没有声明我们的基本technique(技巧)。我们默认使用它去找到第一个在这个文件中并使用它。稍后这是有用处的如果你选择去使用多个techniques(技巧)。所有你应该必须做的是使用这个命令行。
    1 myEffect.CurrentTechnique=myEffect.Techniques["myEffect"];
                                         接下来我们将会看见我们的pass信息。这里我们定义我们第一个pass作为p0,这个数代表相应的索引在我们的myEffect.CurrentTechnique.Passes[0].Begin();在我们的Draw()方法中。
                                         接下来我们声明这个pass将会被用一个PixelShader和它将会被编译,它的Shader Model版本我们将会使用(在这种情况下是2.0),象素着色器的功能名字将会被使用(在Brightness()的情况下)。
                                         接下来我们需要去声明我们将会使用的变量,我们的象素着色器的Brightness()功能。所以我们返回文件的上部并且添加下面的代码。
    1 float Intensity = 0.5f;
    2 sampler2D clrSampler;
    3 float4 Brightness(float2 Tex : TEXCOORD0) : COLOR0
    4 {
    5     float4 Color;
    6     Color = tex2D(clrSampler, Tex.xy) * Intensity;    
    7     return Color;
    8 }
                                         首先你会看见我们的变量,我们传递数据在我们的Game1代码中。我们会使用这个变量去调整这个明亮效果的程度。接下来我们定义我们的Sampler(取样器)为我们所有的颜色数据。这个2D(x,y)代表所有在我们的图象中的颜色信息,我们将会使用它。
                                         接下来,我们有我们的Brightness()函数。正如看见的,它有一个返回值是float4,意思是它将传回四个floats和所有方式的结尾,我们看到冒号后面的是叫做句法。这个句法基本上是一个这个函数的模板。所以在这种情况下我们使用这个颜色数据在寄存器0的模板功能。我们使用寄存器0,因为此时我们不能使用多个纹理,所以默认的所有信息传入到我们的HLSL文件里,是在寄存器0中。现在在我们的参数里,我们看见一些相似的地方。这里我们有一个float2,用TEXCOORD0的句法命名的Tex。所以意思我们通过使用在寄存器0中(X,Y)坐标收集纹理信息。
                                         现在,我们有我们的函数声明,让我们进入函数中。首先让我们声明一个变量去保存我们的新颜色信息。然后我们通过使用tex2D()功能去设置这个信息。这个函数使用我们前面定义的取样器,去得到从我们的纹理得到的纹理信息。这个信息是通过使用(点)扩展提取出来。从我们的坐标的xy.然后通过我们的Intensity乘以它。
                                         因此,在本质上是这样做的...
                                         假设我们在纹理的(0,0)位置,我们用一个颜色(100,100,100,255)象素.它接收这个信息并且然后转换它成一个从0到1的值。所以它接收Red值并且找到它的值是100/255或者0.39。它与我们其他的值相同。然后它接收我们的Intensity变量并且乘以它自己的每一部分。所以我们说Intensity是0.5。意思我们的Red值是(100/255)*0.5=0.39*0.5=0.195。它在0到255范围内可能是49.725。
                                         这是所有的代码。编译它,试一试看它做了些什么。这仅仅是HLSL的冰山一角,还有许多不同的效果。你可以通过改变a couple of things去实现它。
                                          下面是一组有趣的效果。

    Brightness

    1 float4 Brightness(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy) * Intensity;    
    5     return Color;
    6 }

    Top fade
    1 float4 TopFade(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy) * Tex.y; 
    5     return Color;
    6 }

    Left fade
    1 float4 LeftFade(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy) * Tex.x; 
    5     return Color;
    6 }


    Top/Left fade

    1 float4 TopLeftFade(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy) * Tex.y * Tex.x;      
    5     return Color;
    6 }

    Color hues

    1 float4 ColorHue(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy);
    5     Color.g *= Intensity;     
    6     return Color;
    7 }

    Color glow

    1 float4 ColorGlow(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy);
    5     Color.g /= Intensity;     
    6     return Color;
    7 }

    Multi Color glow

    1 float4 MultiColorGlow(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = tex2D(clrSampler, Tex.xy);
    5     Color.rg /= Intensity;    
    6     return Color;
    7 }

    Scaling

    1 float4 Scale(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Tex.xy *= Intensity;
    5     Color = tex2D(clrSampler, Tex.xy);
    6     return Color;
    7 }

    Panning

    1 float4 Pan(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Tex.xy += Intensity;
    5     Color = tex2D(clrSampler, Tex.xy);
    6     return Color;
    7 }

    Fishbowl

    1 float4 Fishbowl(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Tex.xy = Tex.xy + (sin(Tex.xy * Intensity)* 0.1);
    5     Color = tex2D(clrSampler, Tex.xy);
    6     return Color;
    7 }


    Note
                                            这很难说一个单独的屏幕截图。尝试下,并且来回调整强度。
    Blur

     1 float4 Blur(float2 Tex : TEXCOORD0) : COLOR0
     2 {
     3     float4 Color;
     4     Color =  tex2D(clrSampler, Tex.xy);
     5     Color += tex2D(clrSampler, Tex.xy + (0.01));
     6     Color += tex2D(clrSampler, Tex.xy + (0.02));
     7     Color += tex2D(clrSampler, Tex.xy + (0.03));
     8     Color = Color / 4;
     9  
    10     return Color;
    11 }


    Grayscale

    1 float4 Grayscale(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3       float4 Color;
    4       Color.a = 1.0f;
    5       Color = tex2D( clrSampler, Tex.xy);
    6       Color.rgb = (Color.r + Color.g + Color.b) / Intensity;
    7       return Color;
    8 }

    Negative
    1 float4 Negative(float2 Tex : TEXCOORD0) : COLOR0
    2 {
    3     float4 Color;
    4     Color = 1 - tex2D(clrSampler, Tex.xy);
    5     Color.a = 1.0f;
    6     return Color;
    7 }


    结论
                                          正如你看见的这里使用精灵的HLSL有无限的可能。只要想下所有可与2D游戏也做的事情。我希望本教程可以帮助你。如果任何人有任何疑问,枪毙我的电子邮件在slyprid@sbcglobal.net
    源代码:http://www.ziggyware.com/readarticle.php?article_id=147
    (完)

  • 相关阅读:
    深信服入职前编码训练21题--02
    深信服入职前编码训练21题--01
    Leetcode本地阅读器开发--01界面设计三
    Leetcode本地阅读器开发--01界面设计二
    Leetcode本地阅读器开发--01界面设计一
    使用DDMS测试安卓手机APP的性能(android)
    在PC上测试移动端网站和模拟手机浏览器的5大方法
    SeleniumIDE与eclipse如何连接使用
    Selenium RC配置
    Selenium IDE- 不同的浏览器
  • 原文地址:https://www.cnblogs.com/315358525/p/1563145.html
Copyright © 2011-2022 走看看