[OpenGL] 简单二维粒子系统——烟花,喷水,落叶

参考代码:http://download.csdn.net/detail/blue6333589/6785389

在这个代码的基础上扩展了二维粒子系统的框架,该系统由一个发射器类和一个粒子类组成,作为编程练习而言,我们只实现了最基本的粒子系统功能,但是已经可以做出一些效果了。
在这里,通过调节参数给出了在这个框架下烟花、喷水、落叶的代码,参考代码实现的是飘雪;只要在物理参数模拟和贴图选择上做得足够好,也可以实现火焰、爆炸等效果。


发射器 其中发射器类支持从点发射和从直线发射,暂时不支持曲线(编程实现困难)以及平面(二维不便于平面发射)的发射器,发射位置分布是随机而均匀的。
同时,我们还可以指定发射速率(单位时间内发射的粒子数目),来控制粒子产生的快慢。


粒子

粒子包含位置、速度、加速度、颜色、贴图、角度、大小、生命等属性。这些都是通过编写init函数完成的,这个init函数是使用库的人自行编写,传入发射器类作为函数指针调用,在这个函数中设置粒子的属性,只要稍作改动,还能实现同一个发射器发射多种形状粒子的效果。

运行流程


初始化发射器
初始化粒子参数
发射粒子
粒子死亡,重新生成该粒子


particle.h

#pragma once #define GLUT_DISABLE_ATEXIT_HACK #include class particle { bool is_forever; //永生 bool has_tex; //纹理或颜色 float x, y; //位置 float size_x; //大小 float size_y; unsigned int texture; //纹理 float speed_x; //速度 float speed_y; float acc_x; //加速度 float acc_y; float life; //生命 float angle; //角度 unsigned char color[3]; //颜色 friend class emitter; void draw(GLuint texture); //绘制粒子(纹理) void draw(); //绘制粒子(颜色) void show(); public: particle(); particle(float _size_x, float _size_y, float _speed_x, float _speed_y, float _acc_x, float _acc_y, float _life, float _angle, unsigned int _texture, bool _is_forever); particle(float _size_x, float _size_y, float _speed_x, float _speed_y, float _acc_x, float _acc_y, float _life, float _angle, unsigned char* _color, bool _is_forever); }; class emitter { float x1, y1, x2, y2; //发射器位置 int speed; //发射速率 particle **p; //发射粒子 particle* (*f)(); //初始化粒子的函数指针 public: void emit(particle* (init)()); void update(); emitter(int _speed, float _x1, float _x2, float _y1, float _y2); };


particle.cpp

#include #include"particle.h"void particle::draw(GLuint texture) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); //选择纹理texture[status] const GLfloat x1 = -0.5, x2 = 0.5; const GLfloat y1 = -0.5, y2 = 0.5; const GLfloat point[4][2] = { { x1,y1 },{ x2,y1 },{ x2,y2 },{ x1,y2 } }; int dir[4][2] = { { 0,0 },{ 1,0 },{ 1,1 },{ 0,1 } }; glBegin(GL_QUADS); for (int i = 0; i < 4; i++) { glTexCoord2iv(dir[i]); glVertex2fv(point[i]); } glEnd(); glDisable(GL_TEXTURE_2D); }void particle::draw() { const GLfloat x1 = -0.5, x2 = 0.5; const GLfloat y1 = -0.5, y2 = 0.5; const GLfloat point[4][2] = { { x1,y1 },{ x2,y1 },{ x2,y2 },{ x1,y2 } }; glBegin(GL_QUADS); for (int i = 0; i < 4; i++) { glVertex2fv(point[i]); } glEnd(); }void particle::show() { if (life > 0 || is_forever) { if (has_tex) { glDepthMask(GL_FALSE); glPushMatrix(); glTranslatef(x, y, 0); glRotatef(angle, 0, 0, 1); glScalef(size_x, size_y, 0); draw(texture); glPopMatrix(); y += speed_y; x += speed_x; speed_y += acc_y; speed_x += acc_x; if (!is_forever)life -= 0.2f; glDepthMask(GL_TRUE); } else { glPushMatrix(); glColor3f(color[0], color[1], color[2]); glTranslatef(x, y, 0); glRotatef(angle, 0, 0, 1); glScalef(size_x, size_y, 0); draw(); glPopMatrix(); y += speed_y; x += speed_x; speed_y += acc_y; speed_x += acc_x; if (!is_forever)life -= 0.2f; glColor3f(0, 0, 0); } } } particle::particle() {} particle::particle(float _size_x, float _size_y, float _speed_x, float _speed_y, float _acc_x, float _acc_y, float _life, float _angle, unsigned int _texture, bool _is_forever) { size_x = _size_x; size_y = _size_y; speed_x = _speed_x; speed_y = _speed_y; acc_x = _acc_x; acc_y = _acc_y; life = _life; texture = _texture; angle = _angle; has_tex = true; is_forever = _is_forever; } particle::particle(float _size_x, float _size_y, float _speed_x, float _speed_y, float _acc_x, float _acc_y, float _life, float _angle, unsigned char* _color, bool _is_forever) { size_x = _size_x; size_y = _size_y; speed_x = _speed_x; speed_y = _speed_y; acc_x = _acc_x; acc_y = _acc_y; life = _life; if (_is_forever)_life = 1; color[0] = *_color; color[1] = *(_color + 1); color[2] = *(_color + 2); angle = _angle; has_tex = false; is_forever = _is_forever; }void emitter::emit(particle* (init)()) { for (int i = 0; i < speed; i++) { f = init; p[i] = init(); int place = rand() % speed; p[i]->x = 1.0f*place / speed*(x2 - x1) + x1; p[i]->y = 1.0f*place / speed*(y2 - y1) + y1; } }void emitter::update() { for (int i = 0; i < speed; i++) { p[i]->show(); if (p[i]->life < 0) { delete p[i]; p[i] = f(); int place = rand() % speed; p[i]->x = 1.0f*place / speed*(x2 - x1) + x1; p[i]->y = 1.0f*place / speed*(y2 - y1) + y1; } } }emitter::emitter(int _speed, float _x1, float _x2, float _y1, float _y2) { speed = _speed; x1 = _x1; x2 = _x2; y1 = _y1; y2 = _y2; p = new particle*[speed]; }




