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(大于则通过):

#define WindowWidth   400
#define WindowHeight 400
#define WindowTitle "OpenGLAlpha测试"
#define BMP_Header_Length 54
#include <gl/glut.h>
#include <stdio.h>
#include <stdlib.h> GLuint texGround;
GLuint texWall;
int power_of_two(int n)
{
if( n <= 0 )
return 0;
return (n & (n-1)) == 0;
}
/* 函数load_texture
* 读取一个BMP文件作为纹理
* 如果失败,返回0,如果成功,返回纹理编号
*/
GLuint load_texture(const char* file_name)
{
GLint width, height, total_bytes;
GLubyte* pixels = 0;
GLint last_texture_ID;
GLuint texture_ID = 0;
// 打开文件,如果失败,返回
FILE* pFile = fopen(file_name, "rb");
if( pFile == 0 )
return 0;
// 读取文件中图象的宽度和高度
fseek(pFile, 0x0012, SEEK_SET);
fread(&width, 4, 1, pFile);
fread(&height, 4, 1, pFile);
fseek(pFile, BMP_Header_Length, SEEK_SET);
// 计算每行像素所占字节数,并根据此数据计算总像素字节数
{
GLint line_bytes = width * 3;
while( line_bytes % 4 != 0 )
++line_bytes;
total_bytes = line_bytes * height;
}
// 根据总像素字节数分配内存
pixels = (GLubyte*)malloc(total_bytes);
if( pixels == 0 )
{
fclose(pFile);
return 0;
}
// 读取像素数据
if( fread(pixels, total_bytes, 1, pFile) <= 0 )
{
free(pixels);
fclose(pFile);
return 0;
}
{
GLint max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
if( !power_of_two(width)
|| !power_of_two(height)
|| width > max
|| height > max )
{
const GLint new_width = 1024; //修改为2的整数次幂
const GLint new_height = 1024; // 规定缩放后新的大小为边长的正方形
GLint new_line_bytes, new_total_bytes;
GLubyte* new_pixels = 0;
// 计算每行需要的字节数和总字节数
new_line_bytes = new_width * 3;
while( new_line_bytes % 4 != 0 )
++new_line_bytes;
new_total_bytes = new_line_bytes * new_height;
// 分配内存
new_pixels = (GLubyte*)malloc(new_total_bytes);
if( new_pixels == 0 )
{
free(pixels);
fclose(pFile);
return 0;
}
// 进行像素缩放
gluScaleImage(GL_RGB,
width, height, GL_UNSIGNED_BYTE, pixels,
new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height
free(pixels);
pixels = new_pixels;
width = new_width;
height = new_height;
}
}
// 分配一个新的纹理编号
glGenTextures(1, &texture_ID);
if( texture_ID == 0 )
{
free(pixels);
fclose(pFile);
return 0;
}
// 绑定新的纹理,载入纹理并设置纹理参数
// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
glBindTexture(GL_TEXTURE_2D, last_texture_ID);
// 之前为pixels分配的内存可在使用glTexImage2D以后释放
// 因为此时像素数据已经被OpenGL另行保存了一份(可能被保存到专门的图形硬件中)
free(pixels);
return texture_ID;
}
void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte absolute)
{
GLint width, height;
GLubyte* pixels = 0;
// 获得纹理的大小信息
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
// 分配空间并获得纹理像素
pixels = (GLubyte*)malloc(width*height*4);
if( pixels == 0 )
return;
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
// 修改像素中的Alpha值
// 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2], pixels[i*4+3]
// 分别表示第i个像素的蓝、绿、红、Alpha四种分量,0表示最小,255表示最大
{
GLint i;
GLint count = width * height;
for(i=0; i<count; ++i)
{
if( abs(pixels[i*4] - b) <= absolute
&& abs(pixels[i*4+1] - g) <= absolute
&& abs(pixels[i*4+2] - r) <= absolute )
pixels[i*4+3] = 0;
else
pixels[i*4+3] = 255;
}
}
// 将修改后的像素重新设置到纹理中,释放内存
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
free(pixels);
}
void display(void)
{
static int initialized = 0;
static GLuint texWindow = 0;
static GLuint texPicture = 0;
// 执行初始化操作,包括:读取背景,读取前景,将相框由BGR颜色转换为BGRA,启用二维纹理
if( !initialized )
{
texPicture = load_texture("backImage.bmp");
texWindow = load_texture("frontImage.bmp");
glBindTexture(GL_TEXTURE_2D, texWindow);
texture_colorkey(255, 255, 255, 10);
glEnable(GL_TEXTURE_2D);
initialized = 1;
}
// 清除屏幕
glClear(GL_COLOR_BUFFER_BIT);
// 绘制背景,此时不需要进行Alpha测试,所有的像素都进行绘制 glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65,1,2,50); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,4.5,0,0,0,0,1,0);
glBindTexture(GL_TEXTURE_2D, texPicture);
glDisable(GL_ALPHA_TEST);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(-6.0f, -6.0f,-3);
glTexCoord2f(0, 1); glVertex3f(-6.0f, 6.0f,-3);
glTexCoord2f(1, 1); glVertex3f( 6.0f, 6.0f,-3);
glTexCoord2f(1, 0); glVertex3f( 6.0f, -6.0f,-3);
glEnd(); // 绘制前景,此时进行Alpha测试,只绘制不透明部分的像素
glBindTexture(GL_TEXTURE_2D, texWindow);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(-3.0f, -3.0f,0);
glTexCoord2f(0, 1); glVertex3f(-3.0f, 3.0f,0);
glTexCoord2f(1, 1); glVertex3f( 3.0f, 3.0f,0);
glTexCoord2f(1, 0); glVertex3f( 3.0f, -3.0f,0);
glEnd();
// 交换缓冲
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
// GLUT初始化
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WindowWidth, WindowHeight);
glutCreateWindow(WindowTitle);
glutDisplayFunc(&display);
// 开始显示
glutMainLoop();
return 0;
}

