1. 我们先来看Lens FLare这个例子:
经过了这一章后边几节基本上不再有什么新的东西了,都是对前两个例子的变换。
唯一值得一提的是一个纹理缩放公式:
1 texCoord = (texCoord-0.5)*(Scale) + 0.5;
不停的对可渲染纹理中的图像进行缩放,当Scale取负值的时候,就是带符号的缩放,实际上就是就是把图像旋转了180°。
下边我们来看Vertex Shader的代码:
1 float4x4 view_proj_matrix;
2 struct VS_OUTPUT
3 {
4 float4 Pos: POSITION;
5 float2 texCoord: TEXCOORD0;
6 float2 texCoord1: TEXCOORD1;
7 float2 texCoord2: TEXCOORD2;
8 float2 texCoord3: TEXCOORD3;
9 float2 texCoord4: TEXCOORD4;
10 };
11 VS_OUTPUT vs_main(float4 Pos: POSITION)
12 {
13 VS_OUTPUT Out;
14 // Simply output the position without transforming it
15 Out.Pos = float4(Pos.xy, 0, 1);
16 // Texture coordinates are setup so that the full texture
17 // is mapped completely onto the screen
18 float2 texCoord;
19 texCoord.x = 0.5 * (1 + Pos.x - 1/128);
20 texCoord.y = 0.5 * (1 - Pos.y - 1/128);
21 Out.texCoord = texCoord;
22 // Compute the scaled texture coordinates for the ghost images
23 Out.texCoord1 = (texCoord-0.5)*(-2.0) + 0.5;
24 Out.texCoord2 = (texCoord-0.5)*(2.0) + 0.5;
25 Out.texCoord3 = (texCoord-0.5)*(-0.6) + 0.5;
26 Out.texCoord4 = (texCoord-0.5)*(0.6) + 0.5;
27 return Out;
28 }
一个普通的不能在普通的RTT了,Full texture纹理坐标还是要进行计算的(代码19-20行),因为它要用于进行计算缩放纹理坐标(scaled texture coordinates,代码23-26行)。
下边我们再看Pixel Shader代码:
1 float viewport_inv_height;
2 float viewport_inv_width;
3 float Glow_Factor;
4 sampler Texture0;
5 sampler Texture1;
6 float4 ps_main (float2 texCoord: TEXCOORD0,
7 float2 texCoord1: TEXCOORD1,
8 float2 texCoord2: TEXCOORD2,
9 float2 texCoord3: TEXCOORD3,
10 float2 texCoord4: TEXCOORD4) : COLOR
11 {
12 // Sample all ghost pictures
13 float4 col1 = tex2D(Texture0, texCoord1)*tex2D(Texture1, texCoord1).a;
14 float4 col2 = tex2D(Texture0, texCoord2)*tex2D(Texture1, texCoord2).a;
15 float4 col3 = tex2D(Texture0, texCoord3)*tex2D(Texture1, texCoord3).a;
16 float4 col4 = tex2D(Texture0, texCoord4)*tex2D(Texture1, texCoord4).a;
17 // Combine the ghost images together
18 return (col1+col2+col3+col4)*Glow_Factor;
19 }
上边的Pixel Shader代码:
第一行的 float viewport_inv_height;
第二行的 float viewport_inv_width;
第六行的 float4 ps_main 的第一个参数float2 texCoord: TEXCOORD0都可以去掉, float2 texCoord: TEXCOORD0只在Vertex Shader中有作用,Pixel Shader中没有任何作用。
然后我们再来看
13 float4 col1 = tex2D(Texture0, texCoord1)*tex2D(Texture1, texCoord1).a;
14 float4 col2 = tex2D(Texture0, texCoord2)*tex2D(Texture1, texCoord2).a;
15 float4 col3 = tex2D(Texture0, texCoord3)*tex2D(Texture1, texCoord3).a;
16 float4 col4 = tex2D(Texture0, texCoord4)*tex2D(Texture1, texCoord4).a;
Q1:为什么Texture1的采样坐标不是float2 texCoord: TEXCOORD0呢(Texture0坐标是Full texture纹理坐标,Texture1是缩放后的纹理坐标)????
A1: 我们拿绘制Ghost的第一个Pass中的采样来举例,如果使用Full texture纹理坐标会发生什么情况,正好做一个实验,如下图:
第一幅图是未对缩放后的图片进行Mask处理,上边有很多的条纹(因为我们纹理采样使用的时clamp模式)
未对缩放后的图片进行透明度Mask处理
第二幅图是对缩放后的图片进行Mask处理,但是使用的是Full texture纹理坐标:
这个很容易理解,因为用来Mask的图像是在Full texture空间中进行的,所以它只对屏幕空间圆心处的像素进行保留,其他位置全部Mask掉;
第三副图片就是该书中所采取的,利用缩放的纹理坐标采样Ghost,然后对缩放的纹理进行Mask,可以保证,在缩放后空间内,利用缩放后的Ghost图像正确的对图像进行Mask! ,消除硬边(实际上效果也不是很理想:(,有的地方也消除的不好)。
Q2:值得注意的是,图像上放大的纹理,实际上纹理坐标是缩小的,图像缩小的纹理,实际上纹理坐标是放大的 :)
A2:在Vertex shader中将纹理坐标进行了缩放,该纹理坐标被Route进了Pixel Shader中;
然后在Pixel Shader中对纹理进行采样,不管我们的纹理坐标范围是多少,这个2维范围内的纹理都将按照对应的纹理地址模式被绘制到屏幕!!(理解这句是关键)
如果在Vertex Shader中纹理坐标变换为X(0,2),Y(0,2),Route进Pixel Shader中,我们其实将该纹理进行X(0,2),Y(0,2)的采样,并将该采样范围的图像绘制到屏幕上;实际在屏幕上绘制了4遍,但是在我们看起来,图像是缩小了(clamp模式下,只有左上角部分有图像,其他部分是两个边颜色的Clamp);
如果在Vertex Shader中纹理坐标变换为X(0,0.5),Y(0,0.5),Route进Pixel Shader中,我们其实将该纹理进行X(0,0.5),Y(0,0.5)的采样,并将该采样范围的图像绘制到屏幕上;实际在屏幕上绘制了四分之一的图像,但是在我们看起来,图像是放大了(这里我们就不管是不是Clamp了,因为根本不需要这个地址模式就可以确定纹理坐标范围内的颜色);
(以上举例是以纹理坐标原点为中心的,以纹理为中心一个道理——这是我能想到的最好的解释方式了,If you have a better one, please let me know;)
2. 然后我们再来看Put them together这个例子,实际上就是将Glare,Streak,Lens Flare放在一起,所有的Renderable texture,Pass,纹理资源,变量等等统统糅合在一起——这个简直就是噩梦:( ,组织数据繁琐一些,然后对Pixel Shader稍作修改。
//This is the final Pixel Shader Code...................
//We need to apply some changes....
1 sampler Texture0; //This is for Ghost Image 2 3 sampler Texture1; //This is for Blooming 4 sampler Texture2; 5 sampler Texture3; 6 7 sampler Texture4; //This is for Streak 8 sampler Texture5; // 9 sampler Texture6; // 10 sampler Texture7; // 11 12 float Streak_Factor; 13 float Ghost_Factor; 14 float Glow_Factor1; 15 float Glow_Factor2; 16 float Glow_Factor3; 17 18 float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR 19 { 20 float4 col; 21 22 // Glow 23 col = float4((tex2D(Texture1,texCoord).xyz)*Glow_Factor1,1.0) + 24 float4((tex2D(Texture2,texCoord).xyz)*Glow_Factor2,0) + 25 float4((tex2D(Texture3,texCoord).xyz)*Glow_Factor3,0); 26 27 // Ghost 28 col += float4((tex2D(Texture0,texCoord).xyz),0); 29 30 // Streak 31 32 col += 33 float4((tex2D(Texture4,texCoord).xyz)*Streak_Factor,0) + 34 float4((tex2D(Texture5,texCoord).xyz)*Streak_Factor,0) + 35 float4((tex2D(Texture6,texCoord).xyz)*Streak_Factor,0) + 36 float4((tex2D(Texture7,texCoord).xyz)*Streak_Factor,0); 37 38 return col; 39 }
注意line23, 只把在第一个颜色的α值设置为1,其他都为0,这样最终颜色的α值是1,根据http://www.cnblogs.com/infintyward/p/3244888.html中讲过的混合原理,将最终返回的颜色与后缓存进行混合。
最终效果图如下。
//end