Xna 4.0提供了多种方法实现shader特效,都通过类型Effect接口实现。这里介绍一种通过代码生成器生成Effect访问类型的方法。
实现自定义Shader特效的通常做法
通常的做法是通过将实现shader的.fx文件加入到Content项目中,在Build的过程中生成编译完成的二进制.xnb资源文件,接着在运行时载入这些Effect资源,并通过Effect接口进行shader变量的数据绑定。比如对于这样的一个简单的调整图片饱和度的特效SaturationEffect.fx:
sampler BaseSampler : register(s0); float Saturation = 0.5f; float4 PS(float2 texCoord : TEXCOORD0) : COLOR0 { float4 color = tex2D(BaseSampler, texCoord); float grey = dot(color, float3(0.3, 0.59, 0.11)); return lerp(grey, color, Saturation); } technique Default { pass Pass1 { PixelShader = compile ps_2_0 PS(); } }
在使用时,我们需要先载入,并用字符串引用来为变量Saturation赋值:
Effect saturation = Content.Load<Effect>("SaturationEffect"); saturation.Parameters["Saturation"].SetValue(0.3f);
这种做法有两点不完美的地方:一是访问变量需要通过字符串字典,增加了出错的可能。二是编译完成后的.fx文件要作为资源文件复制到可执行文件的目录下,不适合于类库之类的应用(当然可以使用一种比较麻烦的办法,就是将.xnb作为资源文件嵌入到dll中,然后使用ResourceContentManager来载入)。
使用EffectCustomTool实现自定义Shader特效
由于Xna 4.0在Windows Phone 7平台上的实现使用OpenGl ES,所以上层的API不支持自定义HLSL特效,于是这个从1.0时代就孤身一人的BasicEffect终于有了3个兄弟姐妹:SkinnedEffect, DualTextureEffect和EnvironmentMapEffect(我们姑且认为DualTextureEffect和EnvironmentMapEffect是两位男性,因为他们都比较花心,一个脚踏两只船,一个到处看美女;而SkinnedEffect是个女生,因为她比较在意保养自己的皮肤==!)。而通过使用EffectCustomTool,可以使得我们很容易的实现以这些内置特效的使用方法来使用我们自己的自定义特效(从此你可以在项目中让Effect轻松又惬意的生出一个足球队)。具体过程如下:
1下载并安装 EffectCustomTool for Visual Studio 2010
最新版本的EffectCustomTool 1.2支持最新的Xna 4.0 Beta以及VisualStudio 2010(包括Visual CSharp Express 2010以及Visual Studio 2010 Express for Windows Phone),并修正了一些重命名的bug。 本文以Xna 4.0为例,如果你使用的是Xna 3.1,请下载EffectCustomTool 1.1。
2打开Xna 4.0的游戏项目,将需要使用的.fx文件加入到游戏项目中。注意,不是原来的Content项目。
3设置所使用的.fx文件的CustomTool属性为EffectCustomTool。
4右击所使用的.fx文件,选择Run CustomTool。
5这时访问Shader的C#类就自动生成完毕。同时会生成两个子文件:.cs和.Designer.cs。
使用SpriteBatch和自定义Shader绘制特效图片
Xna 4.0中的SpriteBatch增强了对自定义Effect的支持,使得我们可以很方便的为图片添加自定义特效。
1首先载入一张用于渲染的背景图。同时我们像创建BasicEffect的方法一样new出来一个SaturationEffect。并设置Saturation属性为0.3f.
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); saturation = new SaturationEffect(GraphicsDevice); saturation.Saturation = 0.3f; background = Content.Load<Texture2D>("Background"); }
2使用Xna 4.0中SpriteBatch的新特性来绘制自定义特效。
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.AnisotropicWrap, DepthStencilState.None, RasterizerState.CullCounterClockwise, saturation); spriteBatch.Draw(background, GraphicsDevice.Viewport.Bounds, Color.White); spriteBatch.End(); base.Draw(gameTime); }
3原背景图以及最终的绘制结果:
4EffectCustomTool 1.2程序、代码及示例下载。