代码已经上传至git hub 见:https://github.com/Jeromecen/GaussianBlur
实例目的
1.提供了一个完整的fx框架编写Shader可运行程序,解决掉了编写过程中遇到的所有问题。验证了在FX框架可以不用GetParameterByName获取句柄的,直接用字符串作为句柄即可。2.对高斯模糊图片提供了一个思路,就是高斯过滤矩阵通过程序设置给Shader,相比在Shader中做高斯运算性能更高
或者相比在Shader中写死高斯过滤矩阵,但是这样会不够灵活。
3.合理使用GPU Shader可以有效的提高图形程序性能,运用GPU强大的并行大量数据计算能力,简单随意测试了下CPU降低了大概10%。
调试错误和经验总结
//1).获取效果文件,hlsl注意fx要是asscii格式,不能是utf8格式
//2).结构体不能VS_OUTPUT outData = VS_OUTPUT(0);而是直接VS_OUTPUT outData就好了。
//3).顶点着色器输入输出都要float4类型,且像素着色器不能输入顶点,因为已经是在光栅化阶段了。
// 顶点着色器的输入
//struct VS_INPUT
//{
// float4 POS : POSITION;
// float2 UV : TEXCOORD0;
//};
顶点着色器的输出
//struct VS_OUTPUT
//{
// float4 POS : POSITION;
// float2 UV : TEXCOORD0;
//};
// 4).纹理需要用Sampler正确,不能用texture代替sampler,或者输入texture当sampler来用的方式
// 5).alpha融合需要注意,否则会导致渲染层次有问题,融合结果
// 6).渲染框架要正确,无论是固定管线还是着色器,每帧的Clear,BeginSecne,渲染设置顶点格式/顶点数据/索引数据/Draw函数,EndScene
// 都是要首先正确的。
// 7).对于顶点部分:
// 顶点位置要正确,索引下标要正确,还有世界视图投影变换,特别是索引如果是拷贝的那么很容易什么都不提交PIX也看不到原因
// 8). 对于像素部分:颜色没有出来,可能是光照没有关闭又没有设置材质,也可能是纹理缺失或者设置错误,alpha融合和各种融合情况
// 9).注意视口外裁剪不可见,背面剔除,深度剔除,模板过滤,导致物体绘制不出来。
// 10).要使用上述思维进行代码分析,errorBuffer/Control panel/#define D3D_DEBUG_INFO/PIX来调试分析,反复对比注释提高理论查找问题
// 如果有N卡用NVIDIA Nsight,GPA分析问题和性能更好。
// 11).图像异常:UV坐标没对,PIX传入都没对,那么是UV相关设置出了问题,最后对比发现是顶点声明出了问题:
//D3DVERTEXELEMENT9 Decl_Element [] =
//{
// {eBlurDT_Pos, 0, D3DDECLTYPE_FLOAT4,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION, 0},
// {eBlurDT_UV, 0, D3DDECLTYPE_FLOAT2,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_TEXCOORD, 0},
// D3DDECL_END()
//};
//而不是:
//D3DVERTEXELEMENT9 Decl_Element [] =
//{
// {0, 0, D3DDECLTYPE_FLOAT4,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION, 0},
// {0, 16, D3DDECLTYPE_FLOAT2,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_TEXCOORD, 0},
// D3DDECL_END()
//};
源码
blur.fx
// Globals
// 纹理
texture BlurTex;
// 世界视图投影矩阵
matrix WorldViewProj;
// 纹理大小
float2 TexSize;
// 高斯过滤矩阵,暂时用3x3的
float3x3 ArrayGaussianFilter;
sampler BlurSampler = sampler_state
{
Texture = <BlurTex>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};
//
// Structures
// 顶点着色器的输入
struct VS_INPUT
{
float4 POS : POSITION;
float2 UV : TEXCOORD0;
};
// 顶点着色器的输出
struct VS_OUTPUT
{
float4 POS : POSITION;
float2 UV : TEXCOORD0;
};
VS_OUTPUT VS_Main( VS_INPUT input )
{
VS_OUTPUT outData;
outData.POS = mul( input.POS, WorldViewProj);
outData.UV = input.UV;
return outData;
}
// 像素着色器的输入
struct PS_INPUT
{
float2 UV : TEXCOORD0;
};
// 像素着色器的输出
struct PS_OUTPUT
{
vector diffuse : COLOR0;
};
//用来做滤波操作的函数
float4 dip_filter3(float3x3 _filter , sampler2D _image, float2 _xy, float2 texSize)
{
//纹理坐标采样的偏移
float2 _filter_pos_delta[3][3] =
{
{ float2(-1.0 , -1.0) , float2(0,-1.0), float2(1.0 , -1.0) },
{ float2( -1.0 , 0.0) , float2(0.0, 0.0), float2(1.0 , 0.0) },
{ float2( -1.0 , 1.0) , float2(0, 1.0), float2(1.0 , 1.0) },
};
//最终的输出颜色
float4 final_color = float4(0.0,0.0,0.0,1.0f);
//对图像做滤波操作
for(int i = 0 ; i < 3 ; i++ )
{
for(int j = 0 ; j < 3 ; j++ )
{
//计算采样点,得到当前像素附近的像素的坐标
float2 _xy_new = float2(_xy.x + _filter_pos_delta[i][j].x ,
_xy.y + _filter_pos_delta[i][j].y);
float2 _uv_new = float2(_xy_new.x/texSize.x , _xy_new.y/texSize.y);
//采样并乘以滤波器权重,然后累加
final_color += tex2D( _image, _uv_new ) * _filter[i][j];
}
}
return final_color;
}
PS_OUTPUT PS_Main( PS_INPUT input)
{
PS_OUTPUT output;
float2 intXY = float2(input.UV.x * TexSize.x , input.UV.y * TexSize.y);
//用于模糊操作的