您现在的位置: 中国IT实验室 >> 游戏开发 >> 初学入门 >> 文章正文
如何在2D模式下的alpha混合的技巧
来源:ChinaITLab 收集整理 作者: 时间:2004-12-26


  alpha混合是一种常见的颜色处理,是把源点的颜色值和目标点的颜色值按照一定的算法进行运算,得到一个透明的效果.
  
  alpha混合的基本公式:
  
  result = ALPHA * srcPixel + ( 1 - ALPHA ) * destPixel
  其中:
  ALPHA:0到1之间的一个数,表示混合时的透明程度,为0的时候结果就是目标点的原值,为1的时候是源点的原值
  srcPixel:源点颜色值
  destPixel:目标点颜色值
  result:结果,将会赋给目标点
  
  这个是最基本的公式,但是我们在写程序的时候可以做一些优化.公式里面有两个乘号,乘法消耗的时钟周期要多得多,我们要想方法去掉它.做一个变换.
  
  alpha混合的改进公式1:
  result = ALPHA * ( srcPixel - destPixel ) + destPixel
  
  然后我们也看到ALPHA是一个浮点数,我们可以把它转换成整数,因为一种颜色最多占8bit,所以ALPHA的值也最多到256,那我们把ALPHA的值先乘上256,然后运算的时候再除以256就得到下面的公式:
  
  alpha混合的改进公式2:
  result = ALPHA * ( srcPixel - destPixel )/256 + destPixel
  其中:
  ALPHA是一个0到256的数
  
  有了这个公式,我们的第一份code也就出来了.
  
  alpha混合代码1:
  //16位565格式
  i = height;// 混合矩形高度
  do
  {
  j = width; // 混合矩形宽度
  do
  {
  sTemp = *((WORD*)lpSour);// 源点颜色值,16位--WORD类型,(lpSour和lpDest都是BYTE*)
  if ( sTemp != sColorKey )  // 不是colorkey
  {
  dTemp = *((WORD*)lpDest); // 目标点
  
  sb = sTemp & 0x1f;  // 蓝色分量
  db = dTemp & 0x1f;
  
  sg = (sTemp >> 5) & 0x3f; // 绿色分量
  dg = (dTemp >> 5) & 0x3f;
  
  sr = (sTemp >> 11) & 0x1f;// 红色分量
  dr = (dTemp >> 11) & 0x1f;
  
  blue = (ALPHA * (sb - db) >> 8) + db;// 按照改进公式2运算三个分量
  green = (ALPHA * (sg - dg) >> 8) + dg;
  red = (ALPHA * (sr - dr) >> 8) + dr;
  *((WORD*)lpDest) = blue | (green << 5) | (red << 11); // 565格式生成结果并赋给目标点
  }
  lpDest += 2; // 下一个点,16位占2个字节
  lpSour += 2;
  }while ( --j > 0 );
  lpDest += dPadding; // 下一行
  lpSour += sPadding;
  }while (--i > 0);
  
  到此alpha混合也就差不多了,但是不得不说说MMX版本的alpha混合.上面的方式进行alpha混合的时候效率不高,而MMX使用64位的MMX寄存器,一次操作8(byte)/4(word)/2(dword)个数据单元,也就是所谓的"单指令多数据SIMD结构".这样我们就可以一次处理几个点.下面的代码是写给16位565模式的.
  因为是16位模式,那么我们可以一次处理4个点,但是因为编译器不会主动的生成MMX代码,所以我们使用inline asm的方式进行.因为我们的点是定义成无符号的word型,不能出现负数,所以我们要修改我们的alpha混合公式:
  
  alpha混合mmx版公式:
  result = ( ALPHA * ( ( srcPixel+ 64 ) - destPixel) ) / 256 + destPixel- (ALPHA / 4)
  
  这个公式是这样来的:因为16位模式下每个点的分量最多6位,换成10进制也就是63,那么我们在srcPixel上面加上64然后再减去destPixel,就不会出现负数了.加了之后当然要减回来,那这个公式就是这样的:
  
  result = ( ALPHA * ( ( srcPixel+ 64 -64) - destPixel) ) / 256 + destPixel
  
  然后把紫色的-64提出来也就得到了上面的公式了.
  
  好了我们可以动手写code了,看起来的code应该如下:
  
  alpha混合code2:
  
  MASKRED = 0xF800F800F800F800;// 三种颜色的掩码的64位扩展
  MASKGREEN = 0x07E007E007E007E0;
  MASKBLUE = 0x001F001F001F001F;
  
  __int64 ALPHA64, COLORKEY64, ALPHABY4;
  __int64 MASKRED, MASKGREEN, MASKBLUE;
  __int64 ADD64 = 0x0040004000400040;
  
  _asm
  {
  movd mm2,ALPHA // ALPHA值放入mm2
  punpcklwd mm2,mm2  // mm2 -> 0000 0000 00aa 00aa
  punpckldq mm2,mm2  // mm2 - 00aa 00aa 00aa 00aa,生成alpha的64位扩展
  movq ALPHA64,mm2 // 结果放入到 ALPHA64
  
  psrlw mm2, 2 // 每个ALPHA 除以4
  movq ALPHABY4,mm2  // 放到 ALPHABY4
  
  movd mm4,ColorKey  // ColorKey -> mm4
  punpcklwd mm4,mm4  // mm4 -> 0000 0000 cccc cccc
  punpckldq mm4,mm4  // mm4 -> cccc cccc cccc cccc,生成Colorkey的64位扩展
  movq COLORKEY64,mm4 ;  // 结果放到 COLORKEY64
  }
  
  i = height;
  do
  {
  j = width/4;
  
  // 两行写在一起表示假设他们同时在uv管道里面执行
  
  _asm
  {
  push edi  // 保存edi和esi
  push esi
  
  mov edi,lpDest  // edi指向dest缓冲区
  mov esi,lpSour; // esi指向sour缓冲区
  
  SPAN_RUN_565:
  movq mm7,[edi]  // dest的8 bytes 到 mm7--4个dest点到mm7
  movq mm6,[esi]  // sour的8 bytes 到 mm6--4个sour点到mm6
  
  movq mm2,ALPHA64  // ALPHA64 -> mm2
  movq mm0,mm7  // 红色 - 复制 mm7 到 mm0,目标点
  
  pand mm0,MASKRED  // 红色 - 与上红色掩码 -> [0r00 0r00 0r00 0r00],目标点
  movq mm1,mm6  // 红色 - 复制 mm6 到 mm1,源点
  
  pand mm1,MASKRED  // 红色 - 与上红色掩码 -> [0r00 0r00 0r00 0r00],源点
  psrlw mm0,11  // 红色 - 右移 11 位 -> [000r 000r 000r 000r],目标点
  
  movq mm5,mm7  // 绿色 - 复制 mm7 到 mm5,目标点
  psrlw mm1,11  // 红色 - 右移 11 位 -> [000r 000r 000r 000r],源点
  
  paddw mm1, ADD64// 红色 - 源点加上64
  
  movq mm3,mm6  // 绿色 - 复制 mm6 到 mm3,源点
  psubsw mm1,mm0  // 红色 - 减去目标点
  
  pand mm5,MASKGREEN  // 绿色 - 与上绿色掩码 -> [00g0 00g0 00g0 00g0],目标点
  pmullw mm1,mm2  // 红色 - 乘以ALPHA
  
  pand mm3,MASKGREEN  // 绿色 - 与上绿色掩码 -> [00g0 00g0 00g0 00g0],源点
  psrlw mm5,5 // 红色 - 右移 5 位 -> [000g 000g 000g 000g],目标点
  
  psrlw mm3,5 // 红色 - 右移 5 位 -> [000g 000g 000g 000g],源点
  nop // 空操作 - 指令配对
  
  paddw mm3, ADD64// 绿色 - 源点加上64
  
  psrlw mm1,8 // 红色 - 除以 256 (右移8位)
  psubsw mm3,mm5  // 绿色 - 减去目标点
  
  pmullw mm3,mm2  // 绿色 - 乘以ALPHA
  paddw mm1,mm0 // 红色 - 加上目标点
  
  psubw mm1, ALPHABY4 // 红色 - 减去alpha的四分之一
  
  psllw mm1,11  // 红色 - 左移11位,还原[0r00 0r00 0r00 0r00]
  movq mm0,mm7  // 蓝色 - 复制 mm7 到 mm0,目标点
  
  pand mm0, MASKBLUE  // 蓝色 - 与上蓝色掩码 -> [000b 000b 000b 000b],目标点
  psrlw mm3,8 // 绿色 - 除以 256 (右移8位)
  
  paddw mm3,mm5 // 绿色 - 加上目标点
  movq mm4, mm6 // 蓝色 - 复制 mm6 到 mm4,源点
  
  psubw mm3, ALPHABY4 // 绿色 - 减去alpha的四分之一
  
  pand mm4, MASKBLUE// 蓝色 - 与上蓝色掩码 -> [000b 000b 000b 000b],源点
  psllw mm3,5 // 绿色 - 左移5位,还原[00g0 00g0 00g0 00g0]
  
  paddw mm4, ADD64// 蓝色 - 加上64
  
  psubsw mm4,mm0  // 蓝色 - 减去目标点
  por mm1,mm3 // 组合红色和绿色分量
  
  pmullw mm4,mm2  // 蓝色 - 乘以alpha
  movq mm3,COLORKEY64 // COLORKEY64 -> mm3
  
  psrlw mm4,8 // 蓝色 - 除以256(右移8位)
  pcmpeqw mm3,mm6 // 比较 colorKey 和原来的sour,如果相等,则相应的mm3的位为1
  
  paddw mm4,mm0 // 蓝色 - 加上目标点
  movq mm5,mm3  // mm3 -> mm5
  
  psubw mm4, ALPHABY4 // 蓝色 - 减去alpha的四分之一
  
  por mm1,mm4 // 合成3种颜色
  pand mm5,mm7  // mm5与上目标点 - 取出源点是colorkey的点的目标点的颜色值
  
  pandn mm3,mm1 // mm3取反然后与上mm1,mm1放的是运算结果,这样就把源
收藏本文 责编:admin 


相关文章
游戏开发新手入门之位图化图形
给希望成为游戏美术设计师的朋友
Ogre游戏引擎鼠标选取物体演示  
所有绘画的核心灵魂——素描知识
DirectDraw与DirectInput游戏编程体验
推荐文章


 精彩友情推荐
·神州数码交换机
·神州数码交换机价格
·神州数码网络交换机
·netgear交换机
·网件交换机
·IDC资讯大全
·机房品质万里行
·IDC托管必备知识
·全国IDC报价
·网站推广优化
 基础入门  开发文档
 最新推荐
  多数的Windows程序都需要Windows.h和Windowsx.h这两个头文件,要确保使用它们。当然,你还需要其它......
游戏引擎演化史
在Windows上安装OGRE的方法
关于滤镜遮罩概念,Sobel 遮罩
游戏开发新手入门之Windows编程
游戏开发新手入门之位图化图形
教你实现卡通渲染的另类勾边方法
游戏设计大师谈如何成为一名游戏设
Visual C#编写 3D游戏框架示例
真正的 Java 学习从入门到精通
游戏开发经验——游戏开发的基本常
  针对于移动新出台的政策,需要尽快地把我们公司的游戏对应到不同的手机平台,这是针对市场策略的有利调整............
Quake-III代码里神奇的浮点开方函数
基于Dialogue的MFC程序调用DirectX
关于Kjava手机平台移植可行性报告
网络游戏的数据传输处理和防火墙穿
浅谈网游的数据传输处理和防火墙穿
向量几何在游戏编程中的使用(六)
向量几何在游戏编程中的使用(五)
向量几何在游戏编程中的使用(四)
向量几何在游戏编程中的使用(三)
向量几何在游戏编程中的使用(二)
  培训中心