实现效果,左侧视角:

正视视角:

右侧视角:

剪裁测试:

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

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

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

        glEnable(GL_SCISSOR_TEST);
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. 安卓 WebView加载本地图片时居中显示

    在一个项目中使用WebView显示gif图片(自定义的View无法放大gif),当图片过小时只在左侧显示,经过研究发现无论设置android:layout_gravity="center_h ...

  2. swift学习第二天:swift中的基本数据类型

    一:swift基本数据类型 Swift中的数据类型也有:整型/浮点型/对象类型/结构体类型等等 先了解整型和浮点型 整型 有符号 Int8 : 有符号8位整型 Int16 : 有符号16位整型 Int ...

  3. Visual Stdio 环境下使用 GSL (GNU Scientific Library)

    Visual Stdio 环境下使用 GSL (GNU Scientific Library) 经測试.这里的方法不适用于VS2015. * 这篇文章有点过时了.建议从以下网址下载能够在 vs 环境下 ...

  4. 用JavaScript和CSS实现“在页面中水平和垂直居中”的时钟

    思路:实现起来最麻烦的事实上是水平居中和垂直居中,当中垂直居中是最麻烦的. 考虑到浏览器兼容性,网上看了一些资料,发如今页面中垂直居中确实没有什么太好的办法. 于是就採用了position:fixed ...

  5. js对时间的操作相关

    摘自网络,我主要用了日期增加若干天之后获得的日期,就是现在是5月2号,我增加30天,应该返回6月几号来着,就是这个意思 用到了Date.prototype.DateAdd 方法,prototype的意 ...

  6. 我的IT成长路——为梦想扬帆起航

    在持续了一个多月的雾霾之后,西安这座城市又看到了久违的阳光,好的天气预兆新梦想的开始.我的IT路从开始接触编程开始已经有5个年头了,从一个没有摸过计算机的农村男孩到现在学会几门编程语言的IT人,这段路 ...

  7. 【codeforces 757C】Felicity is Coming!

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  8. Android ReentrantLock

    synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候. 1.某个线程在等待一 ...

  9. C++ 与 Java 语言对比

    1 . Java 是完全封装的,而 C++ 的函数是可以定义在 Class 的外部的.从这里就可以看出 C++ 的 OO 思想不够彻底,至少在封装这一点上. 2. C++ 中有拷贝构造函数,可以把一个 ...

  10. 常用的iOS开发或者优化的小工具

    下面介绍一下我常用的iOS开发或者优化的小工具 由于很多工具大多数博客都已经介绍过了,我就列举一些我认为还不错但是大家不常列举的: Crafter https://github.com/krzyszt ...