Alpha测试测试就是测试每一个像素的Alpha值是否满足某一个特定的条件,如果满足,则该像素会被绘制,如果不满足则不绘制,跟深度测试的机制是一样的,只不过深度测试考察的是像素的“深度”属性,Alpha测试考察的是像素的“Alpha”属性。

利用Alpha测试的这一特性,可以模拟两幅图像叠加,但是又要求前景图像有一部分是透明的场景,这时候可以把要求透明的区域内的每一个像素的Alpha值设置为0,在之后的Alpha测试的通过条件设置为大于0.5才通过,这样Alpha值为0的像素就不会被绘制,达到透明的效果。

通过glEnable(GL_ALPHA_TEST)启用Alpha测试,通过GLDisable(GL_ALPHA_TEST)禁用Alpha测试。

设置Alpha测试的通过条件的函数是glAlphaFunc(GLenum_func,GLclampf ref),func是参数的比较方式,ref是参数,可以取的参数以及含义如下:

  • GL_ALWAYS(始终通过)
  • GL_NEVER(始终不通过)
  • GL_LESS(小于则通过)
  • GL_LEQUAL(小于等于则通过)
  • GL_EQUAL(等于则通过)
  • GL_GEQUAL(大于等于则通过)
  • GL_NOTEQUAL(不等于则通过)

例如有如下两幅图像需要叠加,第一个是前景图像,第二个是背景图像,场景要求是叠加之后的效果是从窗户里看过去的效果。

背景:

前景:

