当前位置:文档之家› 计算机图形学实验报告

计算机图形学实验报告

实验一 3D模型的加载、渲染与三维操作学院:专业班级:指导老师:学号:姓名:完成日期:目录一、实验目的 (3)二、使用的工具软件及环境 (3)三、实验内容 (3)四、实验步骤 (3)五、思考 (12)一、实验目的1、掌握在Microsoft Visual Studio环境中使用OpenGL、GLUT和GLUI;2、了解计算机图形学固定流水线;3、了解OpenGL编程基础;4、掌握三维观察的数学表达和程序实现;5、掌握多边形网格的绘制;二、使用的工具软件及环境Microsoft Visual Studio 2010、OpenGL、Glut、Glui三、实验内容1、在VS 2010中配置OpenGL环境;2、编译简单的GLUT程序;3、编译GLUI源代码,并在调试模式下执行6个示例程序;4、在给定的工程中添加绘制简单几何体的代码;5、在给定的工程中添加读取、绘制三维模型的代码;6、在给定的工程中添加旋转、平移和缩放的控制代码;四、实验步骤1、安装Microsoft Visual Studio软件版本选择:Microsoft Visual Studio 2010以上版本2、VS2010中配置GLUT1)下载GLUT。

Windows环境下的GLUT下载地址:/resources/libraries/glut/glutdlls37beta.zip2)将下载的压缩包解开,将得到5个文件:glut.h、glut.lib、glut32.lib、glut.dll、glut32.dll。

3)将glut.h放到"%WinDir%\ProgramFiles(x86)\Microsoft SDKs\Windows\v7.0A\Include\gl\"文件夹中。

4)将glut.lib和glut32.lib放到"%WinDir%\ProgramFiles(x86)\Microsoft Visual Studio 10.0\VC\lib\"文件夹中。

5)将glut.dll和glut32.dll放到"%WinDir%\system32"文件夹(32位操作系统)或者"%WinDir%\SysWOW64"文件夹(64位操作系统)。

3、测试GLUT配置环境1) 打开VS2010,选择文件->新建->项目,选择Win32控制台应用程序,填入合适的名字如OpenGLTest,然后选择确定。

2) 在弹出的对话框中点击下一步,然后在附加选项中选择空项目,点击完成。

3) 然后向该工程添加一个源代码文件,取名为OpenGLTest.cpp。

4) 向OpenGLTest.c中添加代码(可在公共邮箱下载)#include <GL/glut.h>#include<gl/gl.h>#include<gl/GLU.h>void myDisplay(){glClear(GL_COLOR_BUFFER_BIT);glRectf(-0.5f,-0.5f,0.5f,0.5f);glFlush();}int main(int argc,char *argv[]){glutInit(&argc,argv);glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);glutInitWindowPosition(100,100);glutInitWindowSize(400,400);glutCreateWindow("第一个OpenGL程序");glutDisplayFunc(&myDisplay);glutMainLoop();return 0;}5) 设置必要的静态链接库列表选择“项目->属性->链接器->输入->附加包含目录”,填写必要的静态链接库列表,如“opengl32.lib; glu32.lib; glut32.lib”6) 编译、链接、执行该程序,生成一个黑色的窗口,中央显示一个白色的矩形,表明配置环境正确。

4、编译GLUI库文件和示例程序在公共邮箱中下载GLUI源代码并解压到合适的目录用VS2010打开"glui-2.36\src\msvc"目录下的glui.sln解决方案文件。

在“解决方案资源管理器”中右键点击“解决方案"glui"”项,点击批生成,勾选前四项,点击生成。

在“解决方案资源管理器”中右键点击“解决方案"glui"”项,点击批生成,取消选择前四项,勾选其余项,点击生成。

在"glui-2.36\src\msvc\bin"目录下可见到生成的动态链接库文件以及可执行文件。

在"glui-2.36\src\msvc\lib"目录下可见到生成的静态链接库文件。

将glui相关的头文件、静态链接库文件、动态链接库文件依次放入4.2节中所述目录下。

5、编译MeshViewer示例程序从公共邮箱中下载MeshViewer示例程序,试编译运行。

