龙云尧个人博客,转载请注明出处。
CSDN地址:http://blog.csdn.net/michael753951/article/details/71316132
个人blog地址:http://yaoyl.cn/nehexue-xi-bi-ji-wu/
这次我们将尝试Lesson6和Lesson7的内容。这个部分我们将学习怎么给一个模型进行纹理映射(其实就是贴图)。
环境搭建
这次实验因为需要使用OpenGL的glaux.h库头使用位图对构建的图形进行纹理映射。所以我们需要进一步进行环境搭建。(注:环境搭建很麻烦,因为微软的VS环境很乱)
如何布置这个库头可以参考【 VS2008无法打开gl/glaux.h头文件的解决方法】我使用的是方法4,测试能够正确include库头。
在高版本的VS中,因为VS使用的是自己重新修改过的C++,所以在进行编译的过程中,可能会出现ERROR LNK2019报错,无法解析“_sscanf,_sscanf_s”,这个时候我们可以参考【 VS2015 无法解析的外部符号 __vsnwprintf_s】
如果我们在使用AUX_RGBImageRec定义变量的时候,系统没有报错的话,就说明我们本次基本的环境已经搭建好了。
另外,因为我们在实验中需要使用fopen,而微软的VS2015中会强行报错,为了避免不必要的麻烦,我们需要关掉fopen的报错。这个部分我们可以参考【百度经验:VS2013中如何解决error C4996: ‘fopen’问题】
开始实现
如果没出什么问题的话,到这里我们应该能够正常的编写这一刻的代码了。(如果还有什么报错请尝试自行解决或者戳我)。
本次需要在3维图像上添加纹理映射,首先需要的是读取位图像文件。读取的代码如下。
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL
}
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(1, &texture[0]); // Create The Texture
// Typical Texture Generation Using Data From The Bitmap
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
if (TextureImage[0]) // If Texture Exists
{
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status
}
第一个函数LoadBMP不需要解释,主要功能就是探寻目的位置中是否存在该图像文件。如果存在就调用auxDIBImageLoad将位图加载成渲染文件返回出来。
第二个函数LoadGLTextures要稍微注意一下,在本次实验中是很重要的一个功能函数。
函数中定义了一个LoadGLTextures数组用来存放位图的句柄,这里因为我们只读取了一张位图,所以只开了一个大小的数组。
接着调用LoadBMP将位图转换成为纹理渲染文件存进TextureImage, glGenTextures(1, &texture[0]) 告诉OpenGL我们想生成一个纹理名字,glBindTexture将纹理名字 texture[0] 绑定到纹理目标上。
然后我们调用glTexImage2D进行纹理的创建。然后使用glTexParameteri对图像进行放大和缩小的滤波器进行设置。
最后再纹理穿件完成之后,我们需要释放掉纹理渲染数组中的内容。
整个纹理渲染工作到这里也就结束了。我们对InitGL稍作修改,使用LoadGLTextures检验位图是否存在,然后调用glEnable启用映射
int InitGL(GLvoid) // 此处开始对OpenGL进行所有设置
{
if (!LoadGLTextures()) // 调用纹理载入子例程
{
return FALSE; // 如果未能载入,返回FALSE
}
glEnable(GL_TEXTURE_2D); // 启用纹理映射
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
glClearDepth(1.0f); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正
return TRUE; // 初始化 OK
}
最后我们按照惯例,修改DrawGLScene方法,需要注意的是,在将纹理贴上模型的时候,需要调用glTexCoord2f方法,第一个参数是X坐标,0.0是纹理的左侧,0.5是纹理的中点,1.0是纹理的右侧。第二个参数是Y坐标,0.0是纹理的底部,0.5是纹理的中点,1.0是纹理的顶部。将4个点全部绑定在张芳行上面之后,便能够正常的显示了。需要注意的是,在glTexCoord2f方法中,参考系是以图像的右下角作为原点,左边为X轴正方向,上方为Y轴正方向(和绘图中的直角坐标系的设定相似)。
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(xrot,1.0f,0.0f