当前位置: 首页 > news >正文

OpenGL教程之Alpha混合

Jeff Molofee(NeHe) 的OpenGL 教程
- Alpha 混合

 原 文Lesson 8: Blending
 译 者 CKER

  OpenGL 中 的绝大多数特效都与某些类型的(色彩)混合有关。混色的定义为,将某个象素的颜色和已绘制在屏幕上与其对应的象素颜色相互结合。至于如何结合这两个颜色则 依赖于颜色的alpha 通道的分量值,以及/ 或 者所使用的混色函数。Alpha 通常是位于颜色值末尾的第4 个 颜色组成分量。前面这些课我们都是用GL_RGB 来指定颜色的三个分量。相应的GL_RGBA 可以指定alpha 分量的值。更进一步, 我们可以使用glColor4f() 来代替glColor3f()
  绝大多数人都认为Alpha 分 量代表材料的透明度。这就是说,alpha 值为0.0 时 所代表的材料是完全透明的。alpha 值为1.0 时 所代表的材料则是完全不透明的。

8.1
、混色的公式
  若您对数学不感兴趣,而只想看看如何实现透明,请跳过这一节。若您想深入理解(色彩)混合的工作原理,这一节应该适合您吧。(译 者 :其实混合的基本原理是就将要分色的图像各象素的颜色以及背景颜色均按照RGB 规 则各自分离之后,根据 图像的RGB 颜 色分量*alpha+ 背景的RGB 颜色分量*(1-alpha) — 这样一个简单公式来混合之后,最后将混合得到的RGB 分 量重新合并。)公式如下:

(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)


  OpenGL 按照上面的公式计算这两个象素的混色结果。小写的sr 分别代表源象素和目标象素。大写的SD 则是相应的混色因子。这些决定了您如何对这些象素混色。绝大多数情况下,各颜色通道的alpha 混色值大小相同,这样对源象素就有(As, As, As, As) ,目标象素则有(1, 1, 1, 1) - (As, As, As, As) 。 上面的公式就成了下面的模样:

(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bs (1 - As), As As + Ad (1 - As))


   这个公式会生成透明/ 半透明的效果。

8.2
OpenGL 中的混色
  在OpenGL 中实现混色的步骤类似于我们以前提到的OpenGL 过程。接着设置公式,并在绘制透明对象时关闭写深度缓存。因为我们想在半透明的图形背后绘制对象。 这不是正确的混色方法,但绝大多数时候这种做法在简单的项目中都工作的很好。
  Rui Martins 的补充 :正确 的混色过程应该是先绘制全部的场景之后再绘制透明的图形。并且要按照与深度缓存相反的次序来绘制(先画最远的物体)。考虑对两个多边形(12 )进行alpha 混 合,不同的绘制次序会得到不同的结果。(这里假定多边形1 离观察者最近,那么正确的过程应该先画多 边形2 ,再画多边形1 。正如您再现实中所见 到的那样,从这两个 透明的 多边形背后照 射来的光线总是先穿过多边形2 ,再穿过多边形1 , 最后才到达观察者的眼睛)。 在深度缓存启用时,您应该将透明图形按照深度进行排序,并在全部场景绘制完毕之后再绘制这些透明物体。否则您将得到不正确的结果。我知道某些时候这样做是 很令人痛苦的,但这是正确的方法。
  我们 将使用第七课的代码。一开始先在代码开始处增加两个新的变量。出于清晰起见,我重写了整段代码。

   #include <windows.h>                      // Windows 的头文件
   #include <stdio.h>                       // 标准输入/ 输 出库的头文件
   #include <gl\gl.h>                       // OpenGL32 库的头文件
   #include <gl\glu.h>                       // GLu32 库的头文件
   #include <gl\glaux.h>                     // GLaux 库的头文件

   HGLRC hRC=NULL;                        // 永久着色描述表
   HDC hDC=NULL;                         // 私有GDI 设 备描述表
    HWND hWnd=NULL;                         // 保存我们的窗口句柄
   HINSTANCE hInstance;                      // 保存程序的实例

   bool keys[256];                        // 用于键盘例程的数组
   bool active=TRUE;                       // 窗口的活动标志,缺省为TRUE
   bool fullscreen=TRUE;                     // 全屏标志缺省设定成全屏模式

   BOOL light;                          // 光源的开/
   bool blend;                          // Blending / ( 新增 )
   BOOL lp;                            // L 键按下了么?
   BOOL fp;                            // F 键按下了么?

   GLfloat xrot;                         // X 旋转
   GLfloat yrot;                         // Y 旋转
   GLfloat xspeed;                        // X 旋转速度
   GLfloat yspeed;                        // Y 旋转速度

   GLfloat z=-5.0f;                        // 深入屏幕的距离

   GLfloat LightAmbient[]= { 0.5f };               // 环境光参数
  GLfloat LightDiffuse[]= { 1.0f };                // 漫射光参数
  GLfloat LightPosition[]= { 0.0f };               // 光源位置

   GLuint filter;                         // 滤波类型
   GLuint texture[3];                       // 3 种纹理的储存空间
   LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);     // WndProc 定义

  然后往下移动到 LoadGLTextures() 这 里。找到 if (TextureImage[0]=LoadBMP("Data/Crate.bmp")) 这一行。我们现在使用有色玻璃纹理来代替上一课中的木箱纹理。

       if (TextureImage[0]=LoadBMP("Data/glass.bmp"))     // 载入玻璃位图 ( 已修改)

  在 InitGL() 代码段加入以下两行。第一行以全亮度绘制此物体,并对其进行50%alpha 混合(半透明)。当混合选项打开时,此物体将会产生50% 的 透明效果。第二行设置所采用的混合类型。Rui Martins 的补充alpha 通道的值为0.0 意味着物体材质是完全透明 的。1.0 则意味着完全不透明。

       glColor4f(1.0f,1.0f,1.0f,0.5f);            // 全亮度, 50% Alpha 混 合( 新增)
       glBlendFunc(GL_SRC_ALPHA,GL_ONE);   // 基于源象素alpha 通道值的半透明混合函 数 ( 新增)

  在接近第七课结尾处的地方找到下面的代码段。

       if (keys[VK_LEFT])                   // Left 方向键按下了么?
       {
           yspeed-=0.01f;                 // 若是, 减少yspeed
       }

  接着上面的代码,我们增加如下的代码。这几行监视B 键是否按下。如果是的话,计算机检查混合选项是否已经打开。然后将其置为相反的状态。

       if (keys[VK_LEFT])                   // Left 方向键按下了么?
       if (keys['B'] && !bp)                  // B 健按下且bp FALSE?
       {
           bp=TRUE;                   // 若是, bp 设为 TRUE
           blend = !blend;                // 切换混合选项的 TRUE / FALSE
           if(blend)                   // 混合打开了么?
           {
               glEnable(GL_BLEND);          // 打开混合
               glDisable(GL_DEPTH_TEST);      // 关闭深度测试
           }
           else                      // 否则
           {
               glDisable(GL_BLEND);         // 关闭混合
               glEnable(GL_DEPTH_TEST);       // 打开深度测试
           }
      }
      if (!keys['B'])                    // B 键松开了么?
       {
           bp=FALSE;                  // 若是, bp 设为 FALSE
       }

  但是怎样才能在使用纹理贴图的时候指定混合时的颜色呢?很简单, 在调整贴图模式时,文理贴图的每个象素点的颜色都是由alpha 通道参数与当前地象素颜色相乘所得 到的。比如,绘制的颜色是(0.5, 0.6, 0.4) ,我们会把颜色相乘得到(0.5, 0.6, 0.4, 0.2)alpha 参 数在没有指定时,缺省为1.0 )。
  就是如此。OpenGL 实现Alpha 混合的确很简单。


  原文注 11/13/1999
  我(NeHe )混色代码进行了修改,以使 显示的物体看起来更逼真。同时对源象素和目的象素使用alpha 参数来混合,会导致物体的人造痕迹 看起来很明显。会使得物体的背面沿着侧面的地方显得更暗。基本上物体会看起来很怪异。我所用的混色方法也许不是最好的,但的确能够工作。启用光源之后,物 体看起来很逼真。感谢Tom 提供的原始代码,他采用的混色方法是正确的,但物体看起来并不象所期望 的那样吸引人。

  代码所作的再次修改是因 为在某些显卡上 glDepthMask() 函数存在寻址问题。这条命令在某些卡上启用或关闭深度缓冲测试时似乎不是很有效,所以我已经将启用或 关闭深度缓冲测试的代码转成老式的 glEnableglDisable

