使用 CImage 类在 OpenGL 中蒙版纹理






3.64/5 (13投票s)
使用 CImage 类从位图图像文件中在 OpenGL 中蒙版纹理(只需调用文件名)
引言
在我之前的文章 使用 CImage 类在 OpenGL 中进行纹理映射 中,我仅通过调用图像文件名就能演示一些有用的纹理处理技术,用于纹理映射,而无需进行大量分阶段的条件实现。紧随其后的应该是图像蒙版应用程序,同样安排为仅调用图像位图文件的名称。
背景
在 OpenGL 中实现仅调用图像位图文件名的纹理蒙版的过程已经通过 CImage 类的应用开发完成。演示项目 MaskTexture
是从我之前的文章项目 ImgTexture
派生而来,而 ImgTexture
项目又从标准的 **MFC Cube Sample** 项目派生而来,并使用 CodeProject ProjRename 程序重命名。
Using the Code
全局过程 LoadMaskTexture(LPCTSTR fName)
和相关过程 MakeBWMask(CImage * pImg, CDC *pDC, int w, int h, COLORREF eColor, int BPP)
已添加到之前文章项目 ImgTexture
的 GlobGLTexture.cpp 文件中。要使用提供的技术,您可以通过菜单 **PROJECT**->**Add Existing Item...** 命令将 GlobGLTexture.cpp 文件插入到您自己的项目中。
蒙版纹理加载过程
DWORD LoadMaskTexture(LPCTSTR fName) //Load Mask texture from Bitmap Image file
{
CImage img;
HRESULT hResult = img.Load(fName); //Standard procedure of CImage loading
if (FAILED(hResult)) {
_TCHAR fmt[1028];
_stprintf_s((_TCHAR *)fmt, hResult,
_T("Error %d\n%s\nin file:\n%s"), _com_error(hResult).ErrorMessage(), fName);
MessageBox(NULL, fmt, _T("Error:"), MB_OK | MB_ICONERROR);
return FALSE;
}//if(FAILED(hResult))
if (img.GetBPP() != 24) //if Bitmap format not compatible with
//GL_BGR_EXT
{
CImage tmg;
tmg.Create(img.GetWidth(), img.GetHeight(), 24); //Create CImage compatible
//with GL_BGR_EXT
img.BitBlt(tmg.GetDC(), CPoint(0, 0)); //Copy Original Image to
//the environment created
}
CImage * pSmg = new CImage;
CDC * tDC = CDC::FromHandle(img.GetDC()); //Temporarily graphic context
//Create Black & White mask from original image:
MakeBWMask(pSmg, tDC, img.GetWidth(), img.GetHeight(), tDC->GetPixel(0, 0),
img.GetBPP());
CBitmap * pBmw = GetImgBitmap(pSmg); //Bitmap of the
//Black & White mask
if (pBmw == NULL)
return FALSE;
BITMAP BMPw;
pBmw->GetBitmap(&BMPw);
GLuint nBw = LoadGLTexture(&BMPw); //Create texture of the
//Black & White mask
CDC * pDC = new CDC; //Temporarily graphic context
pDC->CreateCompatibleDC(CDC::FromHandle(img.GetDC()));
CBitmap bmt;
bmt.CreateCompatibleBitmap(CDC::FromHandle(img.GetDC()),
img.GetWidth(), img.GetHeight());
CBitmap * pBm = pDC->SelectObject(&bmt);
//Copy Black & White mask into Temporarily graphic context:
pDC->BitBlt(0, 0, img.GetWidth(), img.GetHeight(),
CDC::FromHandle(pSmg->GetDC()), 0, 0, SRCCOPY);
//Invert colours in Copy Temporarily graphic context mask int
//Temporarily graphic context:
pDC->BitBlt(0, 0, img.GetWidth(),
img.GetHeight(), NULL, 0, 0, DSTINVERT);
//Copy Temporarily graphic context into original image into
//making background color Black:
CDC::FromHandle(img.GetDC())->BitBlt(0, 0, img.GetWidth(),
img.GetHeight(), pDC, 0, 0, SRCAND);
pDC->SelectObject(pBm);
bmt.DeleteObject();
pDC->DeleteDC();
delete pDC; //Remove Temporarily graphic context
CBitmap * pBmi = GetImgBitmap(&img);
BITMAP BMPi;
pBmi->GetBitmap(&BMPi);
delete pBmw; //Clear all Temoparily
delete pSmg;
pSmg = NULL;
GLuint nImg = LoadGLTexture(&BMPi); //Create texture of the mask
//with Black background
delete pBmi;
return MAKELONG(nImg, nBw); //return HIWORD with color texture name
//and LOWORD with Black & White texture name
}
蒙版纹理的方案已在下方的表格中提供
原始蒙版图像位图格式和单色背景色;左上角像素 GetPixel(0,0) 必须是背景色 | ![]() | 原始背景图像;可以是任何格式 | ![]() | |
![]() | ![]() | |||
通过 MakeBWMask 过程提供的黑白蒙版图像 | ![]() | ![]() | 将原始背景图像中的蒙版区域 1 1! 1! 清除为黑色 | ![]() |
![]() | ![]() | |||
将背景更改为黑色,并反转黑白蒙版图像 | ![]() | ![]() | 最终蒙版图像是将黑色背景的彩色蒙版与原始背景纹理组合的结果,其中包含用于蒙版的黑色区域 | ![]() |
上表中左侧一列演示了 LoadMaskTexture
创建两个蒙版纹理的步骤
- 通过 MakeBWMask 过程提供的黑白蒙版图像
- 带有黑色背景的彩色蒙版图像,以及反转后的黑白蒙版图像 反转
创建黑白蒙版图像的过程(将所有背景像素变为白色,其他变为黑色):
void MakeBWMask(CImage * pImg, CDC *pDC, int w, int h, COLORREF eColor, int BPP)
{
pImg->Create(w, h, BPP);
CDC * tDC = CDC::FromHandle(pImg->GetDC());
for (int i = 0; i < w; i++)
for (int j = 0; j < h; j++)
{
COLORREF rgb = pDC->GetPixel(i, j); //get pixel colour
if (rgb == eColor)
tDC->SetPixel(i, j, RGB(255, 255, 255)); //if the colour is a
//background colour
//set pixel white;
else
tDC->SetPixel(i, j, RGB(0, 0, 0)); //if the colour is not
//a background
//colour, set pixel black;
}
}
插入的变量
int m_texNum; //Current order number of the name of the texture
int m_maskNum; //Current order number of the name of the mask texture
CWordArray m_globTexture; //Array of the textures' names available
CDWordArray m_globMask; //Array of the bitmap mask textures' names available
enum VIEW_TYPE
{
VIEW_DEFAULT, //Original Cube Sample View
VIEW_TEXTURE, //Texture View
VIEW MASK, //Masking View
};
原始的 CImgTextureView::Init()
过程及其相关过程保持不变;在演示目的的 CImgTextureView::OnCreate
过程中,位于根目录 **Data 文件夹** 中的图像文件的纹理实现的两行和蒙版实现的三个行
int CImgTextureView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
Init(); // initialize OpenGL
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/MSUN.jpg"))); //you may insert
//here any image file
//in any pathway
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/famrt.jpg")));//and as much as
//you like
m_globMask.Add(LoadMaskTexture(_T("Data/vldv.bmp"))); //you may insert here any
//bitmap image file in
//any pathway
m_globMask.Add(LoadMaskTexture(_T("Data/ussr.bmp"))); //and as much as you like;
//just keep in mind that
//the color
m_globMask.Add(LoadMaskTexture(_T("Data/rsfsr.bmp"))); //of the left top pixel
//(GetPixel(0,0)) assumed as
//a background color
return 0;
} ;
您可以在此处插入任何路径有效的图像文件和任何蒙版位图图像文件,数量不限。在原始 CMaskTextureView::DrawScene
过程中,插入了蒙版纹理处理块
case VIEW_MASK:
{
//Every face visibility checking required(depth test)
GLdouble model[16]; //MODELVIEW_MATRIX
glGetDoublev(GL_MODELVIEW_MATRIX, model);
GLdouble proj[16]; //PROJECTION_MATRIX
glGetDoublev(GL_PROJECTION_MATRIX, proj);
GLint vw[4]; //VIEWPORT MATRIX
glGetIntegerv(GL_VIEWPORT, vw);
GLdouble xt0, yt0, zt0; //true coord of the cube center
gluProject(0.0, 0.0, 0.0, model,
proj, vw, &xt0, &yt0, &zt0); //calc true coord of the
//cube center
//////////////Front Face
// Front Face Bkg
GLdouble xt, yt, zt;
gluProject(0.0, 0.0, a, model, proj, vw, &xt, &yt, &zt); //calc true coord
//of the face center
if (zt < zt0) //if face is visible
{
glBindTexture(GL_TEXTURE_2D, m_globTexture[m_texNum]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
// Front Face BW
glBindTexture(GL_TEXTURE_2D, HIWORD(m_globMask[m_maskNum]));
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
glBlendFunc(GL_DST_COLOR, GL_ZERO); // Blend Screen Color With
// Zero (Black)
glBegin(GL_QUADS);
glTexCoord2f(roll + 0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(roll + 2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(roll + 2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(roll + 0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
// Front Face Mask
glBindTexture(GL_TEXTURE_2D, LOWORD(m_globMask[m_maskNum]));
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color to
// the screen
glBegin(GL_QUADS);
glTexCoord2f(roll + 0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(roll + 2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(roll + 2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(roll + 0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
}
//////////////Back Face
gluProject(0.0, 0.0, -a, model, proj, vw, &xt, &yt, &zt); //calc true coord
//of the face center
if (zt < zt0) //if face is visible
{
..............................................................................
..............................................................................
///////////////////////////////////////////// Left face
// Left Face bkg
gluProject(-a, 0.0, 0.0,
model, proj, vw, &xt, &yt, &zt); //calc true coord of
//the face center
if (zt < zt0) //if face is visible
{
glBindTexture(GL_TEXTURE_2D,
m_globTexture[m_texNum]);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-a, a, -a);
glEnd();
// Left Face BW
glBindTexture
(GL_TEXTURE_2D, HIWORD(m_globMask[m_maskNum]));
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
glBlendFunc(GL_DST_COLOR, GL_ZERO); // Blend Screen Color
// With Zero (Black)
glBegin(GL_QUADS);
glTexCoord2f(0.0f, roll + 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, roll + 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, roll + 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, roll + 1.0f); glVertex3f(-a, a, -a);
glEnd();
// Left Face Mask
glBindTexture
(GL_TEXTURE_2D, LOWORD(m_globMask[m_maskNum]));
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color To The Screen
glBegin(GL_QUADS);
glTexCoord2f(0.0f, roll + 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, roll + 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, roll + 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, roll + 1.0f); glVertex3f(-a, a, -a);
glEnd();
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
}
roll += 0.05f; // Increase Our Texture Roll Variable
if (roll>1.0f) // Is Roll Greater Than One
{
roll -= 1.0f; // Subtract 1 From Roll
}
}
break;
在此块中,我们需要在处理每个面之前设置深度测试,因为 GL_DEPTH_TEST
在混合时设置为禁用。在绘制每个场景之前,我们调用标准的 gluProject
过程来计算立方体中心的真实坐标。在绘制每个面之前,我们调用标准的 gluProject
过程来计算面的中心的真实坐标。如果面的中心比立方体的中心更近,则该面是可见的。
表中右侧的 表格 演示了蒙版纹理的 DrawScene
步骤
- 原始图像纹理映射 执行方式与通常的纹理映射过程相同
- 将原始背景图像中的蒙版区域清除为黑色
- 最终蒙版图像 是将黑色背景的彩色蒙版与原始背景纹理组合的结果,其中包含用于蒙版的黑色区域
完成蒙版后,滚动因子增加。
以下所有 **菜单和快捷键** 命令均通过标准的 AppWizard
技术实现。
应用程序演示菜单和键盘命令
为演示 ImgTexture
项目实现而安排了一些菜单和一些特殊快捷键
- **菜单文件**->**打开** - 选择用于纹理映射的图像文件
- **菜单文件**->**打开蒙版 *.bmp** - 选择用于纹理蒙版的位图图像文件
- **菜单视图**->**默认** - 原始立方体性能
- **菜单视图**->**纹理** - 当前纹理性能
- **菜单视图**->**下一个纹理** - 下一个纹理性能(也可单击右箭头)
- **菜单视图**->**上一个纹理** - 上一个纹理性能(也可单击左箭头)
- **菜单视图**->**下一个蒙版** - 下一个蒙版性能(也可单击 Page Up)
- **菜单视图**->**上一个蒙版** - 上一个蒙版性能(也可单击 Page Down)
关注点
上述技术是尝试演示一种简单的蒙版纹理实现可能性。您可以通过菜单 **PROJECT**->**Add Existing Item...** 命令将 GlobGLTexture.cpp 文件插入到您自己的项目中,在您自己的应用程序中使用以上过程。
该项目是在 **MFC 平台**上开发的。尽管如此,GlobGLTexture.cpp 过程在 **Win32** 中也有效,并且可用于 **移动** 应用程序。
历史
- 2016年11月21日:初始版本