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

使用 CImage 类进行 OpenGL 纹理映射

2016年8月5日

CPOL

2分钟阅读

viewsIcon

17112

downloadIcon

1195

使用 CImage 类(只需调用文件名)从任何格式的任何图像文件在 OpenGL 中进行纹理映射。

引言

在 OpenGL 中实现纹理映射是一个繁琐的过程。有时,仅仅调用图像文件名进行纹理映射,而无需大量条件实现,就值得拥有一些简单的操作。

背景

使用CImage 类开发了在 OpenGL 中通过调用图像文件名来实现纹理映射的过程。演示项目 ImgTexture 源自标准 MFC Cube Sample 项目,并使用 CodeProject ProjRename 程序进行了重命名。

Using the Code

全局过程 LoadImgTexture(LPCTSTR fName) 和两个相关过程 GetImgBitmap(CImage * pImg)LoadGLTexture(BITMAP * pBm) 位于插入到 ImgTexture 项目中的 *GlobGLTexture.cpp* 文件中,该文件通过菜单 *PROJECT->Add Existing Item...* 命令插入。

纹理映射过程

 GLuint  LoadImgTexture(LPCTSTR fName)      //Load texture from Image file
{
	CImage img;
	HRESULT hResult = img.Load(fName);  //Standart procedure of CImage loading
	if (FAILED(hResult)) {
		CString fmt;
		fmt.Format(_T("Error %d\n%s"), hResult, _com_error(hResult).ErrorMessage());
		MessageBox(NULL, fmt + _T("\nin file:\n") + (CString)fName, _T("Error:"), MB_OK | MB_ICONERROR);
		return FALSE;
	}//if(FAILED(hResult))

	CBitmap * pBm = NULL;
	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
		pBm = GetImgBitmap(&tmg);                        //Get the class CBitmap from CImage class
	}
	else
		pBm = GetImgBitmap(&img);                        //Get the class CBitmap from CImage class

	BITMAP BMP;
	pBm->GetBitmap(&BMP);           //Standard procedure of BITMAP structure derived from CBitmap class
	return  LoadGLTexture(&BMP);	//Load Texture from BITMAP structure
   
}

图像来自使用标准CImage 过程加载的图像文件。期望图像的默认格式为每像素 24 位。如果图像的格式与默认格式不同,则创建 24 位每像素环境,并将原始图像复制到新环境中。

并且 CBitmap 类基于 CImage 类绘制

    CBitmap * GetImgBitmap(CImage * pImg)      //Get the class CBitmap from CImage class
{
	if (pImg == NULL)
		return NULL;

	CDC * pDC = new CDC;
	if (!pDC->CreateCompatibleDC(CDC::FromHandle(pImg->GetDC())))
		return NULL;
	CBitmap * pBm = new CBitmap;
	pBm->CreateCompatibleBitmap(CDC::FromHandle(pImg->GetDC()), pImg->GetWidth(), pImg->GetHeight());

	CBitmap * pBmOld = pDC->SelectObject(pBm);
	pImg->BitBlt(pDC->m_hDC, CPoint(0, 0));
	pDC->DeleteDC();

	return pBm;
}

BITMAP 结构基于 CBitmap 类绘制,并使用标准 OpenGL 过程 且格式为 GL_BGR_EXT(对应于 BITMAP 结构 中的每像素 24 位格式)实现到纹理中

GLuint LoadGLTexture(BITMAP * pBm)     //Load Texture from BITMAP structure
{
	GLuint texi;						//Name of the new texture
glGenTextures(1, &texi);					//Name of the new texture generation
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
	glBindTexture(GL_TEXTURE_2D, texi);			//Connection to texture mapping

	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pBm->bmWidth, pBm->bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pBm->bmBits);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	return texi;                                //the name assigned to the texture created
}

在原始项目中,只有 CImgTextureView 类有一些更改

插入了三个变量

int m_texNum;             //Current order number of the name of the texture 
CWordArray m_globTexture; //Array of the textures' names available	
int m_view_type;          //View performance:VIEW_DEFAULT or VIEW_TEXTURE
enum VIEW_TYPE
{
	VIEW_DEFAULT,           //Original Cube Sample View
	VIEW_TEXTURE,           //Texture 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.bmp"))); //you may insert here any image files in any pathway valid
	m_globTexture.Add((WORD)LoadImgTexture(_T("Data/famrt.bmp")));//and as much as you like 
	return 0;
} ;

您可以在此处插入任何有效的路径中的任何图像文件,并且可以随意插入;在原始的 CImgTextureView::DrawScene 过程中,插入了纹理处理块

	case VIEW_TEXTURE:

			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, (GLuint)m_globTexture.GetAt(m_texNum));

			glBegin(GL_QUADS);

			glColor3f(1.0f, 1.0f, 1.0f);
			// Front Face
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
			glTexCoord2f(2.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
			glTexCoord2f(2.0f, 2.0f); glVertex3f(1.0f, 1.0f, 1.0f);
			glTexCoord2f(0.0f, 2.0f); glVertex3f(-1.0f, 1.0f, 1.0f);

		
			// Back Face
			glTexCoord2f(2.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
			glTexCoord2f(2.0f, 2.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
			glTexCoord2f(0.0f, 2.0f); glVertex3f(1.0f, 1.0f, -1.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f);
			// Top Face
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
			// Bottom Face
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
			// Right face
			glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
			// Left Face
			glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
			glEnd();

			glDisable(GL_TEXTURE_2D);
			break;

所有后续的 *菜单* 和 *加速器* 命令均已使用标准 AppWizard 技术完成。

应用程序演示菜单和键盘命令

为了演示 ImgTexture 项目的实现,排列了一些 *菜单* 和一些特殊的 *加速器* 键

  • 菜单 文件->打开 - 选择带有用于纹理映射的图像的文件;
  • 菜单 查看->默认 - 原始的 Cube 表现;
  • 菜单 查看->纹理 - 当前纹理表现;
  • 菜单 查看->下一个纹理 - 下一个纹理表现(也单击 右箭头);
  • 菜单 查看->上一个纹理 - 上一个纹理表现(也单击 左箭头);

关注点

上面提供的技术试图演示一种简单的纹理实现可能性。该项目已在 MFC 平台中开发。然而,GlobGLTexture.cpp 过程在 Win32 中也有效,并且可用于 移动 应用程序。

© . All rights reserved.