可以利用Alpha测试,设置前景图像中白色部分的Alpah值为0,其他部分的Alpha值为1,在测试条件中选用GL_GREATER(大于则通过):

  1. #define WindowWidth 400
  2. #define WindowHeight 400
  3. #define WindowTitle "OpenGLAlpha测试"
  4. #define BMP_Header_Length 54
  5. #include <gl/glut.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. GLuint texGround;
  9. GLuint texWall;
  10. int power_of_two(int n)
  11. {
  12. if( n <= 0 )
  13. return 0;
  14. return (n & (n-1)) == 0;
  15. }
  16. /* 函数load_texture
  17. * 读取一个BMP文件作为纹理
  18. * 如果失败,返回0,如果成功,返回纹理编号
  19. */
  20. GLuint load_texture(const char* file_name)
  21. {
  22. GLint width, height, total_bytes;
  23. GLubyte* pixels = 0;
  24. GLint last_texture_ID;
  25. GLuint texture_ID = 0;
  26. // 打开文件,如果失败,返回
  27. FILE* pFile = fopen(file_name, "rb");
  28. if( pFile == 0 )
  29. return 0;
  30. // 读取文件中图象的宽度和高度
  31. fseek(pFile, 0x0012, SEEK_SET);
  32. fread(&width, 4, 1, pFile);
  33. fread(&height, 4, 1, pFile);
  34. fseek(pFile, BMP_Header_Length, SEEK_SET);
  35. // 计算每行像素所占字节数,并根据此数据计算总像素字节数
  36. {
  37. GLint line_bytes = width * 3;
  38. while( line_bytes % 4 != 0 )
  39. ++line_bytes;
  40. total_bytes = line_bytes * height;
  41. }
  42. // 根据总像素字节数分配内存
  43. pixels = (GLubyte*)malloc(total_bytes);
  44. if( pixels == 0 )
  45. {
  46. fclose(pFile);
  47. return 0;
  48. }
  49. // 读取像素数据
  50. if( fread(pixels, total_bytes, 1, pFile) <= 0 )
  51. {
  52. free(pixels);
  53. fclose(pFile);
  54. return 0;
  55. }
  56. {
  57. GLint max;
  58. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
  59. if( !power_of_two(width)
  60. || !power_of_two(height)
  61. || width > max
  62. || height > max )
  63. {
  64. const GLint new_width = 1024; //修改为2的整数次幂
  65. const GLint new_height = 1024; // 规定缩放后新的大小为边长的正方形
  66. GLint new_line_bytes, new_total_bytes;
  67. GLubyte* new_pixels = 0;
  68. // 计算每行需要的字节数和总字节数
  69. new_line_bytes = new_width * 3;
  70. while( new_line_bytes % 4 != 0 )
  71. ++new_line_bytes;
  72. new_total_bytes = new_line_bytes * new_height;
  73. // 分配内存
  74. new_pixels = (GLubyte*)malloc(new_total_bytes);
  75. if( new_pixels == 0 )
  76. {
  77. free(pixels);
  78. fclose(pFile);
  79. return 0;
  80. }
  81. // 进行像素缩放
  82. gluScaleImage(GL_RGB,
  83. width, height, GL_UNSIGNED_BYTE, pixels,
  84. new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
  85. // 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height
  86. free(pixels);
  87. pixels = new_pixels;
  88. width = new_width;
  89. height = new_height;
  90. }
  91. }
  92. // 分配一个新的纹理编号
  93. glGenTextures(1, &texture_ID);
  94. if( texture_ID == 0 )
  95. {
  96. free(pixels);
  97. fclose(pFile);
  98. return 0;
  99. }
  100. // 绑定新的纹理,载入纹理并设置纹理参数
  101. // 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复
  102. glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
  103. glBindTexture(GL_TEXTURE_2D, texture_ID);
  104. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  105. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  106. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  107. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  108. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  109. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
  110. GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
  111. glBindTexture(GL_TEXTURE_2D, last_texture_ID);
  112. // 之前为pixels分配的内存可在使用glTexImage2D以后释放
  113. // 因为此时像素数据已经被OpenGL另行保存了一份(可能被保存到专门的图形硬件中)
  114. free(pixels);
  115. return texture_ID;
  116. }
  117. void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte absolute)
  118. {
  119. GLint width, height;
  120. GLubyte* pixels = 0;
  121. // 获得纹理的大小信息
  122. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
  123. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
  124. // 分配空间并获得纹理像素
  125. pixels = (GLubyte*)malloc(width*height*4);
  126. if( pixels == 0 )
  127. return;
  128. glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
  129. // 修改像素中的Alpha值
  130. // 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2], pixels[i*4+3]
  131. // 分别表示第i个像素的蓝、绿、红、Alpha四种分量,0表示最小,255表示最大
  132. {
  133. GLint i;
  134. GLint count = width * height;
  135. for(i=0; i<count; ++i)
  136. {
  137. if( abs(pixels[i*4] - b) <= absolute
  138. && abs(pixels[i*4+1] - g) <= absolute
  139. && abs(pixels[i*4+2] - r) <= absolute )
  140. pixels[i*4+3] = 0;
  141. else
  142. pixels[i*4+3] = 255;
  143. }
  144. }
  145. // 将修改后的像素重新设置到纹理中,释放内存
  146. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
  147. GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
  148. free(pixels);
  149. }
  150. void display(void)
  151. {
  152. static int initialized = 0;
  153. static GLuint texWindow = 0;
  154. static GLuint texPicture = 0;
  155. // 执行初始化操作,包括:读取背景,读取前景,将相框由BGR颜色转换为BGRA,启用二维纹理
  156. if( !initialized )
  157. {
  158. texPicture = load_texture("backImage.bmp");
  159. texWindow = load_texture("frontImage.bmp");
  160. glBindTexture(GL_TEXTURE_2D, texWindow);
  161. texture_colorkey(255, 255, 255, 10);
  162. glEnable(GL_TEXTURE_2D);
  163. initialized = 1;
  164. }
  165. // 清除屏幕
  166. glClear(GL_COLOR_BUFFER_BIT);
  167. // 绘制背景,此时不需要进行Alpha测试,所有的像素都进行绘制
  168. glMatrixMode(GL_PROJECTION);
  169. glLoadIdentity();
  170. gluPerspective(65,1,2,50);
  171. glMatrixMode(GL_MODELVIEW);
  172. glLoadIdentity();
  173. gluLookAt(0,0,4.5,0,0,0,0,1,0);
  174. glBindTexture(GL_TEXTURE_2D, texPicture);
  175. glDisable(GL_ALPHA_TEST);
  176. glBegin(GL_QUADS);
  177. glTexCoord2f(0, 0); glVertex3f(-6.0f, -6.0f,-3);
  178. glTexCoord2f(0, 1); glVertex3f(-6.0f, 6.0f,-3);
  179. glTexCoord2f(1, 1); glVertex3f( 6.0f, 6.0f,-3);
  180. glTexCoord2f(1, 0); glVertex3f( 6.0f, -6.0f,-3);
  181. glEnd();
  182. // 绘制前景,此时进行Alpha测试,只绘制不透明部分的像素
  183. glBindTexture(GL_TEXTURE_2D, texWindow);
  184. glEnable(GL_ALPHA_TEST);
  185. glAlphaFunc(GL_GREATER, 0.5f);
  186. glBegin(GL_QUADS);
  187. glTexCoord2f(0, 0); glVertex3f(-3.0f, -3.0f,0);
  188. glTexCoord2f(0, 1); glVertex3f(-3.0f, 3.0f,0);
  189. glTexCoord2f(1, 1); glVertex3f( 3.0f, 3.0f,0);
  190. glTexCoord2f(1, 0); glVertex3f( 3.0f, -3.0f,0);
  191. glEnd();
  192. // 交换缓冲
  193. glutSwapBuffers();
  194. }
  195. int main(int argc, char* argv[])
  196. {
  197. // GLUT初始化
  198. glutInit(&argc, argv);
  199. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
  200. glutInitWindowPosition(100, 100);
  201. glutInitWindowSize(WindowWidth, WindowHeight);
  202. glutCreateWindow(WindowTitle);
  203. glutDisplayFunc(&display);
  204. // 开始显示
  205. glutMainLoop();
  206. return 0;
  207. }

