前言
最近项目中需要使用到OpenGL对3D模型进行渲染。
已有数据为:
- 带纹理的3D模型
- 模型上的关键点。
需要实现的功能:
- 读取和保存 带纹理的3D模型、读取模型的关键点
- 对模型进行渲染,保存设定角度的渲染图片、以及关键点在相同角度的2D坐标
- 在渲染图片中模型上任意一个2D点,反向计算到该点空间的3D位置
开发环境:
- VS2015、三方库 OpenGL、OpenCV。
OpenGL渲染模型 || 1. OpenCV、OpenGL的环境配置
OpenGL渲染模型 || 2. 3D模型的读取与保存
OpenGL渲染模型 || 3. opengl 将模型成渲染图片
由于自己是简单应用,所以对其了解重心在实现的过程,以及OpenGL的相关原理。
1 OpenGL渲染设置流程
- 1 初始化窗口:并设置初始窗口大小、位置、命名。
- 2 设置光照环境:光照模式、材料属性、光源位置;并开启深度测试、开启剔除操作效果。
- 3 设置相机参数:涉及到模型矩阵( Model Matrix)、投影矩阵(Projection Matrix)、视口矩阵(View Matrix)的设置
- 4 清除屏幕,读取模型
- 5 设置保存渲染窗口为图片的操作(此时,保存好彩色图、深度图、相机三个矩阵,就可以计算 空间3D点与对应的图片2D点 之间的互相映射)
- 6 开启OpenGL渲染
这个过程跟我们实际拍照很像:
- 1 确定拍照环境,如位置、大小、命名等;
- 2 放置光源,确定位置、方向等;
- 3 放置相机,设置相机内参;
- 4 放置模型(注意先清除拍照空间里的杂物);
- 5 给相机选择拍照模式;
- 6 按下快门
2 代码简介
下面实现的要渲染的模型,是带纹理信息的3D模型。
2.1 GLShow.h
该脚本定义了实现渲染模型的类
class GLShow
。
在这里需要使用到上一章节的 obj的读取中的 “ 类 ModelMesh” 的内容。#pragma once #include"meshcnn.h" #include<GL/glut.h> #include<GL/freeglut.h> //#include <opencv2/flann.hpp> using namespace std; class GLShow { public: GLShow(); ~GLShow(); public: // OpenGL 初始化 void glInit(); // 渲染函数 static void glDisplay(); static void glDisplayOnWin(); void glMainLoop(); // 开启渲染 static void glStop(); // 结束渲染 void glExit(); // 退出 // 设置相机参数 void glCamView(); // 设置 void GetCamMatrix(int idx); //获取和保存相机参数 // 将模型放入到坐标系中 void initTexture(); void renderObj(); void renderPoint(); // 虚拟拍照 void getImage(int idx, bool fortest);//获取彩色图 void getDepthImage(int idx);//获取深度图 void getMask(); // 获得渲染的掩码 void D2toD3(int idx); // 2D点反投影获取三D点 void D3toD2(int idx); // 3D点投影得到的2D点 static void glKeyboard(unsigned char key, int x, int y); static void glMouseFunc(int button, int state, int x, int y); static void glMotionFunc(int x, int y); bool IsGetRenderImage = true; bool isShowColor; public: ModelMesh mesh; string ImagePath; //保存渲染的图片路径 string labelPath; //保存3D点到2D点的文本的路径 int glWidth; int glHeight; int num_photo = 2; // 选择两个角度渲染 vector<cv::Mat> images; vector<cv::Mat> images_depth; vector<cv::Mat> masks; vector<vector<cv::Point3f>> Keypoints2; ///< 2d关节点坐标(假定4个面) vector<vector<cv::Point3f>> Keypoints3; ///< 3d关节点坐标(假定4个面) vector<cv::Point3f> finalKeypoints3; private: GLuint m_textureId; static GLShow *gl; /// 初始化 gl = this,用来调用非静态成员 double *modelMatrix[2]; double *projMatrix[2]; int *viewport[2]; float scale; int posX; /// 记录opengl窗口上鼠标X位置 int posY; /// 记录opengl窗口上鼠标Y位置 static int GLUTbutton[3]; /// 记录鼠标按键事件---左键、中键、右键 static float rotation[4][4]; /// 模型的旋转矩阵 static float translate[3]; /// 模型的平移矩阵 };
接下来的就是这些函数的具体实现
2.2 OpenGL的开始及终止
- 完成 OpenGL渲染的所有设置,然后使用
glMainLoop()
开启OpenGL的渲染。程序就会反复的调用 OpenGL的回调函数- 当完成渲染任务后,使用
glStop()
,离开OpenGL的 glMainLoop()- 想要退出OpenGL的整个环境,使用
glExit()
void GLShow::glMainLoop() { glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); // 与glutLeaveMainLoop()使用,退出glut但继续执行后面的程序 glutMainLoop(); } void GLShow::glStop() { glutHideWindow(); glutLeaveMainLoop(); } void GLShow::glExit() { glutExit(); }
2.3 OpenGL的核心渲染流程
2.3.1 部分变量的初始化
# include"GLShow.h" // 初始化静态成员变量 GLShow * GLShow::gl = 0; int GLShow::GLUTbutton[3] = { 0,0,0 }; float GLShow::translate[3] = { 0.0,0.0,0.0 }; float GLShow::rotation[4][4] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; GLShow::GLShow() { gl = this; glWidth = 500; glHeight = 500; ImagePath = "./"; labelPath = "./"; images.resize(num_photo); images_depth.resize(num_photo); masks.resize(num_photo); Keypoints2.resize(num_photo); Keypoints3.resize(num_photo); } GLShow::~GLShow() { }
2.3.2 初始化窗口、设置光照环境
【step1】 初始化窗口:并设置初始窗口大小、位置、命名。
void GLShow::glInit() { int argc2 = 2; char **argv2 = new char *[2]; argv2[0] = "OpenGL"; argv2[1] = "TEST"; glutInit(&argc2, argv2); glutInitWindowPosition(100, 100); //初始化窗口位置 glutInitWindowSize(glWidth, glHeight); //初始化窗口大小 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE); //设定缓冲区类型、颜色模式、深度缓存 int glWindowIdx = glutCreateWindow("OpenGL Viewer"); //创建窗口并命名
【step2】 设置光照环境:光照模式、材料属性、光源位置;并开启深度测试、开启剔除操作效果。
// 设置光照模式 static GLfloat LightAmbient[] = { 0.4, 0.4, 0.4, 1.0 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightAmbient); //设置全局环境光 //glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); //将无限远的观察点改为局部观察点 // 设置材料属性 static GLfloat Matetrial[] = { 0.8, 0.8, 0.8, 0.8 }; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Matetrial); // 设置光源,这里只设置了一个光源 static GLfloat light0Diffuse[] = { 0.9, 0.9, 0.9, 1.0 }; glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); static GLfloat light0Position[] = { 0, 0, 1.0, 0.0 };//光源的位置写在lookat之前,光源的位置和相机的位置就绑定在一起 glLightfv(GL_LIGHT0, GL_POSITION, light0Position); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); //开启深度测试 glEnable(GL_CULL_FACE); //开启剔除操作效果
在
glutMainLoop()
使用之后,会循环运行下面的回调函数。// 初始化回调函数 if (gl->IsGetRenderImage) { glutDisplayFunc(glDisplay); } else { glutKeyboardFunc(glKeyboard); glutMouseFunc(glMouseFunc); glutMotionFunc(glMotionFunc); glutDisplayFunc(glDisplayOnWin); } }
2.3.3 设置相机参数
【step3】设置相机参数:涉及到模型矩阵(Model Matrix)、投影矩阵(Projection Matrix)、视口矩阵(View Matrix)的设置
void GLShow::glCamView() { cv::Point3f camPosition; //相机位置 cv::Point3f camToward(0, 0, -1); //相机z轴负方向 camPosition = mesh.center - camToward * 2 * mesh.radius; //相机位置在z轴负方向,离模型中心的2*处 //设置模型矩阵 Model Matrix================================================== glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(camPosition.x, camPosition.y, camPosition.z, mesh.center.x, mesh.center.y, mesh.center.z, 0.0, 1.0, 0.0); // 设置模型矩阵(Model Matrix),用正交投影===================================== glMatrixMode(GL_PROJECTION); glLoadIdentity(); float r = mesh.radius; glOrtho(-r, r, -r, r, 0.01*r, 100 * r); // 正交投影 //gluPerspective(60, 4 / 3, 0.01*mesh.radius, 100 * mesh.radius); // 透视投影 // 设置视口矩阵(View Matrix)。进行视口缩放之后才与mashlab渲染效果一致 ============ glViewport((glWidth - glHeight) / 2, 0, glHeight, glHeight); //上面的显示,模型的成像不会随窗口的大小而改变;下面的方式相反 ===================== //float s = glHeight / glWidth; //glOrtho(-r, r, -r*s, r*s, 0.01*r, 100 * r); //glViewport(0, 0, glWidth, glHeight); }
2.3.4 读取模型
【step4】清除屏幕,读取模型。 在使用
ModelMesh.readObj
之后,已经将模型的信息获取到。然后需要将这些信息传入到OpenGL的api中。读取纹理
void GLShow::initTexture() { cv::Mat img = cv::imread(mesh.textureFile, 1); int type = img.type(); cvtColor(img, img, CV_BGR2RGB); cv::flip(img, img, 0); glEnable(GL_TEXTURE_2D); glGenTextures(1, &m_textureId); glBindTexture(GL_TEXTURE_2D, m_textureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 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, GL_RGB, img.cols, img.rows, 0, GL_RGB, GL_UNSIGNED_BYTE, img.data); glBindTexture(GL_TEXTURE_2D, 0); }
读取3D模型准备渲染
void GLShow::renderObj() { if (m_textureId == 0) { initTexture(); } glBindTexture(GL_TEXTURE_2D, m_textureId); glBegin(GL_TRIANGLES); int n = mesh.tris.size(); for (int i = 0; i < n; i++) { auto v = mesh.tris[i]; auto n = mesh.faceNrm[i]; auto t = mesh.textures[i]; glNormal3f(mesh.vtxNrm[n.x].x, mesh.vtxNrm[n.x].y, mesh.vtxNrm[n.x].z); glTexCoord2d(mesh.texcodNrm[t.v1].tx, mesh.texcodNrm[t.v1].ty); glVertex3f(mesh.vtx[v.v1].x, mesh.vtx[v.v1].y, mesh.vtx[v.v1].z); glNormal3f(mesh.vtxNrm[n.y].x, mesh.vtxNrm[n.y].y, mesh.vtxNrm[n.y].z); glTexCoord2d(mesh.texcodNrm[t.v2].tx, mesh.texcodNrm[t.v2].ty); glVertex3f(mesh.vtx[v.v2].x, mesh.vtx[v.v2].y, mesh.vtx[v.v2].z); glNormal3f(mesh.vtxNrm[n.z].x, mesh.vtxNrm[n.z].y, mesh.vtxNrm[n.z].z); glTexCoord2d(mesh.texcodNrm[t.v3].tx, mesh.texcodNrm[t.v3].ty); glVertex3f(mesh.vtx[v.v3].x, mesh.vtx[v.v3].y, mesh.vtx[v.v3].z); } glEnd(); glBindTexture(GL_TEXTURE_2D, 0); }
读取3D顶点准备渲染
void GLShow::renderPoint() { glPointSize(10.0f); glBegin(GL_POINTS); for (int i = 0; i < gl->mesh.keypoint.size(); i++) { glVertex3f(gl->mesh.keypoint[i].x, gl->mesh.keypoint[i].y, gl->mesh.keypoint[i].z); } glEnd(); }
2.3.5 设置获取渲染图片模式
【step5】设置保存渲染窗口为图片的操作(此时,保存好彩色图、深度图、相机三个矩阵,就可以计算 空间3D点与对应的图片2D点 之间的互相映射)
在设置好相机参数后,保留当前的三个矩阵void GLShow::GetCamMatrix(int idx) { double* modelMatrixT = new double[16]; double* projMatrixT = new double[16]; int* viewportT = new int[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrixT); glGetDoublev(GL_PROJECTION_MATRIX, projMatrixT); glGetIntegerv(GL_VIEWPORT, viewportT); gl->modelMatrix[idx] = modelMatrixT; gl->projMatrix[idx] = projMatrixT; gl->viewport[idx] = viewportT; //cout << "===============渲染" << endl; //for (int f = 0; f < 16; f++) //{ // cout << gl->modelMatrix[idx][f] << " "; //} //cout << endl; }
这里的函数
glDisplay()
,也就是 glutDisplayFunc() 的回调函数。
在这个函数里面,会调用 glCamView() 以及 renderObj()。由于想要模型的正面和侧面的渲染效果,所以会将旋转角度的操作留在for训练里面。void GLShow::glDisplay() { //设置相机位置和方向 gl->glCamView(); for (int idx = 0; idx < gl->num_photo; idx++) //投影2个面 { if (idx = 0) { glMatrixMode(GL_MODELVIEW); glRotatef(180, 0, 1.0, 0); } // 保存相机矩阵 gl->GetCamMatrix(idx); //清除屏幕 glClearColor(0.0 / 255.0, 255.0 / 255.0, 0 / 255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->renderObj(); glutSwapBuffers(); glutSwapBuffers(); //很奇怪,一定要使用两遍,如果不加这一行代码,总是虚拟拍照获取到上个场景的图片 gl->getImage(idx, false); gl->getDepthImage(idx); // 获取深度图(保存缓存的深度数据) // 读取3D关节点进行渲染 //glClearColor(0 / 255.0, 0 / 255.0, 0 / 255.0, 1.0); //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //gl->renderPoint(); //glutSwapBuffers(); //glutSwapBuffers(); //gl->getImage(idx, true); } gl->glStop(); // 自己定义的停止渲染函数,后面介绍到 }
2.4 OpenGL的其他操作
2.4.1 保存图片
从缓存中保存渲染的图片
void GLShow::getImage(int idx, bool fortest) { cv::Mat image = cv::Mat::zeros(glHeight, glWidth, CV_8UC3); unsigned char *imageData = new unsigned char[glWidth*glHeight * 3]; glReadPixels(0, 0, glWidth, glHeight, GL_RGB, GL_UNSIGNED_BYTE, imageData); for (int rowGL = 0; rowGL < glHeight; rowGL++) { for (int col = 0; col < glWidth; col++) { //opencv的图像坐标的(0,0)在左上角,opengl的(0,0)在左下角 int rowCV = glHeight - rowGL - 1; //颜色OpenCV是BGR,opengl是RGB; image.at<cv::Vec3b>(rowCV, col)[0] = imageData[3 * (rowGL*glWidth + col) + 2]; image.at<cv::Vec3b>(rowCV, col)[1] = imageData[3 * (rowGL*glWidth + col) + 1]; image.at<cv::Vec3b>(rowCV, col)[2] = imageData[3 * (rowGL*glWidth + col) + 0]; //cout << float(image.at<cv::Vec3b>(rowCV, col)[2]) << endl; } } if (fortest) { imwrite(ImagePath + mesh.modelname + string("_") + std::to_string(idx) + string(".png"), image); return; } image.copyTo(images[idx]); return; } void GLShow::getDepthImage(int idx) { cv::Mat image = cv::Mat::zeros(glHeight, glWidth, CV_32FC1); float *sceneDepthBuffer = (float *)malloc(sizeof(float)*glWidth*glHeight); glReadPixels(0, 0, glWidth, glHeight, GL_DEPTH_COMPONENT, GL_FLOAT, sceneDepthBuffer); for (int rowGL = 0; rowGL<glHeight; rowGL++) { for (int col = 0; col<glWidth; col++) { // opencv的图像坐标的(0,0)在左上角, opengl的(0,0)在左下角 // 颜色opencv是BRG,opengl是RGB int rowCV = glHeight - rowGL - 1; image.at<float>(rowCV, col) = sceneDepthBuffer[(rowGL*glWidth + col)]; } } image.copyTo(images_depth[idx]); }
2.4.2 3D到2D的转换
OpenGL的使用过程中,(1) 有时需要将空间的3D点,按照已定的相机参数,投影到2D图片上,并获得其2D坐标;(2) 有时需要对3D模型渲染的2D图上,找到keypoint,然后反算出其对应的3D坐标。
主要是OpenGL的两个api:
- 3D–>2D:
gluProject(object_x, object_y, object_z, modelview, projection, viewport, &winX, &winY, &winZ);- 2D–>3D:
gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ,
modelview, projection, viewport, &object_x, &object_y, &object_z);void GLShow::D2toD3(int idx) { GLint *viewport = gl->viewport[idx]; GLdouble *modelview = gl->modelMatrix[idx]; GLdouble *projection = gl->projMatrix[idx]; std::vector<cv::Point3f> keypoint_Tmp; std::vector<bool> valid; for (int j = 0; j < gl->Keypoints2[idx].size(); j++) // size==18个关节点 { if (gl->Keypoints2[idx][j].x == 0.0f || gl->Keypoints2[idx][j].y == 0.0f) { keypoint_Tmp.push_back(cv::Point3f(0.0f, 0.0f, 0.0f)); valid.push_back(false); continue; } GLint winX, winY; GLfloat winZ; /// 深度缓存数据 // openpose获取的关节点的坐标系(0,0)在左上角,opengl窗口的坐标系(0,0)在左下角 winX = floor(gl->Keypoints2[idx][j].x); winY = floor(glHeight - 1 - gl->Keypoints2[idx][j].y); //glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); //读取深度缓存值 winZ = images_depth[idx].at <float>(gl->Keypoints2[idx][j].y, gl->Keypoints2[idx][j].x); cout << winZ << endl; // 反投影回三维模型 double object_x, object_y, object_z; gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ, modelview, projection, viewport, &object_x, &object_y, &object_z); keypoint_Tmp.push_back(cv::Point3f(float(object_x), float(object_y), float(object_z))); } cout << keypoint_Tmp.size() << endl; Keypoints3[idx] = keypoint_Tmp; } void GLShow::D3toD2(int idx) { // 获取场景的模型、投影矩阵 GLint *viewport = gl->viewport[idx]; GLdouble *modelview = gl->modelMatrix[idx]; GLdouble *projection = gl->projMatrix[idx]; ofstream fout1(labelPath + mesh.modelname + string("_") + std::to_string(idx) + string(".txt")); for (int i = 0; i < mesh.keypoint.size(); i++) { GLdouble object_x = GLdouble(mesh.keypoint[i].x); GLdouble object_y = GLdouble(mesh.keypoint[i].y); GLdouble object_z = GLdouble(mesh.keypoint[i].z); GLdouble winX, winY, winZ; gluProject(object_x, object_y, object_z, modelview, projection, viewport, &winX, &winY, &winZ); //cout << winX << " " << winY << endl; int rowCV = (glHeight - winY - 1) + 0.5; int colCV = winX + 0.5; fout1 << colCV << " " << rowCV << " " << endl; } fout1.close(); }
2.5 OpenGL的简单交互
渲染的模型在窗口持续显示,并能够进行交互,这样在代码里需要修改的地方是OpenGL的回调函数。
在void GLShow::glInit()
中最后位置的代码。需要执行的是 else 内部的内容。需要定义 glKeyboard、glMouseFunc、glMotionFunc、glDisplayOnWin 四个函数。初始化回调函数 if (gl->IsGetRenderImage) { glutDisplayFunc(glDisplay); } else { glutKeyboardFunc(glKeyboard); glutMouseFunc(glMouseFunc); glutMotionFunc(glMotionFunc); glutDisplayFunc(glDisplayOnWin); } }
2.4.1 与鼠标键盘交互的回调函数
void GLShow::glKeyboard(unsigned char key, int x, int y) { switch (key) { case 'o': gl->isShowColor = !gl->isShowColor; glutPostRedisplay(); break; } } void GLShow::glMouseFunc(int button, int state, int x, int y) { gl->posX = x; gl->posY = y; cout << "==" << button << endl; // 左键0、中键1、右键2、中上3、中下4 int b = (button == GLUT_LEFT_BUTTON) ? 0 : ((button == GLUT_MIDDLE_BUTTON) ? 1 : 2); GLUTbutton[b] = (state == GLUT_DOWN) ? 1 : 0; if (state == GLUT_UP && button == 3) { gl->scale -= 0.1; if (gl->scale <= 0) { gl->scale = 0; } rotation[0][0] *= 1 / 1.1f; rotation[1][0] *= 1 / 1.1f; rotation[2][0] *= 1 / 1.1f; rotation[3][0] *= 1 / 1.1f; rotation[0][1] *= 1 / 1.1f; rotation[1][1] *= 1 / 1.1f; rotation[2][1] *= 1 / 1.1f; rotation[3][1] *= 1 / 1.1f; rotation[0][2] *= 1 / 1.1f; rotation[1][2] *= 1 / 1.1f; rotation[2][2] *= 1 / 1.1f; rotation[3][2] *= 1 / 1.1f; } else if (state == GLUT_UP && button == 4) { gl->scale += 0.1; rotation[0][0] *= 1.1f; rotation[1][0] *= 1.1f; rotation[2][0] *= 1.1f; rotation[3][0] *= 1.1f; rotation[0][1] *= 1.1f; rotation[1][1] *= 1.1f; rotation[2][1] *= 1.1f; rotation[3][1] *= 1.1f; rotation[0][2] *= 1.1f; rotation[1][2] *= 1.1f; rotation[2][2] *= 1.1f; rotation[3][2] *= 1.1f; } glutPostRedisplay(); } void GLShow::glMotionFunc(int x, int y) { int dx = x - gl->posX; int dy = y - gl->posY; if (GLUTbutton[0]) { float a = float(dx) / float((gl->glWidth / 4)); float sa = sin(a); float ca = cos(a); float row0[4]; for (int i = 0; i<4; i++) row0[i] = rotation[i][0]; for (int i = 0; i<4; i++) rotation[i][0] = ca*row0[i] + sa*rotation[i][2]; for (int i = 0; i<4; i++) rotation[i][2] = -sa*row0[i] + ca*rotation[i][2]; a = float(dy) / float((gl->glHeight / 4)); sa = sin(a); ca = cos(a); float row1[4]; for (int i = 0; i<4; i++) row1[i] = rotation[i][1]; for (int i = 0; i<4; i++) rotation[i][1] = ca*row1[i] - sa*rotation[i][2]; for (int i = 0; i<4; i++) rotation[i][2] = sa*row1[i] + ca*rotation[i][2]; } else if (GLUTbutton[1]) { gl->translate[0] += dx; gl->translate[1] += dy; for (int i = 0; i<4; i++) rotation[i][0] += (float(dx) / float(gl->glWidth))*rotation[i][3]; for (int i = 0; i<4; i++) rotation[i][1] += (float(dy) / float(gl->glHeight))*rotation[i][3]; for (int i = 0; i<4; i++) rotation[i][2] += 0 * rotation[i][3]; } else if (GLUTbutton[2]) { gl->translate[0] += dx; gl->translate[1] += dy; for (int i = 0; i<4; i++) rotation[i][0] += (float(dx) / float(gl->glWidth))*rotation[i][3]; for (int i = 0; i<4; i++) rotation[i][1] += (float(dy) / float(gl->glHeight))*rotation[i][3]; for (int i = 0; i<4; i++) rotation[i][2] += 0 * rotation[i][3]; } if (GLUTbutton[0] || GLUTbutton[1] || GLUTbutton[2]) glutPostRedisplay(); gl->posX = x; gl->posY = y; glutPostRedisplay(); }
2.4.2 根据操作更新渲染模型
void GLShow::glDisplayOnWin() { //设置相机================================================= gl->glCamView(); // 获取鼠标、键盘的键入操作 转换的旋转平移矩阵=================== // 旋转 glPushMatrix(); glMatrixMode(GL_MODELVIEW); glTranslatef(gl->mesh.center.x, gl->mesh.center.y, gl->mesh.center.z); glMultMatrixf(*rotation); glTranslatef(-gl->mesh.center.x, -gl->mesh.center.y, -gl->mesh.center.z); // 平移 glMatrixMode(GL_PROJECTION); glViewport((gl->glWidth - gl->glHeight) / 2 + gl->translate[0], -gl->translate[1], gl->glHeight, gl->glHeight); glPopMatrix(); //启用半透明效果,渲染模型===================================== glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(221.0 / 255.0, 201.0 / 255.0, 194.0 / 255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->renderObj(); //glDisable(GL_BLEND); //glDepthMask(GL_TRUE); //启用或禁用写入(更新)深度缓冲区 glutSwapBuffers(); }