OpenGL_10 3D空间中移动图像

来源:互联网 发布:顺丰科技数据分析 编辑:程序博客网 时间:2024/05/22 13:36

在本节中,并没有新的知识,只是通过glTranslatef()和glRotatef()函数对星星纹理映射的矩形的位置变换以及glColor4ub()函数对星星颜色改变达到混合效果实现星星自转、绕z轴旋转和闪烁的效果,可以说是对之前知识的回顾。

NEHEOpenGL例程的代码注释率达到90%以上,而51CTO翻译版的NEHE教程注释较少,上午又下载了NEHE例程源码,并将其英文注释全部翻译了一遍,算是对知识的一次巩固。

NeHe原版例程下载地址OpenGL教程Nehe版下载地址


#include "OpenGLSB.h"#include <stdio.h>#include <stdlib.h>         #include "glaux.h"HDChDC = NULL;// 私有GDI设备环境HGLRChRC = NULL;// 永久透视环境HWNDhWnd = NULL;// 保持窗口句柄HINSTANCEhInstance;// 保持应用实例boolkeys[256];// 键盘活动存储数组boolactive = TRUE;// 窗口有效标志默认设置为TRUEboolfullscreen = TRUE;// 全屏标志默认设置为全屏booltwinkle;// 闪烁的星星booltp;// ‘T’键按下?const intnum = 50;//要画的星星的个数typedef struct// 创建一个星星的结构体{int r, g, b;// 星星的颜色GLfloat dist,// 星星距离中心的距离angle;    // 星星当前角度}stars;stars star[num];// 需要保持对'num'个星星的追踪GLfloatzoom = -15.0f;// 星星远离的距离GLfloat tilt = 90.0f;// 视角倾斜GLfloatspin;// 旋转星星GLuintloop;// 通用循环变量GLuinttexture[1];// 用于存储一个纹理LRESULTCALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);// WndProc函数声明AUX_RGBImageRec *LoadBMP(char *Filename)                // 载入一个位图图像{FILE *File = NULL;                                //文件句柄if (!Filename)                                  // 确保文件名给出{return NULL;                            // 如果不返回NULL}File = fopen(Filename, "r");                    // 检查文件是否存在if (File)                                       //文件存在否? {fclose(File);                           // 关闭句柄return auxDIBImageLoad(Filename);       // 加载位图并返回一个指针}return NULL;                                    // 如果加载失败则返回NULL}int LoadGLTextures()                                    //加载位图并转换成纹理{int Status = FALSE;                               //状态指示器AUX_RGBImageRec *TextureImage[1];               // 创建一个纹理存储空间memset(TextureImage, 0, sizeof(void *) * 1);        // 将指针指向NULL// 加载位图,检查错误,如果文图不存在则退出if (TextureImage[0] = LoadBMP("Data/Star.bmp")){Status = TRUE;                            // 将状态设置未TRUEglGenTextures(1, &texture[0]);          // 创建一个纹理// 创建线性滤波纹理glBindTexture(GL_TEXTURE_2D, texture[0]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);}if (TextureImage[0])                            // 如果纹理存在{if (TextureImage[0]->data)              // 如果纹理图像存在{free(TextureImage[0]->data);    // 释放纹理图像内存}free(TextureImage[0]);                  // 释放图像结构体}return Status;                                  // 返回状态}GLvoid ReSizeGLScene(GLsizei width, GLsizei height)// 调整GL窗口并初始化{if (height == 0)// 避免A被0除{height = 1;// 让高度等于1}glViewport(0, 0, width, height);// 重置当前视角glMatrixMode(GL_PROJECTION);// 选择投射矩阵glLoadIdentity();// 重置投射矩阵// 计算窗口方向比gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);glMatrixMode(GL_MODELVIEW);// 选择模型视图矩阵glLoadIdentity();// 重置模型视图矩阵}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);// 深度缓存启动glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// 真实的nice级的场景计算glBlendFunc(GL_SRC_ALPHA, GL_ONE);// 设置半透明混合函数glEnable(GL_BLEND);for (loop = 0; loop<num; loop++){star[loop].angle = 0.0f;star[loop].dist = (float(loop) / num)*5.0f;star[loop].r = rand() % 256;star[loop].g = rand() % 256;star[loop].b = rand() % 256;}return TRUE;// 初始化OKint DrawGLScene(GLvoid)// 这儿是我们所做的所有的绘制{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度缓存glBindTexture(GL_TEXTURE_2D, texture[0]);// 选择我们的纹理for (loop = 0; loop<num; loop++)// 循环所有的星星{glLoadIdentity();// 我们画每个星星前重置模型观察矩阵glTranslatef(0.0f, 0.0f, zoom);// 深入屏幕(使用zoom里的数值)glRotatef(tilt, 1.0f, 0.0f, 0.0f);//倾斜视角(使用tilt里的数值)glRotatef(star[loop].angle, 0.0f, 1.0f, 0.0f);// 旋转至当前星星的角度glTranslatef(star[loop].dist, 0.0f, 0.0f);// 在x平面前移(注:在观察者视角应是向右移动)glRotatef(-star[loop].angle, 0.0f, 1.0f, 0.0f);// 取消当前星星角度glRotatef(-tilt, 1.0f, 0.0f, 0.0f);// 取消屏幕倾斜if (twinkle)//启用闪烁效果{//第一遍绘制静止的星星glColor4ub(star[(num - loop) - 1].r, star[(num - loop) - 1].g, star[(num - loop) - 1].b, 255);glBegin(GL_QUADS);//开始绘制纹理映射的四边形glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 0.0f);glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 0.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);glEnd();}//第二遍绘制绕z轴旋转的星星glRotatef(spin, 0.0f, 0.0f, 1.0f);glColor4ub(star[loop].r, star[loop].g, star[loop].b, 255);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 0.0f);glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 0.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);glEnd();spin += 0.01f;star[loop].angle += float(loop) / num;star[loop].dist -= 0.01f;if (star[loop].dist<0.0f)//星星到达中心{star[loop].dist += 5.0f;star[loop].r = rand() % 256;star[loop].g = rand() % 256;star[loop].b = rand() % 256;}}return TRUE;//一切OK}GLvoid KillGLWindow(GLvoid)//恰当地消除窗口{if (fullscreen)//我们在全屏模式吗{ChangeDisplaySettings(NULL, 0);// 如果是,我们切换回桌面ShowCursor(TRUE);// 显示鼠标指针}if (hRC)//我们拥有一个渲染描述表吗{if (!wglMakeCurrent(NULL, NULL))// 我们能释放DC(设备描述表)或RC(渲染描述表)吗{MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);//消息盒显示错误}if (!wglDeleteContext(hRC))// 我们能删除渲染描述表吗{MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);}hRC = NULL;// 将hRC设置为空}if (hDC && !ReleaseDC(hWnd, hDC))// 我们能释放设备描述表吗{MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);hDC = NULL;// 将DC设置为空}if (hWnd && !DestroyWindow(hWnd))// 我们能清除窗口吗{MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);hWnd = NULL;// 将窗口句柄设置为空}if (!UnregisterClass("OpenGL", hInstance))// 我们能注销类吗{MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);hInstance = NULL;// 将实例句柄设置为空}}/*This Code Creates Our OpenGL Window.  Parameters Are:**title- Title To Appear At The Top Of The Window**width- Width Of The GL Window Or Fullscreen Mode**height- Height Of The GL Window Or Fullscreen Mode**bits- Number Of Bits To Use For Color (8/16/24/32)**fullscreenflag- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)*//*这段代码创建我们地OpenGL窗口,参数为:**title-标题出现在窗口地最顶端**width-GL窗口或全屏模式的宽度**height-GL窗口或全屏模式的高度**bits-用于表示颜色的位数(8/16/24/32)**fullscreenflag-使用全屏模式(TRUE)或窗口模式(FLASE)**/BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag){GLuintPixelFormat;// 搜索到匹配项后保持结果WNDCLASSwc;// Windows类结构DWORDdwExStyle;// 窗口拓展类型DWORDdwStyle;// 窗口类型RECTWindowRect;// 取得矩形左上/右下值WindowRect.left = (long)0;// 左值设为0WindowRect.right = (long)width;// 右值设置为要求的宽度WindowRect.top = (long)0;// 上值设置为0WindowRect.bottom = (long)height;// 下值设置为要求的高度fullscreen = fullscreenflag;//设置全局全屏标志hInstance = GetModuleHandle(NULL);//取得我们窗口的一个实例wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// 重绘尺寸和窗口自己的设备描述表wc.lpfnWndProc = (WNDPROC)WndProc;// WndProc句柄消息wc.cbClsExtra = 0;// 无额外的窗口扩展消息wc.cbWndExtra = 0;// 无额外的窗口消息wc.hInstance = hInstance;//设置实例wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);//加载默认图标wc.hCursor = LoadCursor(NULL, IDC_ARROW);// 加载箭头指针wc.hbrBackground = NULL;//没有GL背景wc.lpszMenuName = NULL;// 我们不想要目录wc.lpszClassName = "OpenGL";//设置类的名称if (!RegisterClass(&wc))//试图注册窗口类{MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;//返回FALSE}if (fullscreen)//试图全屏模式?{DEVMODE dmScreenSettings;// 设备模式memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));//确保内存清空dmScreenSettings.dmSize = sizeof(dmScreenSettings);//开发模式结构体大小dmScreenSettings.dmPelsWidth = width;// 选定屏幕宽度dmScreenSettings.dmPelsHeight = height;// 选定屏幕高度dmScreenSettings.dmBitsPerPel = bits;// 选定像素色彩深度dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;// 试图设置选定的模式并返回结果  提示: CDS_FULLSCREEN没有Start Bar.if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){// 如果模式失败,提供两个选项,退出或使用窗口模式if (MessageBox(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "NeHe GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES){fullscreen = FALSE;//选定窗口模式.  Fullscreen = FALSE}else{//弹出一个消息盒让用户知道程序正在关闭MessageBox(NULL, "Program Will Now Close.", "ERROR", MB_OK | MB_ICONSTOP);return FALSE;// 返回FALSE}}}if (fullscreen)//我们仍在全屏模式?{dwExStyle = WS_EX_APPWINDOW;//窗口扩展类型dwStyle = WS_POPUP;// 窗口类型ShowCursor(FALSE);// 隐藏鼠标指针}else{dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;// 窗口拓展类型dwStyle = WS_OVERLAPPEDWINDOW;// 窗口类型}AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);// 将窗口调整到正确的所需尺寸// 创建窗口if (!(hWnd = CreateWindowEx(dwExStyle,// 窗口拓展类型"OpenGL",// 类名title,// 窗口名称dwStyle |// 定义的窗口类型WS_CLIPSIBLINGS |//所需的窗口类型WS_CLIPCHILDREN,//所需的窗口类型0, 0,// 窗口位置WindowRect.right - WindowRect.left,// 计算窗口宽度WindowRect.bottom - WindowRect.top,// 计算窗口高度NULL,// 没有父窗口NULL,// 没有目录hInstance,// 实例NULL)))// 不传递任何参数至WM_CREATE{KillGLWindow();//重置显示MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;//返回FALSE}staticPIXELFORMATDESCRIPTOR pfd =// pfd(像素格式描述符)告诉窗口我们想让东西变成什么样{sizeof(PIXELFORMATDESCRIPTOR),// pfd大小1,// 版本号PFD_DRAW_TO_WINDOW |// 格式必须支持窗口PFD_SUPPORT_OPENGL |// 格式必须支持OpenGLPFD_DOUBLEBUFFER,// 必须支持双缓存PFD_TYPE_RGBA,// 需要RGBA格式(红绿蓝Alpha)bits,// 选择我们的色彩深度0, 0, 0, 0, 0, 0,// 忽略的色彩位0,// 无Alpha缓存0,// 忽略的移位0,// 无累加缓存0, 0, 0, 0,// 忽略的累加缓存16,// 16Bit Z-Buffer (深度缓存)  0,// 无蒙版缓存0,// 无辅助缓存PFD_MAIN_PLANE,// 主绘图层0,// 预留项0, 0, 0// 忽略层遮罩};if (!(hDC = GetDC(hWnd)))//我们获得设备描述表了吗?{KillGLWindow();// 重置显示MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;// 返回错误}if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))// windows找到匹配的像素格式了吗?{KillGLWindow();// 重置显示MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;// 返回FALSE}if (!SetPixelFormat(hDC, PixelFormat, &pfd))//我们能设置像素格式吗?{KillGLWindow();//重置显示MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;// 返回 FALSE}if (!(hRC = wglCreateContext(hDC)))//我们能获取渲染描述表吗?{KillGLWindow();// 重置显示MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;//返回 FALSE}if (!wglMakeCurrent(hDC, hRC))// 试图激活像素描述表{KillGLWindow();// R重置显示MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;// 返回FALSE}ShowWindow(hWnd, SW_SHOW);//显示窗口SetForegroundWindow(hWnd);//微微提升优先级SetFocus(hWnd);//设置键盘焦点于此窗口ReSizeGLScene(width, height);//设置透视GL屏幕if (!InitGL())// 初始化我们新创建的GL窗口{KillGLWindow();// 重置显示MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);return FALSE;// 返回 FALSE}return TRUE;// 成功}LRESULT CALLBACK WndProc(HWNDhWnd,// 解决这个窗口UINTuMsg,// 这个窗口的消息WPARAMwParam,// 额外消息信息LPARAMlParam)// 额外消息信息{switch (uMsg)//检查消息{case WM_ACTIVATE://监视窗口激活消息{if (!HIWORD(wParam))// 检查最低状态{active = TRUE;// 程序被激活}else{active = FALSE;//程序不再激活}return 0;// 返回到消息循环}case WM_SYSCOMMAND:// 系统中断命令{switch (wParam)//检查系统调用{case SC_SCREENSAVE:// 屏保要运行?case SC_MONITORPOWER:// 显示器要进入屏保?return 0;// 阻止发生}break;// 退出}case WM_CLOSE:// 我们收到关闭消息?{PostQuitMessage(0);// 发送退出消息return 0;// 返回}case WM_KEYDOWN:// 有一个键被按下?{keys[wParam] = TRUE;// 如果是,将其标记为TRUEreturn 0;// 返回}case WM_KEYUP://有键被释放?{keys[wParam] = FALSE;// 如果是,将其标记为FALSEreturn 0;// 返回}case WM_SIZE://重设OpenGL窗口尺寸{ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));  // LoWord=Width, HiWord=Heightreturn 0;// 返回}}//所有未解决的消息传送到DefWindowProcreturn DefWindowProc(hWnd, uMsg, wParam, lParam);}int WINAPI WinMain(HINSTANCEhInstance,// 实例HINSTANCEhPrevInstance,// 之前的实例LPSTRlpCmdLine,// 命令行参数intnCmdShow)// 窗口显示状态{MSGmsg;//窗口消息结构BOOLdone = FALSE;// Bool变量用于退出循环//询问用户他们想要哪种模式if (MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO | MB_ICONQUESTION) == IDNO){fullscreen = FALSE;// 窗口模式}// 创建我们的OpenGL窗口if (!CreateGLWindow("NeHe's Animated Blended Textures Tutorial", 640, 480, 16, fullscreen)){return 0;// 窗口未被创建退出}while (!done)// 当done=FALSE循环{if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//有消息等待?{if (msg.message == WM_QUIT)//我们收到一个退出的消息?{done = TRUE;//如果是done=TRUE}else// 如果不是,处理窗口消息{TranslateMessage(&msg);// 翻译消息DispatchMessage(&msg);// 传递消息}}else//没有消息{//绘制场景.监视来自DrawGLScene()的ESC键和退出消息if ((active && !DrawGLScene()) || keys[VK_ESCAPE])// 激活? 或 有一个退出收到?{done = TRUE;// ESC or DrawGLScene标记一个退出}else// 未退出,更行场景   (原例程标注为not time to quit){SwapBuffers(hDC);//转换缓存(双缓存)if (keys['T'] && !tp){tp = TRUE;twinkle = !twinkle;}if (!keys['T']){tp = FALSE;}if (keys[VK_UP]){tilt -= 0.5f;}if (keys[VK_DOWN]){tilt += 0.5f;}if (keys[VK_PRIOR]){zoom -= 0.2f;}if (keys[VK_NEXT]){zoom += 0.2f;}if (keys[VK_F1])//F1按下?{keys[VK_F1] = FALSE;//如果是,让Key为FALSEKillGLWindow();// 关闭当前窗口fullscreen = !fullscreen;// 开启 全屏 / 窗口模式// 重新创建我们的OpenGL窗口if (!CreateGLWindow("NeHe's Animated Blended Textures Tutorial", 640, 480, 16, fullscreen)){return 0;// 如果窗口没有被创建退出}}}}}// 关闭KillGLWindow();//关闭窗口return (msg.wParam);// 退出程序}


原创粉丝点击