65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CImage 类在 OpenGL 中蒙版纹理

2016年11月21日

CPOL

4分钟阅读

viewsIcon

19245

downloadIcon

1159

使用 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) 已添加到之前文章项目 ImgTextureGlobGLTexture.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日:初始版本
© . All rights reserved.