高斯模糊、径向缩放模糊
2013-04-11 21:17 三戒1993 阅读(140) 评论(0) 编辑 收藏 举报初学图形编程,开始记录
工作内容:通过学习某知名商业引擎,构建新游戏引擎,对新引擎进行简单测试。
札记:
1、移植代码大部分时间都是很枯燥的,不用想只需要重复的做,重复的做。。。。, 最多要改的地方就是编码规范,然后是在许多模块没有建立的基础上对把移植好的模块编译连接,最重要的技巧就是注释,许多设计没有建立的模块太多,只能留下空实现的函数,以后用到的时候再实现吧。
2、这次做完了Texture模块,虽然还没有做任何渲染相关的代码,但是测试还是需要的,不然以后累加起来可能就忘记了。
2.1。测试流程:载入一个图片到缓存,操作缓存(即像素),做出特定的模糊效果,再另保存为文件,进行查看。(注:文件操作和DDS图像文件读取已经做完)
2.2。制作高斯模糊(累加像素求平均值):
输入:像素数据指针,高斯模糊半径(X和Y分量上各一个)
算法流程:1、遍历每一个像素点
2、以这个像素点为中心,根据高斯模糊半径创建一个区域,此区域内的像素用来计算中心点像素的高斯模糊值。
3、遍历这个区域的每一个像素,累加RGBA的各个分量值(我测试的图片是32位的DDS文件)。
4、用各个分量除以累加的数量组合成一个像素(即高斯模糊后的像素点)。
注:
1、使用unsigned char储存一个像素的分量,但累加的时候要使用更大存储空间的类型比如unsigned int,否则会溢出。
2、这次操作的图像是读DDS文件,保存格式为BMP,发现两种格式文件的RGBA的通道存储顺序是不一致的,所以操作的时候要改为正确的才能进行存储。
3、BMP格式解析文件是从下到上进行倒置存储的。
4、进行多次遍历像素点的时候要保持遍历的顺序,否则容易出现贴图倒置或翻转的效果。
事例代码:
//---------------------------------------------------------------------------
void FillPerPixelGaussBlur(yqg_IPixelData * pDest, DWORD originX, DWORD originY, BYTE * pSrc, DWORD radiusX, DWORD radiusY)
{
// 记录共受多少个像素的影响
DWORD t_Num = 0;
// 获得高斯模糊半径内的像素区域
DWORD t_pixelLeft = originX > radiusX ? originX-radiusX : 0;
DWORD t_pixelTop = originY > radiusY ? originY-radiusY : 0;
DWORD t_pixelRight = (originX+radiusX) < pDest->GetWidth() ? originX+radiusX : pDest->GetWidth();
DWORD t_pixelBottom= (originY+radiusY) < pDest->GetHeight() ? originY+radiusY : pDest->GetHeight();
DWORD t_pPixels[4];
for(int t_d = 0; t_d < 4; ++t_d)
{
t_pPixels[t_d] = 0;
}
// 遍历区域内的每个元素
for(DWORD t_dX = t_pixelLeft; t_dX < t_pixelRight; ++t_dX)
{
for(DWORD t_dY = t_pixelTop; t_dY < t_pixelBottom; ++t_dY)
{
// 计数
++t_Num;
// 将影响像素分值添加到高斯模糊像素上
BYTE * t_pOrigin = (BYTE*)&(((DWORD*)pSrc)[t_dX + t_dY * pDest->GetWidth()]);
t_pPixels[0] = t_pPixels[0] + *(t_pOrigin+0); //Red
t_pPixels[1] = t_pPixels[1] + *(t_pOrigin+1); //Green
t_pPixels[2] = t_pPixels[2] + *(t_pOrigin+2); //Blue
t_pPixels[3] = t_pPixels[3] + *(t_pOrigin+3); //Alpha
}
}
// 取累加后的像素平均值,即高斯模糊
if(t_Num != 0)
{
BYTE * t_pDestPixel = pDest->operator()(originX, originY);
*(t_pDestPixel+0) = (BYTE)(t_pPixels[0] / t_Num);//Blue
*(t_pDestPixel+1) = (BYTE)(t_pPixels[1] / t_Num);//Green
*(t_pDestPixel+2) = (BYTE)(t_pPixels[2] / t_Num);//Red
*(t_pDestPixel+3) = (BYTE)(t_pPixels[3] / t_Num);
}
}
//---------------------------------------------------------------------------
2.3。制作径向缩放模糊(针对任意一点,循环数量,根据数量值求出单位缩放,确定当前数量下的像素点,进行累加,然后求平均值):
输入:像素数据指针,径向缩放中心点(指定的像素位置),数量
算法流程:1、遍历每一个像素点
2、循环数量,根据每个数量下的单位缩放值和中心点累加像素值。
3、求平均值,即该像素点的径向缩放模糊值。
注:做缩放值和像素点的计算时要确定类型,如unsigned int相减是不会的得到负数的,细节很重要。
事例代码:
//---------------------------------------------------------------------------
void FillPerPixelRadialBlur(yqg_IPixelData * pDest, BYTE * pSrc, DWORD dCenterX, DWORD dCenterY, DWORD dNum, DWORD dCurrentPosX, DWORD dCurrentPosY)
{
// 缩放值
float t_fScale;
// 根据缩放值和中心点计算后用来累加像素点的位置
DWORD t_caluPixelPosX;
DWORD t_caluPixelPosY;
// 临时存储累加的计算结果,并初始化
DWORD t_pPixels[4];
for(int t_d = 0; t_d < 4; ++t_d)
{
t_pPixels[t_d] = 0;
}
// 遍历数量
for(DWORD t_dIndex = 0; t_dIndex < dNum; ++t_dIndex)
{
// 计算缩放值
t_fScale = 1.0f + (-(dNum*1.0f/pDest->GetWidth()) * t_dIndex) / (dNum - 1);
// 计算累加像素点的位置
t_caluPixelPosX = (DWORD)(((int)dCurrentPosX - (int)dCenterX) * t_fScale + dCenterX);
t_caluPixelPosY = (DWORD)(((int)dCurrentPosY - (int)dCenterY) * t_fScale + dCenterY);
t_caluPixelPosX = (t_caluPixelPosX > (pDest->GetWidth() - 1)) ? (pDest->GetWidth() - 1) : t_caluPixelPosX;
t_caluPixelPosY = (t_caluPixelPosY > (pDest->GetHeight() - 1)) ? (pDest->GetHeight() - 1) : t_caluPixelPosY;
// 将影响像素分值添加到径向缩放模糊像素上
BYTE * t_pOrigin = (BYTE*)&(((DWORD*)pSrc)[t_caluPixelPosX + t_caluPixelPosY * pDest->GetWidth()]);
t_pPixels[0] = t_pPixels[0] + *(t_pOrigin+0); //Red
t_pPixels[1] = t_pPixels[1] + *(t_pOrigin+1); //Green
t_pPixels[2] = t_pPixels[2] + *(t_pOrigin+2); //Blue
t_pPixels[3] = t_pPixels[3] + *(t_pOrigin+3); //Alpha
}
// 取累加后的像素平均值,即高斯模糊
BYTE * t_pDestPixel = pDest->operator()(dCurrentPosX, dCurrentPosY);
*(t_pDestPixel+0) = (BYTE)(t_pPixels[0] / dNum);//Blue
*(t_pDestPixel+1) = (BYTE)(t_pPixels[1] / dNum);//Green
*(t_pDestPixel+2) = (BYTE)(t_pPixels[2] / dNum);//Red
*(t_pDestPixel+3) = (BYTE)(t_pPixels[3] / dNum);
}
//---------------------------------------------------------------------------
以下是原图和效果图