OpenGL渲染模型 || 3. opengl 将模型成渲染图片
前言
最近项目中需要使用到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 将模型成渲染图片相关推荐
- [OpenGL ES 03]3D变换:模型,视图,投影与Viewport
[OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循"署名-非商业用途-保持一致" ...
- OpenGL模型加载之模型
参考: https://learnopenglcn.github.io/03%20Model%20Loading/03%20Model/ 定义一个模型类 class Model {public:/* ...
- 【OpenGL】十、OpenGL 绘制点 ( 初始化 OpenGL 矩阵 | 设置投影矩阵 | 设置模型视图矩阵 | 绘制点 | 清除缓冲区 | 设置当前颜色值 | 设置点大小 | 绘制点 )
文章目录 一.初始化 OpenGL 矩阵 1.设置投影矩阵 2.设置模型视图矩阵 二.绘制点 1.清除缓冲区 2.设置当前颜色值 3.设置绘制点的大小 4.绘制点 5.将缓冲区绘制到前台 三.部分代码 ...
- 3ds模型在OpenGL中的读取和重绘
关键字: OpenGL 3ds模型文件格式 读取与重绘 对OpenGL做了基本的介绍,并详细介绍了3ds模型的文件格式.在VC+十下的OpenGL编程中完成了3ds模型的读取与重绘.并例举了一个3d ...
- opengl加载多个3ds模型失败记
VC6 下载 http://blog.csdn.net/bcbobo21cn/article/details/44200205 opengl环境配置 http://blog.csdn.net/bcbo ...
- 相机模型:opengl投影 vs 小孔成像
相机模型:opengl投影 vs 小孔成像 一级目录 相机投影方式 Perspective Projection 对应小孔成像 小孔成像 opengl near-far-plane lookup ma ...
- 使用3ds Max和3D Exploration将Solidworks模型导入Opengl
在项目中,有一项工作需要将SOLIDWORKS建好的模型导入到Opengl中实现操作设备的可视化,下面是具体的实现方法. 1)在SOLIDWORKS完成模型的建模后,附加零件材质,并另存为IGS格式. ...
- 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★
文章目录 一.导入 OpenGL 的两个头文件 二.链接 OpenGL 库 三.将 Windows 桌面窗口改成 OpenGL 窗口 四.获取窗口设备 五.设置像素格式描述符 六.设置像素格式 七.创 ...
- 使用three.js导入OBJ模型,变更、修改成其他OBJ模型和模型不可见原因说明
最近的一个项目需要在HTML中对OBJ模型进行大量的变更,修改为其他模型.基于这个需求下,这里有一种解决方案. 另外在各大论坛上的相关博客基本都是那几种导入obj例子····并没有对后续操作进行说明. ...
最新文章
- OKR简单通俗易懂的介绍,1分钟了解什么是OKR工作法
- 为UINavigationBar添加自定义背景
- VB6.0使用ADO对象连接数据库
- 社区不支持HTML,popover不支持html内容吗?
- [转]详解HTTP包
- 相量除法能用计算机吗,电路相量的加减乘除运算
- list vue 添加数据方法_一篇文章教会你创建vue项目和使用vue.js实现数据增删改查...
- indesign缩放图片被切割_InDesign怎么改变图片的大小
- 数据平台SQL开发详解与函数使用
- java实训任务_java实训任务
- 什么是连接池?为什么需要连接池呢?连接池的组成原理又是什么呢?
- Some Thoughts
- 使用Texmacs帮助您写格式规范统一的BLOG
- 远程操作Linux图形界面
- Unity动态天空shader实现
- 安卓苹果手机在微信内打开支付宝h5拉起app支付
- MacOS swift 首页导航栏 不显示标题问题
- 全球与中国汽车点火线圈市场深度研究分析报告
- Udacity数据分析(进阶试学)-五王之战分析 - 冰与火之歌
- 盛世昊通联手民族品牌CaldiceKris,创造价值互联