6、在示例程序中添加代码实现下述功能1)在MeshViewer.cpp文件myGlutDisplay函数的相应位置,添加绘制圆柱的代码void DrawCylinder(){//绘制圆柱体float h = 1.0f;//绘制上面的圆glBegin(GL_TRIANGLES);glNormal3f(0.0f, 0.0f, 1.0f); //确定法向for (int i = 0; i <= n; i++){//点的顺序(n,h),(0,h),(n+1,h)glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), h);glVertex3f(0, 0, h);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), h);}glEnd();//绘制下面的圆glBegin(GL_TRIANGLES);glNormal3f(0.0f, 0.0f, -1.0f); //确定法向for (int i = 0; i <= n; i++){//点的顺序(n,0),(n+1,0),(0,0)glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), -h);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), -h);glVertex3f(0, 0, 0);}glEnd();//绘制侧面glBegin(GL_QUADS);int i = 0;for (int i = 0; i <= n; i++){glNormal3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), 0);//画点的顺序v(n,0),(n,h),(n+1,h),(n+1,0)glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), -h);glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), h);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), h);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), -h);}glEnd();}2)在MeshViewer.cpp文件myGlutDisplay函数的相应位置,添加绘制圆锥的代码void DrawCone(){//绘制圆锥float h = 2.0f; //定义圆锥的高//绘制下面的圆glBegin(GL_TRIANGLES);glNormal3f(0.0f, 0.0f, -1.0f); //确定法向for (int i = 0; i <= n; i++){//点的顺序(n,0),(n+1,0),(0,0)glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), 0);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), 0);glVertex3f(0, 0, 0);}glEnd();//绘制圆锥的侧面glBegin(GL_TRIANGLES);int i = 0;for (int i = 0; i <= n; i++){//计算圆锥面的法向量Vector3 v1(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), 0);Vector3 v2(0, 0, h);Vector3 v3(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), 0);Vector3 vnormal = Cross((v3 - v2), (v2 - v1));glNormal3f(vnormal.fX,vnormal.fY,vnormal.fZ);//绘?制?顺3序ò(n,0),(0,h),(n+1,0)glVertex3f(R*cos((2 * Pi)*i / n), R*sin((2 * Pi)*i / n), 0);glVertex3f(0, 0, h);glVertex3f(R*cos((2 * Pi)*(i + 1) / n), R*sin((2 * Pi)*(i + 1) / n), 0);}glEnd();}3)从.obj文件中读取顶点数据和面数据:实现方法CObj::ReadObjFile();bool CObj::ReadObjFile(const char* pcszFileName){//读取模型文件FILE* fpFile = fopen(pcszFileName, "r"); //以只读方式打开文件if (fpFile == NULL){return false;}m_pts.clear();m_faces.clear();//将模型文件中的点和面数据分别存入m_pts和ím_faces中const int nLineLenth = 256;char szLine[nLineLenth];Point pt;Face f;while (fgets(szLine, nLineLenth, fpFile)){std::stringstream lineStream(szLine);char szType[10];lineStream >> szType;if (szType[0] == 'v' && szType[1] == '\0') //读入顶点{lineStream >> pt.pos.fX >> pt.pos.fY >> pt.pos.fZ;m_pts.push_back(pt);}else if (szType[0] == 'f' && szType[1] == '\0') //读入面{lineStream >> f.pts[0] >> f.pts[1] >> f.pts[2];f.pts[0]--;f.pts[1]--;f.pts[2]--;m_faces.push_back(f);}}fclose(fpFile);UnifyModel(); //将模型归一化ComputeNormals(); //计算法线return true;}4)将模型归一化:实现方法CObj::UnifyModel();void CObj::UnifyModel(){//模型归一化Vector3 vMax, vMin;vMax = vMin = m_pts[0].pos;for (int i = 1; i < m_pts.size(); ++i){vMin.fX = min(vMin.fX , m_pts[i].pos.fX);vMin.fY = min(vMin.fY, m_pts[i].pos.fY);vMin.fZ = min(vMin.fZ, m_pts[i].pos.fZ);vMax.fX = max(vMax.fX , m_pts[i].pos.fX);vMax.fY = max(vMax.fY, m_pts[i].pos.fY);vMax.fZ = max(vMax.fZ, m_pts[i].pos.fZ);}Vector3 center = (vMax + vMin) * 0.5;//Calculate scale rationdouble fScale;Vector3 vBounding;vBounding = vMax - vMin;fScale = vBounding.Length();fScale = 10.0 / fScale;for (int i = 0; i < m_pts.size(); ++i){Vector3& pos = m_pts[i].pos;pos = (pos - center) * fScale;}}5)计算各个三角面片的法向:实现方法CObj::ComputeFaceNormal();void CObj::ComputeFaceNormal(Face& f){//计算面f的法向量,并保存Vector3 one;Vector3 two;one = m_pts[f.pts[1]].pos - m_pts[f.pts[0]].pos;two = m_pts[f.pts[2]].pos - m_pts[f.pts[0]].pos;f.normal = Cross(one, two);//通过叉积y计算法线量f.normal.Normalize();//对法向量长度进行归一化}6)绘制读取的模型:实现函数DrawModel();void DrawModel(CObj &model){//绘制模型glBegin(GL_TRIANGLES); //开始画模型for (int i = 0; i < model.m_faces.size(); ++i){for (int j = 0; j < 3; ++j){glNormal3dv((double*)&model.m_pts[model.m_faces[i].pts[j]].normal);glVertex3dv((double*)&model.m_pts[model.m_faces[i].pts[j]].pos);}}glEnd();}7)在MeshViewer.cpp文件的myGlutMotion函数中,添加鼠标移动控制模型旋转、缩放和平移的代码;void myGlutMotion(int x, int y) //处理当鼠标键摁下时,鼠标拖动的事件{CQrot rot;if (g_xform_mode == TRANSFORM_ROTATE) //旋转{rot = g_arcball.update(x - g_windows_width / 2, g_windows_height / 2 - y);g_ObjRot = rot * g_ObjRot;}else if(g_xform_mode == TRANSFORM_SCALE) //缩放{float old_size = g_scale_size;g_scale_size *= (1 + (y - g_press_y) / 1000.0);if(g_scale_size < 0.0001){g_scale_size = 0.0001;}g_press_y = y;}else if(g_xform_mode == TRANSFORM_TRANSLATE) //平移{g_x_offset += (x - g_press_x) / 100.0;g_y_offset -= (y - g_press_y) / 100.0;g_press_x = x;g_press_y = y;}// force the redraw functionglutPostRedisplay();}五、思考你实现的模型旋转控制功能与预期表现符合吗?能够表达所有的旋转吗?为什么?圆柱和圆锥可以进行旋转。

相关主题