对于一幅图像来说,可以看做是一个二维像素点的矩阵。剪纸效果的纹理贴图是指一张图片有的像素点正常显示,有的像素点则不显示(完全透明)。有的图片的每个像素有 3 个通道 R、G、B(分别代表红、绿、蓝),其值 0 ~ 255;也有的图片的每个像素有 4 个通道R、G、B、A(alpha值,代表透明度,opengl中可用于混合)。
一般 opengl 中比较常用的图片格式为 bmp,其仅仅含有 RGB 三个通道,并不含 alpha 通道。因此,如果要使用 bmp 制作剪纸效果的纹理的话,这里提出2个方法:
方法一:使用透明的方法显示纹理图片
-
在初始化时,调用
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
和glEnable(GL_BLEND)
开启混合功能。 -
在初始化时调用
glEnable(GL_TEXTURE_2D)
开启纹理贴图的功能。使用pImage = auxDIBImageLoad(fileName)
加载图片。其中pImage的数据类型为
typedef struct _AUX_RGBImageRec { GLint sizeX, sizeY;//像素的x,y数值 unsigned char *data;//像素的内容,对于bmp来说,其大小为3*sizeX*sizeY } AUX_RGBImageRec;
-
虽然图片中并没有 alpha 通道,但是对于一般剪纸图片来说,可以假定不显示的部门为白色,而显示的部分为其他颜色。由此可以新建一个 4 通道的数组
unsigned char* pPic = new unsigned char[4 * pImage->sizeX * pImage->sizeY]; size_t NUM = pImage->sizeX * pImage->sizeY; for (int i=0; i<NUM; ++i) { int idx0 = i * 3; int idx1 = i * 4; pPic[idx1] = 255 - pImage->data[idx0];// 因为GL_BLEND模式下,图片会反色显示 bool r = pPic[idx1] < 10; pPic[idx1+1] = 255 - pImage->data[idx0+1]; bool g = pPic[idx1+1] < 10; pPic[idx1+2] = 255 - pImage->data[idx0+2]; bool b = pPic[idx1+2] < 10; if (r && g && b) pPic[idx1+3] = 0; // 若像素点的颜色接近白色,则设置alpha值为0,表示完全透明 else pPic[idx1+3] = 255;// 若像素点的颜色不为白色,则设置alpha值为255,表示完全不透明 }
-
绑定并生成纹理图片
glBindTexture(GL_TEXTURE_2D, m_Texture[texName]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //Set texture environment parameter // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); /* gluBuild2DMipmaps(GL_TEXTURE_2D , 4 // 表示有RGBA四个通道 , pImage->sizeX , pImage->sizeY , GL_RGBA // 重要 , GL_UNSIGNED_BYTE , pPic);*/ // 这个函数也可以 glTexImage2D(GL_TEXTURE_2D , 0 , GL_RGBA // 重要 , pImage->sizeX , pImage->sizeY , 0 , GL_RGBA // 重要 , GL_UNSIGNED_BYTE , pPic);
-
删除pPic和pImage的内存
-
显示剪纸效果的纹理图片
-
为了清楚看出剪纸效果,这里画一个黄色的矩形作为背景。
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);// 设置为GL_DECAL float oldColor[4]; glGetFloatv(GL_CURRENT_COLOR, oldColor); glColor4f(1.0f, 1.0f, 0.0f, 1.0f);// 设置alpha值为1,表示完全不透明 glPushMatrix(); glBegin(GL_POLYGON); glVertex3f(-150.0f, -150.0f, -100.0f); glVertex3f(150.0f, -150.0f, -100.0f); glVertex3f(150.0f, 150.0f, -100.0f); glVertex3f(-150.0f, 150.0f, -100.0f); glEnd(); glPopMatrix(); glColor4fv(oldColor); // 然后再绘制纹理图片 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);//设置为GL_BLEND glBindTexture(GL_TEXTURE_2D, m_Texture[0]); glBegin(GL_POLYGON); glTexCoord2f(0, 0); glVertex3f(-60.0f, -120.0f, 100.0f); glTexCoord2f(1, 0); glVertex3f( 60.0f, -120.0f, 100.0f); glTexCoord2f(1, 1); glVertex3f( 60.0f, 120.0f, 100.0f); glTexCoord2f(0, 1); glVertex3f(-60.0f, 120.0f, 100.0f); glEnd();
-
显示结果
背景为白色的一幅图片:
image
显示的纹理结果为:
image
image
方法二:不使用透明的方法显示纹理图片,但使用模板缓冲区的方法显示纹理图片
待续~~_
网友评论