前言

最近项目中需要使用到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、中下4int 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();}

OpenGL渲染模型 || 3. opengl 将模型成渲染图片相关推荐

  1. [OpenGL ES 03]3D变换:模型,视图,投影与Viewport

    [OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循"署名-非商业用途-保持一致" ...

  2. OpenGL模型加载之模型

    参考: https://learnopenglcn.github.io/03%20Model%20Loading/03%20Model/ 定义一个模型类 class Model {public:/* ...

  3. 【OpenGL】十、OpenGL 绘制点 ( 初始化 OpenGL 矩阵 | 设置投影矩阵 | 设置模型视图矩阵 | 绘制点 | 清除缓冲区 | 设置当前颜色值 | 设置点大小 | 绘制点 )

    文章目录 一.初始化 OpenGL 矩阵 1.设置投影矩阵 2.设置模型视图矩阵 二.绘制点 1.清除缓冲区 2.设置当前颜色值 3.设置绘制点的大小 4.绘制点 5.将缓冲区绘制到前台 三.部分代码 ...

  4. 3ds模型在OpenGL中的读取和重绘

    关键字: OpenGL 3ds模型文件格式 读取与重绘  对OpenGL做了基本的介绍,并详细介绍了3ds模型的文件格式.在VC+十下的OpenGL编程中完成了3ds模型的读取与重绘.并例举了一个3d ...

  5. opengl加载多个3ds模型失败记

    VC6 下载 http://blog.csdn.net/bcbobo21cn/article/details/44200205 opengl环境配置 http://blog.csdn.net/bcbo ...

  6. 相机模型:opengl投影 vs 小孔成像

    相机模型:opengl投影 vs 小孔成像 一级目录 相机投影方式 Perspective Projection 对应小孔成像 小孔成像 opengl near-far-plane lookup ma ...

  7. 使用3ds Max和3D Exploration将Solidworks模型导入Opengl

    在项目中,有一项工作需要将SOLIDWORKS建好的模型导入到Opengl中实现操作设备的可视化,下面是具体的实现方法. 1)在SOLIDWORKS完成模型的建模后,附加零件材质,并另存为IGS格式. ...

  8. 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★

    文章目录 一.导入 OpenGL 的两个头文件 二.链接 OpenGL 库 三.将 Windows 桌面窗口改成 OpenGL 窗口 四.获取窗口设备 五.设置像素格式描述符 六.设置像素格式 七.创 ...

  9. 使用three.js导入OBJ模型,变更、修改成其他OBJ模型和模型不可见原因说明

    最近的一个项目需要在HTML中对OBJ模型进行大量的变更,修改为其他模型.基于这个需求下,这里有一种解决方案. 另外在各大论坛上的相关博客基本都是那几种导入obj例子····并没有对后续操作进行说明. ...

最新文章

  1. OKR简单通俗易懂的介绍,1分钟了解什么是OKR工作法
  2. 为UINavigationBar添加自定义背景
  3. VB6.0使用ADO对象连接数据库
  4. 社区不支持HTML,popover不支持html内容吗?
  5. [转]详解HTTP包
  6. 相量除法能用计算机吗,电路相量的加减乘除运算
  7. list vue 添加数据方法_一篇文章教会你创建vue项目和使用vue.js实现数据增删改查...
  8. indesign缩放图片被切割_InDesign怎么改变图片的大小
  9. 数据平台SQL开发详解与函数使用
  10. java实训任务_java实训任务
  11. 什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
  12. Some Thoughts
  13. 使用Texmacs帮助您写格式规范统一的BLOG
  14. 远程操作Linux图形界面
  15. Unity动态天空shader实现
  16. 安卓苹果手机在微信内打开支付宝h5拉起app支付
  17. MacOS swift 首页导航栏 不显示标题问题
  18. 全球与中国汽车点火线圈市场深度研究分析报告
  19. Udacity数据分析(进阶试学)-五王之战分析 - 冰与火之歌
  20. 盛世昊通联手民族品牌CaldiceKris,创造价值互联

热门文章

  1. Web测试的经典总结
  2. c语言函数中调用的参数太多
  3. 从护肤品到北斗/GPS双模定位模块应该怎么选
  4. 情商高不是让人舒服,而是达到目的
  5. 【入侵检测】驭龙系统Windows下面部署
  6. select函数详解及使用案例
  7. HTML5系列代码:播放快进
  8. Mysql大数据量查询优化的思路
  9. html5 jsplumb,jsPlumb开发入门教程(实现html5拖拽连线)
  10. java计算增长率_Java 计算年平均增长率