[翻译]XNA 3.0 Game Programming Recipes之nine
PS:自己翻译的,转载请著明出处
2-13.创建一个模糊/发光的Post-Processing效果
问题
你想在你最终的图象上添加一个模糊的效果,或者你想添加一个发光的对象在你的屏幕上。
解决方案
这两个效果都是post-processing效果。在上一节中学习了怎么设置一个post-processing框架。发光效果的选择,因为它演示了如何融合更多的着色通行的输出。
您可以获取模糊效应计算每个像素的平均颜色值约周围的像素,然后将原来的颜色的像素用这个平均值取代。例如,在图2-25这个网格,它是一个需要被模糊的图象,你如何计算象素9的结果颜色值?
你会发现,总共9个号码被9平均分成9份 。您找到平均颜色用相同的方式:2到4象素求和,8到10象素求和,14到16求和,然后用9象素来分结果。
如果所有的象素都是白的除了象素9,正如图2-26左边那种情况,这种结果是9象素的颜色展开象素2到4,8到10,14到16,它们使象素9"展开"。尽管,象素9的颜色它自己很弱,因为这也是所取代的颜色是指其周围像素。这是显示在图2-26中间部分所示。为了得到发光的效果,混合了初始图象,有些还原原始色彩的像素9 。因此,你最终像素9有其原始颜色和像素9周围的像素有一点象素9的颜色,它们看起来就象象素9那样发光,如图2-26右边所示。
它是如何工作的
有几个忠告,但是。要获得一个不错的模糊,你需要平均超过了很多围绕中心像素像素,以获得一个不错的结果。更好的办法是第一次模糊的图像平均水平的只有几个同一列像素作为中心像素。将结果和模糊这一结果垂直均超过几个相同的列像素作为中心象素。这将使你们两个一维的平均值,而不是一个二维平均, 这将需要您平均多的像素,以获得一个不错的结果。
其次,你应该决定哪些平均像素。您得到最好的结果,中间象素它周围的象素比远处的象素更重要。这被称为给它更多"重量"。为了您的方便,我已有些偏移和计算重量相当于高斯,相当于模糊作为它发生的本质。
下面的表单,它包含了象素的距离。第一个条目有0偏移量,这意味着的中心颜色像素本身将考虑到。第二个项目的0.005偏移量,这将导致采样像素 非常接近中心像素。为了让事情对称,你将样品的两个像素距中心象素0.005的左右象素,你将给它们颜色重量为0.102作为它们最后的颜色,如第二个表单所示。下一步是处理距中心象素有0.0117的左右象素,你将给它一点颜色重量是0.0936。 继续处理直到你远离中心像素的和因此在外层的标一点重量。
2 {
3 0.0f,
4 0.005,
5 0.01166667,
6 0.01833333,
7 0.025,
8 0.03166667,
9 0.03833333,
10 0.045,
11 };
12 float weights[]=
13 {
14 0.0530577,
15 0.1028506,
16 0.09364651,
17 0.0801001,
18 0.06436224,
19 0.04858317,
20 0.03445063,
21 0.02294906,
22 };
注意:该中心像素似乎比较小重量在其他像素的取样里。 然而,由于0和-0是相同的,该中心的像素,将考虑到两次,有效地增加了一倍它的重量,使它的像素将有最有影响力的最终结果。
您也将使用xBlurSize变量,因此您可以调整模糊的宽度从您的XNA应用:
您已经可以创建空机构HorBlur效果在以前的章节的基础上:
2 PPPixelToFrame HorBlurPS(PPVertexToPixel PSIn):COLORo
3 {
4 PPPixelToFrame Output=(PPPixelToFrame)o;
5 return Output;
6 }
7 technique HorBlur
8 {
9 pass Passo
10 {
11 VertexShader=compile vs_1_1 DefaultVertexShader();
12 PixelShader=compile ps_2_0 HorBlurPS();
13 }
14 }
实际效果是用像素着色器指定.从先前列表对每个像素周围界定,您将样品的颜色和分配给它的重量相乘。因为对称原理,所以中心象素的两边都需要这么做。最后,你一起添加所有的象素。
你找到周围的像素的位置,从TexCoord的像素中心和增加这个值从positions数组的横向纹理坐标:
2 {
3 PPPixelToFrame Output=(PPPixelToFrame)o;
4 for(int i=0;i<8;i++)
5 {
6 float4 samplePos=tex2D(textureSampler,PSIn.TexCoord+float2(position[i],0)*xBlurSize);
7 samplePos*=weights[i];
8 float4 sampleNeg=tex2D(textureSampler,PSIn.TexCoord-float2(position[i],0)*BlurSize);
9 sampleNeg*=weights[i];
10 Output.Color+=samplePos+sampleNeg;
11 }
12 return Output;
13 }
这个xBlurSize变量能被用来增加和减少中心点和周围的点之间的距离。
在你的XNA程序的内部,您只需指定一个值到这个变量和激活的效果:
2 ppEffectsList.Add("HorBlur");
3 postProcessor.Parameters["xBlurSize"].SetValue(0.5f);
4 postProcessor.PostProcess(ppEffectsList);
垂直模糊
现在你有了一个水平的模糊,也十分容易建立一个垂直的模糊。增加值positions矩阵的横向纹理坐标,您应该添加到垂直纹理坐标,选择像素同一列的像素作为象素的中心:
2 PPPixelToFrame VerBlurPS(PPVertexToPixel PSIn):COLORo
3 {
4 PPPixelToFrame Output=(PPPixelToFrame)o;
5 for(int i=0;i<8;i++)
6 {
7 float4 samplePos=tex2D(textureSampler,PSIn.TexCoord+float2(position[i],0)*xBlurSize);
8 samplePos*=weights[i];
9 float4 sampleNeg=tex2D(textureSampler,PSIn.TexCoord-float2(position[i],0)*BlurSize);
10 sampleNeg*=weights[i];
11 Output.Color+=samplePos+sampleNeg;
12 }
13 return Output;
14 }
15 technique VerBlur
16 {
17 pass Passo
18 {
19 VertexShader=compile vs_1_1 DefaultVertexShader();
20 PixelShader=compile ps_2_0 HorBlurPS();
21 }
22 }
运用水平和垂直模糊我们得到了一个不错的模糊图象:
2 ppEffectsList.Add("HorBlur");
3 ppEffectsList.Add("VerBlur");
4 postProcessor.Parameters["xBlurSize"].SetValue(0.5f);
5 postProcessor.PostProcess(ppEffectsList);
正如在引进这一章节,您可以取得发光效果生效混合图像和融合中的原始图像一点。通过这种方式,将原来的轮廓变尖锐。
这就需要你有模糊图像中存在后备缓冲区,以便在第二次通过,您可以混合在原始图像。因此,您将定义一个新的技术,发光, 已作为第一个通过垂直模糊,作为第二阶段的通过一个blend-in pass:
这是象素着色器在第二阶段:
2 pppixelToFrame BlendInPS(PPVertexToPixel PSIn):COLORo
3 {
4 PPPixelToFrame Output=(PPPixelToFrame)o;
5 float4 finalColor=tex2D(originalSampler,PSIn.TexCoord);
6 finalColor.a=0.3f;
7 Output.Color=finalColor;
8 return Output;
9 }
总之,百分之70的最终颜色将会从已经在后备缓冲采取(第一阶段的模糊效果被储存)。其余的百分之三十将采取的新的色彩要写回后备缓冲区,而在这种情况下, 从原来的形象里采样。
你还没有定义originalSample。把这个添加到你效果文件的顶部:
2 sampler originalSampler=sampler_state
3 {
4 texture=<originalImage>;
5 magfilter=LINEAR;
6 minfilter=LINEAR;
7 mipfilter=LINEAR;
8 };
2 {
3 device.ResolveBackBuffer(resolveTexture,0);
4 textureRenderedTo=resolveTexture;
5 ppEffect.Parameters["originalImage"].SetValue(textureRenderedTo);
6 }
现在,所有的效果已经准备就绪,此代码将首先垂直模糊图片。随后, 这一结果将首先由横向模糊首次通过的VerBlurAndGlow的效果。 在第一阶段,将继续模糊图像帧缓冲区内,让您共混物中的原始图像!
2 ppEffectsList.Add("HorBlur");
3 ppEffectsList.Add("VerBlurAndGlow");
4 postProcessor.Parameters["xBlurSize"].SetValue(0.5f);
5 postProcessor.PostProcess(ppEffectsList);
课外阅读
每完成游戏中包含了一套后处理的影响,因为它们有潜力将额外的联系到最后的图片。虽然模糊作用是一个相对容易的概念, 某种模糊或发光几乎总是用于一些不完善的3D对象的边缘。
整个系列的后处理的效果确实存在,但与发光效果,利用多种途径和alpha混合,你理解关于它们的基础知识。