使用 CImage 类进行 OpenGL 纹理映射





5.00/5 (6投票s)
使用 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 中也有效,并且可用于 移动 应用程序。