8.3
、纹理贴图的Alpha 混合
  用于纹理贴图的alpha 参数可以象颜色一样从问题贴图中读取。方法如 下,您需要在载入所需的材质同时取得其的alpha 参数。然后在调用 glTexImage2D() 时使用 GL_RGBA 的颜色格式。

相关文章:

  • 模式识别与机器学习读书笔记——2.1 Binary Variables
  • 【转】【翻译】Orx官方教程:0.基础(Basic)
  • ASP.NET——/应用程序中的服务器错误
  • 【转】【翻译】Orx官方教程:1. object
  • WEB上传文件的插件uploadify
  • 读书笔记,深入理解linux内核第三版
  • OGC标准介绍 2
  • Android游戏开发之游戏帧动画的播放与处理(七)
  • OGC标准介绍 3
  • [我研究]7月第三周
  • 查看服务器实例的属性信息函数--SERVERPROPERTY
  • 10w级别的mysql数据插入
  • 绿色 . IT . 从小事做起
  • x64 参数传递
  • 《Windows Phone 7 UI设计及人机交互指南》翻译稿
  • 【347天】每日项目总结系列085(2018.01.18)
  • 【翻译】babel对TC39装饰器草案的实现
  • CODING 缺陷管理功能正式开始公测
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaScript异步流程控制的前世今生
  • leetcode388. Longest Absolute File Path
  • passportjs 源码分析
  • Phpstorm怎样批量删除空行?
  • python 学习笔记 - Queue Pipes,进程间通讯
  • 讲清楚之javascript作用域
  • 力扣(LeetCode)22
  • 前端
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 深入浏览器事件循环的本质
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用Canvas画一棵二叉树
  • 自制字幕遮挡器
  • 【干货分享】dos命令大全
  • 从如何停掉 Promise 链说起
  • 国内开源镜像站点
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #Spring-boot高级
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • #考研#计算机文化知识1(局域网及网络互联)
  • (C语言)共用体union的用法举例
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (MATLAB)第五章-矩阵运算
  • (二)fiber的基本认识
  • (理论篇)httpmoudle和httphandler一览
  • (生成器)yield与(迭代器)generator
  • (四)模仿学习-完成后台管理页面查询
  • (转) Face-Resources
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)负载均衡,回话保持,cookie
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .htaccess配置重写url引擎
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net 设置默认首页
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证