实现效果,左侧视角:

正视视角:

右侧视角:

剪裁测试:

所谓剪裁测试就是限定一个矩形绘制窗口,只有在这个窗口范围内的像素才会被绘制,窗口外的像素被忽略。使用glEnable(GL_SCISSOR_TEST)开启剪裁测试,使用GLDisable(GL_SCISSOR_TEST)关闭。使用

glScissor (GLint x, GLint y, GLsizei width, GLsizei height)设定剪裁窗口。

在上例代码的基础上,只需要在显示部分函数display清屏之后,加入以下两句:

  1. glEnable(GL_SCISSOR_TEST);
  2. glScissor(0,0,300,300);

就可以实现把显示画面划定在以左下角为起点的300*300的剪裁窗口中,显示效果如下:

OpenGL(十三) Alpha测试、剪裁测试的更多相关文章

  1. OpenGL ES 2.0 剪裁测试

    剪裁测试:可以在渲染时用来限制绘制区域,通过此技术可以在屏幕(帧缓冲)上指定一个矩形区域. //启用剪裁测试 GLES20.glEnable(GL10.GL_SCISSOR_TEST); //设置区域 ...

  2. OpenGL-----深度测试,剪裁测试、Alpha测试和模板测试

    片断测试其实就是测试每一个像素,只有通过测试的像素才会被绘制,没有通过测试的像素则不进行绘制.OpenGL提供了多种测试操作,利用这些操作可以实现一些特殊的效果.我们在前面的课程中,曾经提到了“深度测 ...

  3. OpenGL ES 中的模板测试

    模板测试的主要功能是丢弃一部分片元,相对于深度检测来说,模板测试提出的片元数量相对较少.模板测试发生在剪裁测试之后,深度测试之前. 使用模板测试时很重要的代码提示: 1.glClear( GL_STE ...

  4. Alpha 和Beta 测试

    在正式发布产品之前往往要先发布一些测试版,让用户能够反馈出相关信息,或者找到存在的Bug,以便在正式版中得到解决. 特别是在有客户参加的情况下,对系统进行测试可能会出现一些我们没有考虑的情况,还可以解 ...

  5. 团队进行Alpha冲刺--项目测试

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--项目测试 作业正文 如下 其他参 ...

  6. 【Alpha版本】测试文档

    App测试点 UI测试 测试各界面控件布局.总体色调.风格是否能够给用户良好的使用感. 文字是否正确,图文符合,文字与图片的组合是否够美观. 操作是否友好,是否易于操作,是否繁琐,存在无用操作. 配图 ...

  7. 冒烟测试、α测试、Beta测试、性能测试

    “冒烟测试”(也可称为showcase)这一术语描述的是在将代码更改嵌入到产品的源树中之前对这些更改进行验证的过程. 冒烟测试(smoke test)在测试中发现问题,找到了一个Bug,然后开发人员会 ...

  8. APP手工测试01-app专项测试要点-测试、开发环境-敏捷开发

    APP专项测试要点 兼容性测试 安装,卸载,升级 交叉事件 PUSH消息推送测试 性能测试 其他类型 兼容性测试 手机型号 系统版本 安卓 (版本4.4开始兼容) IOS(版本9.x开始兼容) 屏幕尺 ...

  9. APP敏捷测试,测试和开发并行!

    测试和开发具有同等重要的作用,从一开始,测试和开发就是相向而行的.测试是开发团队的一支独立的.重要的支柱力量. 测试要具备独立性,独立分析业务需求,独立配置测试环境,独立编写测试脚本,独立开发测试工具 ...

随机推荐

  1. 使用XX-Net永久访问真正的互联网

    XX-Net基于GoAgent(代理软件),使用谷歌App Engine(GAE)代理服务器通过防火墙,是github上的一个开源项目. https://github.com/XX-net/XX-Ne ...

  2. IfSpeed 带宽计算

    http://www.360doc.com/content/11/0304/22/2614615_98214710.shtml http://www.cisco.com/support/zh/477/ ...

  3. [JS Compose] 1. Refactor imperative code to a single composed expression using Box

    After understanding how Box is, then we are going to see how to use Box to refacotr code, to un-nest ...

  4. sigmoid function vs softmax function

    DIFFERENCE BETWEEN SOFTMAX FUNCTION AND SIGMOID FUNCTION 二者主要的区别见于, softmax 用于多分类,sigmoid 则主要用于二分类: ...

  5. python opencv3 —— findContours

    findContours 是 opencv 下的轮廓提取函数. 1. api 分析 findContours(image, mode, method[, contours[, hierarchy[, ...

  6. Android多线程研究(1)——线程基础及源码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com. ...

  7. ORACLE会话数、连接数配置

    ORACLE会话数.连接数配置 ORACLE会话数.连接数配置 ORACLE的会话数和连接数参数配置 以sysdba身份登录 sqlplus sys/xxxx as sysdba; 查看最大连接数: ...

  8. Android 输入框弹出样式

    在androidMainfest.xml文件里 在Activity中设置 [A]stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置 [B]stateU ...

  9. (一一六)新浪微博client的离线缓存实现思路

    上一节(一一五)利用NSKeyedArchiver实现随意对象转为二进制介绍了将随意对象转化为二进制数据和还原的方法.可用于实现本节介绍的微博数据离线缓存. 通过新浪官方的API能够发现,返回的微博数 ...

  10. Android JNI 自定义对象为参数和返回值

    ndroid JNI 提供了很强大的支持,不仅可以采用基本类型做为参数和返回值,同时也支持自定义对象做为参数和返回值,以下举例说明. 一.定义作为输入和返回的自定义类 (仅提供两个简单类型和一个打印函 ...