Looking Through A Filter 通过滤波器观察
渲染目标render target
所谓渲染目标,就是指GPU可以把画面绘制到的目标,我们可以把它理解为GPU的画布。
当场景不是被渲染在正常的屏幕后备缓冲,而是被渲染在一个临时的纹理。这个临时的纹理经过过滤特效处理后,然后传到后备缓冲,最后画到屏幕上。绘制这样的一个可以实现某些功能的临时纹理被称为渲染目标。
实质上,渲染目标是一个连续的内存区域,这样的内存区域可以同时的存在多个,也就是多个渲染目标。一般来说,渲染目标被输出到屏幕上,这样我们就能看到画好的画面了。但是有时为了实现一些特效,某些渲染结果并不直接画到屏幕上,而是再返给GPU做进一步的特效处理,而且渲染目标中也不一定是画好的画面的颜色信息。
要想把纹理目标的内容渲染到屏幕上,就必须把纹理目标投影到屏幕上
纹理坐标
想把纹理覆盖全部。必须确保矩形的每个角的坐标是以下:(0,1)(1,0)(1,1)(0,0)
要想屏幕上的每一个像素都对应纹理的像素,必须要注意:
计算纹理坐标
// Texture coordinates are setup so that the full texture
// is mapped completely onto the screen
Out.texCoord.x = 0.5 * (1 + Pos.x);
Out.texCoord.y = 0.5 * (1 - Pos.y);
Combining the standard scale and offset with the texture correction offset yields the following code:
// Texture coordinates are setup so that the full texture
// is mapped completely onto the screen
Out.texCoord.x = 0.5 * (1 + Pos.x - viewport_inv_width);
Out.texCoord.y = 0.5 * (1 - Pos.y - viewport_inv_height);
光亮度(intensity)和灰阶(grayscale)
求光亮度最直观简单的方法是intensity = (green + blue + red)/3
但是这是有缺陷的,人眼所接收的颜色不是均等,根据研究表明,人眼对颜色的感知得出的光度公式为 intensity = 0.299 * red + 0.587 * Green + 0.114 * blue
(注:在《shader for game programmers and Artists》的blue乘以的是0.184
在《实时计算机图形学》(real-time Rendering) 中说明:在一些旧的教材中,通常表示为Y=0.30R+0.59G +0.11B 但是这是基于旧的NTSC荧光,而基于CRT和LCD的基本光度公式是Y=0.2125R+0.7145G+0.0721B)
Pixel shader代码
sampler Texture0;
float4 ps_main(
float4 inDiffuse: COLOR0,
float2 inTxr1: TEXCOORD0
) : COLOR0
{
// Output constant color:
float4 col = tex2D(Texture0,inTxr1);
float Intensity;
Intensity = 0.299 * col.r + 0.587 * col.g + 0.114 * col.b;
//等同于上面
Intensity = dot(col,float4(0.299,0.587,0.114,0));
// Return the intensity as a uniform RGB color
return float4(Intensity.xxx,col.a);
}
注:用点乘dot一般效率会比直接用公式要高。
模糊(blur)和运动模糊
模糊纹理:
简单的模糊效果
取一个像素的四周的像素加起来求平均值:
因为模糊效果需要多次采样纹理,所以,最好定义一个常数向量数组:
const float4 samples[4] =;
pass blur的pixel shader代码:
float viewport_inv_width;
float viewport_inv_height;
sampler Texture0;
const float4 samples[4] = {
-1.0, 0, 0, 0.25,
1.0, 0, 0, 0.25,
0, -1.0, 0, 0.25,
0, 1.0 , 0, 0.25
};
float4 ps_main(float2 texCoord: TEXCOORD) : COLOR
{
float4 col = float4(0,0,0,0);
for(int i = 0; i < 4; i++)
{
col+=samples[i].w * tex2D(Texture0,texCoord +
float2(samples[i].x * viewport_inv_width,
samples[i].x * viewport_inv_height));
}
return col;
}
边缘检测(Edge detection)
在上面的模糊效果改下数组:
float viewport_inv_width;
float viewport_inv_height;
sampler Texture0;
const float4 samples[6] = {
-1.0, 1.0, 0, 1.0,
0.0, 1.0, 0, 2.0,
1.0, 1.0, 0, 1.0,
-1.0, -1.0, 0, -1.0,
0.0, -1.0, 0, -2.0,
1.0, -1.0, 0, -1.0
};
float4 ps_main(float2 texCoord: TEXCOORD) : COLOR
{
float4 col = float4(0,0,0,0);
for(int i = 0; i < 6; i++)
{
col+=samples[i].w * tex2D(Texture0,texCoord +
float2(samples[i].x * viewport_inv_width,
samples[i].y * viewport_inv_height));
}
return col;
}
锐化(sharp color)
在上面的模糊效果改下数组:
float viewport_inv_width;
float viewport_inv_height;
sampler Texture0;
const float4 samples[5] = {
0.0, 0.0, 0, 11.0/3.0,
0.0, 1.0, 0, -2.0/3.0,
0.0, -1.0, 0, -2.0/3.0,
-1.0, 0.0, 0, -2.0/3.0,
1.0, 0.0, 0, -2.0/3.0
};
float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR
{
float4 col = float4(0,0,0,0);
// Sample and output the averaged colors
for(int i=0;i<5;i++)
col += samples[i].w*tex2D(Texture0,texCoord+
float2(samples[i].x*viewport_inv_width,
samples[i].y*viewport_inv_height));
return col;
}
运动模糊(motion blur)
运动模糊效果的工作流程
|
1.先将场景渲染到一个RenderTarget1上
2.将RenderTarget1跟上一帧渲染的结果进行混合, 并输出到RenderTarget2
3.将RenderTarget2输出到屏幕, 并将其保留到下一帧进行混合
ScreenAlignedQuad:一个正方形网格
Pass0的设置和代码:
RenderTarget 开启颜色清除和深度缓冲清除。
Vertex Shader代码:
float4x4 matViewProjection;
struct VS_INPUT
{
float4 Position : POSITION0;
float2 Txr1 : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 Txr1 : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
Output.Position = mul( Input.Position, matViewProjection );//位置
Output.Txr1 = Input.Txr1;//获取纹理
return( Output );
}
Pixel Shader代码:
sampler Texture0;
float4 ps_main(
float4 inDiffuse: COLOR0,
float2 inTxr1: TEXCOORD0
) : COLOR0
{
// Output color:
return tex2D(Texture0,inTxr1); //纹理映射
}
Blur1的设置和代码:
RenderState设置
D3DCULLMODE – D3DCULL_NONE,
D3DRS_ZENABLE – D3DZB_FALSE,
D3DRS_ZWRITEENABLE – FALSE.
Texture0设置:
Vertex Shader代码:
float4x4 matViewProjection;
struct VS_INPUT
{
float4 Position : POSITION0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 texCoord : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
// Simply output the position without transforming it
Output.Position = float4(Input.Position.xy,0,1);
// Texture coordinates are setup so that the full texture
// is mapped completeley onto the screen
Output.texCoord.x = 0.5 * (1 + Input.Position.x);
Output.texCoord.y = 0.5 * (1 - Input.Position.y);
return( Output );
}
Pixel Shader 代码:
float4 blurFactor;
sampler Texture0;
sampler Texture1;
float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR0
{
float4 col1 = tex2D(Texture0, texCoord);
float4 col2 = tex2D(Texture1, texCoord);
return lerp(col1,col2,blurFactor);
}
Present的设置和代码:
Texture0设置
Vertex Shader代码:
float4x4 matViewProjection;
struct VS_INPUT
{
float4 Position : POSITION0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 texCoord : TEXCOORD0;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
Output.Position = float4(Input.Position.xy,0,1);
Output.texCoord.x = 0.5 * (1 + Input.Position.x);
Output.texCoord.y = 0.5 * (1 - Input.Position.y);
return( Output );
}
Pixel Shader代码:
sampler Texture0;
float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR0
{
// Simply read the temporary texture and send
// the color to the output without manipulating it
return tex2D(Texture0, texCoord);
}
效果: