实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

一、实验目的

  • 利用openMesh导入应用软件制作的3D模型,有一定的交互功能。
    • 使用键盘实现切换图片
    • 使用键盘实现平移
    • 使用键盘实现旋转
    • WireFrame/Flatlines/Flat模式切换

二、实验环境

  • Visual Studio 2019
  • Windows 10

三、算法分析与设计

  • 设置全局变量

    // 旋转角度
    float xRotate = 0.0f;
    float yRotate = 0.0f;
    
    // 位置坐标
    float ty = 0.0f;
    float tx = 0.0f;
    
    // 缩放比例
    float scale = 1;
    
    //文件读取有关的
    MyMesh mesh;  //mesh把文件读取了,封装在mesh对象中
    const string file_2 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\Armadillo.off";
    const string file_5 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";
    const string file_6 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";
    const string file_7 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";
    
    int currentfile = 1;
    
    GLuint showFaceList, showWireList;
    int showstate = 1;
    bool showFace = true;
    bool showWire = false;
    bool showFlatlines = false;
    
  • 光照

  • 读文件

  • 键盘交互

    // 键盘交互
    // f2:切换文件
    // f5:正常显示
    // f6:缩放图片
    // f7:旋转图片
    // INSERT:切换模式
    // key:平移
    void mySpecial(int key, int x, int y) {
    	switch (key) {
    
    	case GLUT_KEY_F2:
    		cout << "读取文件:" << file_2 << " 中......" << endl;
    		readfile(file_2);
    		scale = 0.003;
    		currentfile = 2;
    		initGL();
    		break;
    
    	case GLUT_KEY_F5: 
    		cout << "读取文件:" << file_5 << " 中......" << endl;
    		readfile(file_5);
    		scale = 1;
    		currentfile = 5;
    		initGL();
    		break;
    
    	case GLUT_KEY_F6:
    		cout << "读取文件:" << file_6 << " 中......" << endl;
    		readfile(file_6);
    		scale = 0.5;
    		currentfile = 3;
    		initGL();
    		break;
    
    	case GLUT_KEY_F7:  
    		cout << "读取文件:" << file_7 << " 中......" << endl;
    		readfile(file_7);
    		scale = 1;
    		xRotate += 10.0f;
    		currentfile = 3;
    		initGL();
    		break;
    
    
    	// 实现不同模式
    	case GLUT_KEY_INSERT:
    		if (showFace == true) {
    			showFace = false;
    			showWire = true;
    
    			cout << "切换显示模式为:WireFrame" << endl;
    		}
    		else if (showWire == true)
    		{
    			showWire = false;
    			showFlatlines = true;
    			cout << "切换显示模式为:Flatlines" << endl;
    		}
    		else if (showFlatlines == true) {
    			showFlatlines = false;
    			showFace = true;
    			//DisplaySphere(0.5, "G:\\source\\OpenGL\\Cow\\checkerboard3.bmp");
    			cout << "切换显示模式为:Flat" << endl;
    		}
    		break;
    	
    	// 实现平移
    	case GLUT_KEY_LEFT:
    		tx -= 0.01;
    		break;
    	case GLUT_KEY_RIGHT:
    		tx += 0.01;
    		break;
    	case GLUT_KEY_UP:
    		ty += 0.01;
    		break;
    	case GLUT_KEY_DOWN:
    		ty -= 0.01;
    		break;
    	default:
    		break;
    	}
    	glutPostRedisplay();
    }
    

四、实验结果

f2切换文件

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

f5正常显示

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

f6缩放图片

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

f7旋转图片

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

key平移

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

INSERT切换模式

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

实现3D物体导入与绘制_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

五、附录

#include <bits/stdc++.h>
#include <OpenMesh/Core/IO/MeshIO.hh>  
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>  
#include<GL/glut.h>

using namespace std;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;

// 旋转角度
float xRotate = 0.0f;
float yRotate = 0.0f;

// 位置坐标
float ty = 0.0f;
float tx = 0.0f;

// 缩放比例
float scale = 1;

//文件读取有关的
MyMesh mesh;  //mesh把文件读取了,封装在mesh对象中
const string file_2 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\Armadillo.off";
const string file_5 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";
const string file_6 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";
const string file_7 = "D:\\Sophomore\\计算机图形学\\assignment\\lab07\\lab07\\openmesh模型\\cow.obj";

int currentfile = 1;

GLuint showFaceList, showWireList;
int showstate = 1;
bool showFace = true;
bool showWire = false;
bool showFlatlines = false;



void setLightRes() {
	GLfloat lightPosition[] = { 0.0f, 1.0f, 0.0f, 0.0f }; // 平行光源, GL_POSITION属性的最后一个参数为0


	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
	glEnable(GL_LIGHTING); //启用光源
	glEnable(GL_LIGHT0);   //使用指定灯光
}
void SetupRC()
{
	glEnable(GL_DEPTH_TEST);
	glFrontFace(GL_CCW);
	glEnable(GL_CULL_FACE);
	// 启用光照计算
	glEnable(GL_LIGHTING);
	// 指定环境光强度(RGBA)
	GLfloat ambientLight[] = { 1.0f, 0.0f, 0.0f, 0.0f };
	// 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
	// 启用颜色追踪
	glEnable(GL_COLOR_MATERIAL);
	// 设置多边形正面的环境光和散射光材料属性,追踪glColor
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
}

//初始化顶点和面   
void initGL()
{
	//实用显示列表
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClearDepth(2.0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST); //用来开启深度缓冲区的功能,启动后OPengl就可以跟踪Z轴上的像素,那么它只有在前面没有东西的情况下才会绘制这个像素,在绘制3d时,最好启用,视觉效果会比较真实
	glEnable(GL_TEXTURE_2D);
	
	// Lighting  
	glEnable(GL_LIGHTING); // 如果enbale那么就使用当前的光照参数去推导顶点的颜色
	glEnable(GL_LIGHT0); //第一个光源,而GL_LIGHT1表示第二个光源
	
	// Display List  
	setLightRes();
	SetupRC();//设置环境光
	showFaceList = glGenLists(1);
	showWireList = glGenLists(1);
	int temp = mesh.n_edges();

	// 绘制 wire 
	glNewList(showWireList, GL_COMPILE);
	glDisable(GL_LIGHTING);
	glLineWidth(1.0f);
	glColor3f(0.5f, 0.5f, 0.5f);//灰色
	glBegin(GL_LINES);
	for (MyMesh::HalfedgeIter he_it = mesh.halfedges_begin(); he_it != mesh.halfedges_end(); ++he_it) {
		//链接这个有向边的起点和终点
		glVertex3fv(mesh.point(mesh.from_vertex_handle(*he_it)).data());
		glVertex3fv(mesh.point(mesh.to_vertex_handle(*he_it)).data());
	}
	glEnd();
	glEnable(GL_LIGHTING);
	glEndList();

	// 绘制flat
	glNewList(showFaceList, GL_COMPILE);
	for (MyMesh::FaceIter f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
		glBegin(GL_TRIANGLES);
		for (MyMesh::FaceVertexIter fv_it = mesh.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) {
			glNormal3fv(mesh.normal(*fv_it).data());
			glVertex3fv(mesh.point(*fv_it).data());
		}
		glEnd();
	}
	glEndList();
}

// 当窗体改变大小的时候,改变窗口大小时保持图形比例
void myReshape(GLint w, GLint h)
{
	glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (w > h)
		glOrtho(-static_cast<GLdouble>(w) / h, static_cast<GLdouble>(w) / h, -1.0, 1.0, -100.0, 100.0);
	else
		glOrtho(-1.0, 1.0, -static_cast<GLdouble>(h) / w, static_cast<GLdouble>(h) / w, -100.0, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


// 读取文件的函数
void readfile(string file) {
	// 请求顶点法线 vertex normals
	mesh.request_vertex_normals();
	//如果不存在顶点法线,则报错 
	if (!mesh.has_vertex_normals())
	{
		cout << "错误:标准定点属性 “法线”不存在" << endl;
		return;
	}
	// 如果有顶点发现则读取文件,读入到mesh对象中
	OpenMesh::IO::Options opt;
	if (!OpenMesh::IO::read_mesh(mesh, file, opt))
	{
		cout << "无法读取文件:" << file << endl;
		return;
	}
	else cout << "成功读取文件:" << file << endl;
	cout << endl; 
	
	//如果不存在顶点法线,则计算出
	if (!opt.check(OpenMesh::IO::Options::VertexNormal))
	{
		// 通过面法线计算顶点法线
		mesh.request_face_normals();
		// mesh计算出顶点法线
		mesh.update_normals();
		// 释放面法线
		mesh.release_face_normals();
	}
}

//  键盘交互
// f2:切换文件
// f5:正常显示
// f6:缩放图片
// f7:旋转图片
// INSERT:切换模式
// key:平移
void mySpecial(int key, int x, int y) {
	switch (key) {

	case GLUT_KEY_F2:
		cout << "读取文件:" << file_2 << " 中......" << endl;
		readfile(file_2);
		scale = 0.003;
		currentfile = 2;
		initGL();
		break;

	case GLUT_KEY_F5: 
		cout << "读取文件:" << file_5 << " 中......" << endl;
		readfile(file_5);
		scale = 1;
		currentfile = 5;
		initGL();
		break;

	case GLUT_KEY_F6:
		cout << "读取文件:" << file_6 << " 中......" << endl;
		readfile(file_6);
		scale = 0.5;
		currentfile = 3;
		initGL();
		break;

	case GLUT_KEY_F7:  
		cout << "读取文件:" << file_7 << " 中......" << endl;
		readfile(file_7);
		scale = 1;
		xRotate += 10.0f;
		currentfile = 3;
		initGL();
		break;


	// 实现不同模式
	case GLUT_KEY_INSERT:
		if (showFace == true) {
			showFace = false;
			showWire = true;

			cout << "切换显示模式为:WireFrame" << endl;
		}
		else if (showWire == true)
		{
			showWire = false;
			showFlatlines = true;
			cout << "切换显示模式为:Flatlines" << endl;
		}
		else if (showFlatlines == true) {
			showFlatlines = false;
			showFace = true;
			//DisplaySphere(0.5, "G:\\source\\OpenGL\\Cow\\checkerboard3.bmp");
			cout << "切换显示模式为:Flat" << endl;
		}
		break;
	
	// 实现平移
	case GLUT_KEY_LEFT:
		tx -= 0.01;
		break;
	case GLUT_KEY_RIGHT:
		tx += 0.01;
		break;
	case GLUT_KEY_UP:  // 与屏幕显示一致
		ty -= 0.01;
		break;
	case GLUT_KEY_DOWN:
		ty += 0.01;
		break;
	default:
		break;
	}
	glutPostRedisplay();
}

void myDisplay()
{
	//要清除之前的深度缓存
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	//与显示相关的函数
	glRotatef(xRotate, 1.0f, 0.0f, 0.0f); // 让物体旋转的函数 第一个参数是角度大小,后面的参数是旋转的法向量
	glRotatef(yRotate, 0.0f, 1.0f, 0.0f);
	glTranslatef(0.0f, 0.0f, ty);
	glTranslatef(tx, ty, 0);
	glScalef(scale, scale, scale); // 缩放

								   //每次display都要使用glcalllist回调函数显示想显示的顶点列表
	if (showFace)
		glCallList(showFaceList);
	if (showFlatlines) {
		glCallList(showFaceList);
		glCallList(showWireList);
	}
	if (showWire)
		glCallList(showWireList);

	glutSwapBuffers(); //这是Opengl中用于实现双缓存技术的一个重要函数
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // GLUT_Double 表示使用双缓存而非单缓存
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(800, 500);
	glutCreateWindow("Mesh Viewer");

	glutSpecialFunc(&mySpecial);
	glutReshapeFunc(&myReshape);
	glutDisplayFunc(&myDisplay);

	glutMainLoop();
	return 0;
}
上一篇:ABAP 7.50 新特性 Open SQL中的宿主表达式和其它表达式


下一篇:如何创建最简单的 ABAP 数据库表,以及编码从数据库表中读取数据 (上)