我们通过修改main.cpp,在这个粒子系统框架下,可以实现不同的效果:

落叶:


[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
文章图片


main.cpp

#define _CRT_SECURE_NO_WARNINGS#include #include #include"particle.h" #include"texture.h" emitter *e1; GLuint texture[1]; //视区 float whRatio; int wHeight = 0; int wWidth = 0; //视点 float center[] = { 0, 0, 0 }; float eye[] = { 0, 0, 5 }; particle* init_particle() { float size = rand() % 100 * 0.02f; unsigned char color[] = { 1.0f,0.0f,0.0f }; particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 40, 1.0 / 10000, -4.9 / 40000, rand() % 200, rand() % 360,texture[0],false); return p; }void drawScene() { e1->update(); }void updateView(int height, int width) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); //设置矩阵模式为投影 glLoadIdentity(); //初始化矩阵为单位矩阵 whRatio = (GLfloat)width / (GLfloat)height; //设置显示比例 glOrtho(-30, 30, -30, 30, -100, 100); //正投影 glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型 }void reshape(int width, int height) { if (height == 0){ //如果高度为0 height = 1; //让高度为1(避免出现分母为0的现象) } wHeight = height; wWidth = width; updateView(wHeight, wWidth); //更新视角 }void idle() { glutPostRedisplay(); }void init(void) { srand(unsigned(time(nullptr))); glClearColor(1.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glColor4f(1.0, 1.0, 1.0, 1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glEnable(GL_BLEND); BuildTexture("11.jpg", texture[0]); e1 = new emitter(500, -30,30, 30, 30); e1->emit(init_particle); }void redraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色和深度缓存 glClearColor(0, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //初始化矩阵为单位矩阵 gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0); drawScene(); //绘制场景 glutSwapBuffers(); //交换缓冲区 }int main(int argc, char *argv[]) { glutInit(&argc, argv); //对glut的初始化 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //初始化显示模式:RGB颜色模型,深度测试,双缓冲 glutInitWindowSize(800, 600); //设置窗口大小 int windowHandle = glutCreateWindow("Simple GLUT App"); //设置窗口标题 glutDisplayFunc(redraw); //注册绘制回调函数 glutReshapeFunc(reshape); //注册重绘回调函数 glutIdleFunc(idle); //注册全局回调函数:空闲时调用 init(); glutMainLoop(); // glut事件处理循环 return 0; }


[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
文章图片

11.jpg


烟花:


[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
文章图片


main.cpp


#define _CRT_SECURE_NO_WARNINGS#include #include #include"particle.h" #include"texture.h" emitter *e1; emitter *e2; emitter *e3; //视区 float whRatio; int wHeight = 0; int wWidth = 0; //视点 float center[] = { 0, 0, 0 }; float eye[] = { 0, 0, 5 }; particle* init_particle1() { float size = rand() % 15 * 0.02f; unsigned char color[] = { 1.0f,0.0f,0.0f }; particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80, 0, -4.9 / 40000, rand() % 80, 0, color, false); return p; }particle* init_particle2() { float size = rand() % 15 * 0.02f; unsigned char color[] = { 0.0f,1.0f,0.0f }; particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80, 0, -4.9 / 40000, rand() % 50, 0, color, false); return p; } particle* init_particle3() { float size = rand() % 15 * 0.02f; unsigned char color[] = { 0.0f,0.0f,1.0f }; particle* p = new particle(size, size, float(rand() % 10 - 4) / 80, float(rand() % 10 - 4) / 80, 0, -4.9 / 40000, rand() % 40, 0, color,false); return p; }void drawScene() { e1->update(); e2->update(); e3->update(); }void updateView(int height, int width) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); //设置矩阵模式为投影 glLoadIdentity(); //初始化矩阵为单位矩阵 whRatio = (GLfloat)width / (GLfloat)height; //设置显示比例 glOrtho(-30, 30, -30, 30, -100, 100); //正投影 glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型 }void reshape(int width, int height) { if (height == 0){ //如果高度为0 height = 1; //让高度为1(避免出现分母为0的现象) } wHeight = height; wWidth = width; updateView(wHeight, wWidth); //更新视角 }void idle() { glutPostRedisplay(); }void init(void) { srand(unsigned(time(nullptr))); glClearColor(1.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glColor4f(1.0, 1.0, 1.0, 1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glEnable(GL_BLEND); e1 = new emitter(1000, 0, 0, 0, 0); e1->emit(init_particle1); e2 = new emitter(1000, 10, 10, 10, 10); e2->emit(init_particle2); e3 = new emitter(1000, -20, -20, 13, 13); e3->emit(init_particle3); }void redraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色和深度缓存 glClearColor(0, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //初始化矩阵为单位矩阵 gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0); drawScene(); //绘制场景 glutSwapBuffers(); //交换缓冲区 }int main(int argc, char *argv[]) { glutInit(&argc, argv); //对glut的初始化 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //初始化显示模式:RGB颜色模型,深度测试,双缓冲 glutInitWindowSize(800, 600); //设置窗口大小 int windowHandle = glutCreateWindow("Simple GLUT App"); //设置窗口标题 glutDisplayFunc(redraw); //注册绘制回调函数 glutReshapeFunc(reshape); //注册重绘回调函数 glutIdleFunc(idle); //注册全局回调函数:空闲时调用 init(); glutMainLoop(); // glut事件处理循环 return 0; }

喷水:
[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
文章图片

main.cpp

#define _CRT_SECURE_NO_WARNINGS#include #include #include"particle.h" #include"texture.h" emitter *e1; GLuint texture[1]; //视区 float whRatio; int wHeight = 0; int wWidth = 0; //视点 float center[] = { 0, 0, 0 }; float eye[] = { 0, 0, 5 }; particle* init_particle() { static int count = 0; float size = rand() % 50 * 0.02f; particle* p; p = new particle(size, size, float(rand() % 10-4) / 50, float(rand() % 100) / 200+0.5, 0, -4.9 / 1000, rand() % 60, 0, texture[0],false); return p; } void drawScene() { e1->update(); }void updateView(int height, int width) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); //设置矩阵模式为投影 glLoadIdentity(); //初始化矩阵为单位矩阵 whRatio = (GLfloat)width / (GLfloat)height; //设置显示比例 glOrtho(-30, 30, -30, 30, -100, 100); //正投影 glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型 }void reshape(int width, int height) { if (height == 0){ //如果高度为0 height = 1; //让高度为1(避免出现分母为0的现象) } wHeight = height; wWidth = width; updateView(wHeight, wWidth); //更新视角 }void idle() { glutPostRedisplay(); }void init(void) { srand(unsigned(time(nullptr))); glClearColor(1.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glColor4f(1.0, 1.0, 1.0, 1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glEnable(GL_BLEND); BuildTexture("12.jpg", texture[0]); e1 = new emitter(5000, 0,0, -30, -30); e1->emit(init_particle); }void redraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色和深度缓存 glClearColor(0, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //初始化矩阵为单位矩阵 gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], 0, 1, 0); drawScene(); //绘制场景 glutSwapBuffers(); //交换缓冲区 }int main(int argc, char *argv[]) { glutInit(&argc, argv); //对glut的初始化 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //初始化显示模式:RGB颜色模型,深度测试,双缓冲 glutInitWindowSize(800, 600); //设置窗口大小 int windowHandle = glutCreateWindow("Simple GLUT App"); //设置窗口标题 glutDisplayFunc(redraw); //注册绘制回调函数 glutReshapeFunc(reshape); //注册重绘回调函数 glutIdleFunc(idle); //注册全局回调函数:空闲时调用 init(); glutMainLoop(); // glut事件处理循环 return 0; }


[OpenGL] 简单二维粒子系统——烟花,喷水,落叶
文章图片

12.jpg

______________________________________________________________________________________________________________________________________
【[OpenGL] 简单二维粒子系统——烟花,喷水,落叶】以下纹理代码来自参考代码(可加载jpg图片),非原创,在这里给出以保证代码完整性:
texture.h

#pragma once #include // OpenGL32库的头文件 #include struct TextureTga// 建立一个结构体 { GLubyte *imageData; // 图像数据 (最高32bit) GLuint bpp; // 每一象素的图像颜色深度 GLuint width; // 图像宽度 GLuint height; // 图像高度 GLuint texID; // 纹理ID }; // 载入BMP,JPG,GIF等文件 bool BuildTexture(char *szPathName, GLuint &texid); // 载入TGA文件 bool BuildTexture(char *filename, TextureTga *texture);


texture.cpp

#define _CRT_SECURE_NO_WARNINGS #include// 标准输入输出头文件 #include // OLE控制库头文件 #include // 数学函数头文件#include "texture.h"bool BuildTexture(char *szPathName, GLuint &texid)// 载入图片并转换为纹理 { HDChdcTemp; // DC用来保存位图 HBITMAPhbmpTemp; // 保存临时位图 IPicture *pPicture; // 定义IPicture Interface OLECHARwszPath[MAX_PATH + 1]; // 图片的完全路径 charszPath[MAX_PATH + 1]; // 图片的完全路径 longlWidth; // 图像宽度 longlHeight; // 图像高度 longlWidthPixels; // 图像的宽带(以像素为单位) longlHeightPixels; // 图像的高带(以像素为单位) GLintglMaxTexDim; // 保存纹理的最大尺寸 if (strstr(szPathName, "http://"))// 如果路径包含 http:// 则... { strcpy(szPath, szPathName); // 把路径拷贝到 szPath } else// 否则从文件导入图片 { GetCurrentDirectory(MAX_PATH, szPath); // 取得当前路径 strcat(szPath, "\\"); // 添加字符"\" strcat(szPath, szPathName); // 添加图片的相对路径 } MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); // 把ASCII码转化为Unicode标准码 HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture); if (FAILED(hr))// 如果导入失败 { // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } hdcTemp = CreateCompatibleDC(GetDC(0)); // 建立窗口设备描述表 if (!hdcTemp)// 建立失败? { pPicture->Release(); // 释放IPicture // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim); // 取得支持的纹理最大尺寸 pPicture->get_Width(&lWidth); // 取得IPicture 宽度 (转换为Pixels格式) lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540); pPicture->get_Height(&lHeight); // 取得IPicture 高度 (转换为Pixels格式) lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540); // 调整图片到最好的效果 if (lWidthPixels <= glMaxTexDim)// 图片宽度是否超过显卡最大支持尺寸 lWidthPixels = 1 << (int)floor((log((double)lWidthPixels) / log(2.0f)) + 0.5f); else// 否则,将图片宽度设为显卡最大支持尺寸 lWidthPixels = glMaxTexDim; if (lHeightPixels <= glMaxTexDim)// 图片高度是否超过显卡最大支持尺寸 lHeightPixels = 1 << (int)floor((log((double)lHeightPixels) / log(2.0f)) + 0.5f); else// 否则,将图片高度设为显卡最大支持尺寸 lHeightPixels = glMaxTexDim; // 建立一个临时位图 BITMAPINFO bi = { 0 }; // 位图的类型 DWORD*pBits = 0; // 指向位图Bits的指针 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 设置结构大小 bi.bmiHeader.biBitCount = 32; // 32 位 bi.bmiHeader.biWidth = lWidthPixels; // 宽度像素值 bi.bmiHeader.biHeight = lHeightPixels; // 高度像素值 bi.bmiHeader.biCompression = BI_RGB; // RGB 格式 bi.bmiHeader.biPlanes = 1; // 一个位平面// 建立一个位图这样我们可以指定颜色和深度 并访问每位的值 hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0); if (!hbmpTemp)// 建立失败? { DeleteDC(hdcTemp); // 删除设备描述表 pPicture->Release(); // 释放IPicture // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } SelectObject(hdcTemp, hbmpTemp); // 选择临时DC句柄和临时位图对象// 在位图上绘制IPicture pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0); // 将BGR转换为RGB 将ALPHA值设为255 for (long i = 0; i < lWidthPixels * lHeightPixels; i++)// 循环遍历所有的像素 { BYTE* pPixel = (BYTE*)(&pBits[i]); // 获取当前像素 BYTEtemp = pPixel[0]; // 临时存储第一个颜色像素(蓝色) pPixel[0] = pPixel[2]; // 将红色值存到第一位 pPixel[2] = temp; // 将蓝色值存到第三位 pPixel[3] = 255; // ALPHA值设为255 } glGenTextures(1, &texid); // 创建纹理// 使用来自位图数据生成 的典型纹理 glBindTexture(GL_TEXTURE_2D, texid); // 绑定纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 线形滤波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 线形滤波// 生成纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits); DeleteObject(hbmpTemp); // 删除对象 DeleteDC(hdcTemp); // 删除设备描述表 pPicture->Release(); // 释放 IPicture return true; // 返回 TRUE }bool BuildTexture(char *filename, TextureTga *texture)// 载入一个.TGA 文件到内存 { GLubyteTGAheader[12] = { 0,0,2,0,0,0,0,0,0,0,0,0 }; // 没有压缩的TGA Header GLubyteTGAcompare[12]; // 用来比较 TGA Header GLubyteheader[6]; // Header里,头六个有用字节 GLuintbytesPerPixel; // 保存TGA文件里每个像素用到的字节数 GLuintimageSize; // 用来保存随机产生的图像的大小 GLuinttemp; // 临时变量 GLuinttype = GL_RGBA; // 将默认的GL模式设置为RBGA (32 BPP) FILE *file = fopen(filename, "rb"); // 打开 TGA 文件 if (file == NULL)// 文件是否已存在? { // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回FALSE } if (fread(TGAcompare, 1, sizeof(TGAcompare), file) != sizeof(TGAcompare)// 是否有十二个字节可读? || memcmp(TGAheader, TGAcompare, sizeof(TGAheader)) != 0// header和我们想要的是否相符? || fread(header, 1, sizeof(header), file) != sizeof(header))// 如果是读下六个字节 { fclose(file); // 如果失败,关闭文件 // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回FALSE } texture->width = header[1] * 256 + header[0]; // 确定的TGA 宽度 (高字节*256+低字节) texture->height = header[3] * 256 + header[2]; // 确定的TGA 高度 (高字节*256+低字节) if (texture->width <= 0// 宽度是否小于等于0 || texture->height <= 0// 高度是否小于等于0 || (header[4] != 24 && header[4] != 32))// TGA 是24位或32位? { fclose(file); // 任何一个不成立, 则关闭文件 // 图片载入失败出错信息 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回FALSE } texture->bpp = header[4]; // 获取TGA每个像素的位(24 or 32) bytesPerPixel = texture->bpp / 8; // 除以8以取得 每个像素的字节 imageSize = texture->width*texture->height*bytesPerPixel; // 计算TAG数据所需要的内存 texture->imageData = https://www.it610.com/article/(GLubyte *)malloc(imageSize); // 开辟一个内存空间用来存储TGA数据 if (texture->imageData =https://www.it610.com/article/= NULL// 用来存储的内存是否存在? || fread(texture->imageData, 1, imageSize, file) != imageSize) // 图像大小是否和内存空间大小相符? { if (texture->imageData != NULL)// 图像数据是否载入 { free(texture->imageData); // 如果是 释放图像数据 } fclose(file); // 关闭文件 MessageBox(HWND_DESKTOP, "图片导入失败!\n(TextureLoad Failed!)", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回FALSE } for (GLuint i = 0; iimageData[i]; // 将图像数据‘i’的值存在临时变量中 texture->imageData[i] = texture->imageData[i + 2]; // 将第三个字节的值存到第一个字节里 texture->imageData[i + 2] = temp; // 将临时变量的值存入第三字节(第一字节的值) } fclose(file); // 关闭文件//创建一种纹理 glGenTextures(1, &texture->texID); // 产生OpenGL纹理ID glBindTexture(GL_TEXTURE_2D, texture->texID); // 绑定纹理 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 线性滤波 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 线性滤波 if (texture->bpp == 24)// TGA图片是不是 24 位的 { type = GL_RGB; // 如果是将'type'设置为 GL_RGB } glTexImage2D(GL_TEXTURE_2D, 0, type, texture->width, texture->height, 0, type, GL_UNSIGNED_BYTE, texture->imageData); return true; // 纹理创建成功,返回正确 }






    推荐阅读