将RGB值转换为灰度值的简单算法
作者:Soft Boy
来源:GameRes
使场景或精灵以灰度的形式显示,这是一般游戏制作中常常用到的效果,如:战棋游戏中当一个角色被使用过后,通常就会变成灰色,代表本回合已不能行动了;《仙剑》中回忆彩蝶的部分是用整屏的灰色来表现的?(记的不太清楚,太久了^_^);还有很多很多例子……
将RGB值转换为灰度的过程应该是在程序中实现的(至少我是这么认为的)。其实这是非常简单的,基本原理就是将一个点的RGB值分开来求和,然后除以3,把得到的值再分别付给RGB,用公式表示如下:
R = G = B = 0.3R + 0.6G + 0.1B; //第二版改正后的公式
//第一版中的错误公式是 R = G = B = ( R + G + B ) / 3;
在实际编程应用中又可分为8位、16位和24位三种情况,下面进行一一介绍:
一、首先说最简单的24位点的转换,24位点的RGB均匀分布,所以分离和合成都较为简单,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | //=======24位转换============ int gMask=0x00ff00; //绿色掩码 int bMask=0x0000ff; //兰色掩码 int RGB24toGray(int sour) { int r,g,b,t; //临时变量 r=(sour>>16); g=(sour & gMask) >>8; b=sour & bMask; t=(r*3+g*6+b)/10; //第二版改正的地方 return (t<<16)|(t<<8)|t; } <span style="color: #ff0000;">二、16位点的转换要麻烦一些,因其涉及到555和565两种色码格式,所以在转换前需要我们进行一些初始工作</span>: //=======16位转换============ BYTE RMove, GMove; //R和G移动到最低位需要的步数 //初始化数据,本函数在游戏初始时执行,仅执行一次 void Init() { if( Is555 ) //555模式 0rrrrrgggggbbbbb { RMove=10; GMove=5; } else //565模式 rrrrrggggggbbbbb { RMove=11; GMove=6; /*注意:为什么这里GMove=6,因为565模式下G值有6位,如果用一个6位值和两个5位值相加除以3,得到的结果可能使5位溢出,所以我们要多移动一位即除以2*/ } } //16位点转换 WORD RGB16toGray(WORD sour) { WORD t; WORD r, g, b; r= sour >> RMove; g= (GMask & sour) >> GMove; b= BMask & sour; t = (r*3+b*6+g)/10; //第二版改正的地方 return (t<<RMove)|(t<<GMove)|t; } <span style="color: #ff0000;">三、8位点的转换和上面两种有比较大的差异,因为它的颜色是由调色板决定的,我们只有通过改变调 色板来进行转换,先用lpDDPal->GetEntries()获得调色板,然后分别转换需要的调色板值,完成后用 lpDDPal->SetEntries()更新即可,</span>程序如下: //===========8位转换(注:本函数只适用于全屏转换)=========== void RGB8_to_Gray() { int t; //临时变量 LPPALETTEENTRY Pal = (LPPALETTEENTRY) LocalAlloc( LPTR, sizeof( PALETTEENTRY ) * 256 ); //获取调色板 lpDDPal->GetEntries(0,0,256,Pal); //转换 for(int i=0; i<256; i++) { t=( Pal[i].peRed * 3 + Pal[i].peGreen *6 + Pal[i].peBlue ) / 10; //第二版改正的地方 Pal[i].peRed=Pal[i].peGreen=Pal[i].peBlue=t; } //更新调色板 lpDDPal->SetEntries(0,0,256,Pe); } |
上面代码中16位转换已经过测试,而其余两种尚未测试,如果各位发现有问题请及时指正。另:我曾试图用汇编对16转换进行优化,但由于本人的汇 编功底实在过于拙劣,经汇编改写后的代码效率不但没有提高,反而有小幅下降,所以如果有人对其16位转换进行优化后,请务必发给在下一份,不胜感激!
