Stock Effects示例
原文地址:http://create.msdn.com/en-US/education/catalog/sample/stock_effects。
effects提供了五个effect(BasicEffect,SkinnedEffect,EnvironmentMapEffect,DualTextureEffect和AlphaTestEffect)和SpriteBatch(SpriteEffect)使用的默认shader的源代码,它们都内置在XNA框架中。这个项目还包含一个命令行工具(CompileEffect),它使用Content Pipeline将一个.fx源文件编译为二进制文件,这样二进制文件就可以直接传递到XNA框架的Effect类的构造函数中。
概览
此代码用于教育目的,当你想创建一个更高级的shader时,它可以作为一个很好的出发点。
虽然XNA框架内置的effect类非常简单易于使用,但背后的shader代码是非常复杂的,这是因为在一个shader中需要支持很多绘制的情况。例如,BasicEffect可以让你切换是否选择纹理,顶点颜色、光照,选择逐像素光照还是逐顶点光照。要支持所有的情况,BasicEffect需要至少20个不同的vertex shader和10个pixel shader,它们都编译在一个effect文件中。
如果你想从头学习shader编程,可参见官方网站的Shader Series的示例,这些示例比较简单,因为它们不包含太多的调整选项。
使用Effects
要使用这些stock effect代替内置的effect,需要进行以下步骤:
1. 编译对应的解决方案—StockEffectsWindows.sln或StockEffectsXbox.sln(这基于你的开发平台)。
2. 右击你的项目,选择Add Reference并选择Browse面板。
3. 选择StockEffects\bin\<platform>\Debug\StockEffects.dll. 这个项目提供了六个类:
- BasicEffect
- SkinnedEffect
- EnvironmentMapEffect
- DualTextureEffect
- AlphaTestEffect
- SpriteEffect
但这些shader是在StockEffects命名空间而不是在Microsoft.Xna.Framework.Graphics命名空间中,所以要使用这些shader代替XNA框架内建的shader,只需将代码由:
effect = new BasicEffect(GraphicsDevice);
变为
effect = new StockEffects.BasicEffect(GraphicsDevice);
修改Effecs
要修改shader代码,需要编辑.fx文件,然后重新编译StockEffects.dll。如果你想作出较大改变,或重用你的项目中的shader,你需要理解代码是如何进行编译的。
CompileEffect项目是一个命令行工具,它使用Content Pipeline将一个.fx文件编译到一个二进制文件中。这个操作直接调用EffectImporter和EffectProcessor类,然后保存编译后的effect代码, 这样就绕过了Content Pipeline的处理,因为Content Pipeline的处理会将这些数据嵌入到一个 .xnb格式的文件中,而这并不是我们想要的结果。
StockEffects项目有一个自定义的生成规则,它使用CompileEffect工具编译六个effect文件,要编辑这个规则,你可以进行如下的步骤:
1. 在解决方案浏览器中,右击StockEffects项目。
2. 选择属性,点击Build Events面板,然后点击Edit Pre-build按钮。
你可以看到这个生成规则调用了CompileEffect六次,将每个.fx文件编译到一个.bin文件中,这些文件存储在obj文件夹中。
如果编辑Resources.resx,你会看到它包含了六个来自于obj文件夹的.bin文件,这样编译过的shader代码就嵌入了resource中。这让诸如封装effect的BasicEffect.cs类可以通过Resources.BasicEffect访问effect代码。
如果你想添加或移除shader,你必须:
- 在自定义生成规则中添加或移除编译shader的命令行。
- 从Resources.resx 中添加或移除.bin文件。
Effect Include文件
译者注:下面的两段文字与标题Effect Include文件风马牛不相及,怀疑作者贴错了。此程序包含四个Effect Include文件:Macros.fxh,Structures.fxh,Common.fxh,Lighting.fxh。其中Macros.fxh主要定义了指定寄存器绑定的宏指令用于简化代码,Structures.fxh包含顶点着色器和像素着色器的输入、输出结构定义,Common.fxh包含5个effect所共用的设置代码,Lighting.fxh包含共用的计算光照的代码,使用include文件可以共享重用代码,使effect结构更加清晰。
XNA TouchPanel API provides only a polling interface. 你的游戏可以获取当前的触摸状态,但无法获取触摸的begin/end事件的消息。对这个示例来说会发生一些困难,这是因为玩家的屏幕的初始光标定义了手柄的中心位置,当掉帧时光标可能会丢失,这样中心位置就不是玩家所期望的正确位置,这样会导致控制不正确。
幸运的是,XNA TouchPanel API通过提供TryGetPreviousLocation方法可以部分解决这个问题,这个方法可以保存事件的历史,只要游戏的帧频正常,就能保证控制的正确。
许多内建的effect有着类似的行为。例如所有shader都使用了相同的雾化算法,BasicEffect,SkinnedEffect和EnvironmentMapEffect共享了相同的Blinn/Phong光照模型。为了减少重复代码,这些函数放在了头文件中(Common.fxh, Lighting.fxh, and Structures.fxh),它们包含在所有effect中。
Macros.fxh文件要实现几个功能。这个头文件定义了一些辅助宏,让shader代码可以编译为DirectX 9 Shader Model 2.0(用于XNA Framework Content Pipeline)或Shader Model 4.0(用于DirectX 10和DirectX 11,在语义定义上有所不同)。
Preshaders
在设计effect参数时,一个非常重要的事情就是需要提供一个清晰的API,最终的参数格式并不总是最有效率的。
D3D会通过一个叫做“preshaders”的功能修正某些不匹配错误,HLSL编译器会查找对于所有顶点和像素都相同的计算过程,然后将这些过程从主shader中取出放置在一个特殊的pass中,这个pass会在会在开始前运行在CPU上。这是个很好的功能,但也带来了一些负面影响:
- HLSL编译器并不总能找到优化的方法。
- 计算preshaders的虚拟机效率并不是最高。
- 在Xbox 360或Windows Phone上不支持Preshaders。
替代方法是,Game Studio通过重写Effect.OnApply方法在C#中实现了preshader 计算,Effect.OnApply方法在EffectPass.Apply方法前被调用,而EffectPass.Apply方法将参数设置到图形设备上。
这可以让我们的C# effect包装类将API所需的属性暴露,而无需将这些属性匹配HLSL的底层shader参数。当程序员改变了一个属性时,我们只需设置一个dirty标志,然后在OnApply过程中重新计算HLSL参数。使用这个方法我们预先计算了很多东西:
- 将World,View和Projection矩阵组合到一个WorldViewProj矩阵中。
- 当打开光照时,计算WorldInverseTranspose矩阵,在非比例缩放中,这个矩阵对于正确的对法线进行变换是必须的。
- 从视矩阵中提取EyePosition向量。
- 将FogStart,FogEnd,World和View组合成一个vector,这个vector可以在一次点乘操作中计算雾化程度。
- 将DiffuseColor,EmissiveColor,AmbientLightColor和Alpha属性组合成一个更有效率的组合参数。
发布时间:2010/12/23 下午4:50:04 阅读次数:7003