一、问题描述:
模型显示:从给定的off文件(ftp//Models/cube.off、horse.off)读入网格模型的顶点位置和面,显示在屏幕上
观察:(1) 上下左右方向键移动模型;
(2) x键绕x轴方向旋转模型(模型中心为不动点);
(3) y键绕y轴方向旋转模型(模型中心为不动点);
(4) z键绕z轴方向旋转模型(模型中心为不动点);
(5) s或S键缩小或放大模型(把模型拉远或拉近照相机)
二、实验代码:(这里horse.off 以及colorcube.off 的代码由于是老师给的就不放了,毕竟不是自己写的代码,而且horse.off 的代码很长,放进来整个页面都会很长)
colorcube的代码(未引入colorcube文件)
实验思路:在实验的过程中,不用GLLOOKAT 函数而是改用了glTranslatef和glScalef和glRotatef实现Cube的放大缩小,按XYZ轴旋转等功能。
/* Rotating cube with viewer movement from Chapter 5 */
/* Cube definition and display similar to rotating--cube program */
/* We use the Lookat function in the display callback to point
the viewer, whose position can be altered by the x,X,y,Y,z, and Z keys.
The perspective view is set in the reshape callback */
#include <windows.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat normals[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0},
{1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};
void polygon(int a, int b, int c , int d)
{
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glNormal3fv(normals[a]);
glVertex3fv(vertices[a]);
glColor3fv(colors[b]);
glNormal3fv(normals[b]);
glVertex3fv(vertices[b]);
glColor3fv(colors[c]);
glNormal3fv(normals[c]);
glVertex3fv(vertices[c]);
glColor3fv(colors[d]);
glNormal3fv(normals[d]);
glVertex3fv(vertices[d]);
glEnd();
}
void colorcube()
{
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
static GLdouble viewer[]= {0.0, 0.0, -5.0}; /* initial viewer location */
static GLdouble xixi[]= {1.0, 1.0, 1.0}; /* initial viewer location */
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Update viewer position in modelview matrix */
glLoadIdentity();
glTranslatef(viewer[0],viewer[1],viewer[2]);
glScalef(xixi[0],xixi[1],xixi[3]);
/* rotate cube */
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
colorcube();
glFlush();
glutSwapBuffers();
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2;
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
display();
}
void keyl(GLint k,int x, int y)
{
if(k == GLUT_KEY_UP)
{
viewer[1]+=1.0;
}
if(k == GLUT_KEY_DOWN)
{
viewer[1]-=1.0;
}
if(k == GLUT_KEY_LEFT)
{
viewer[0]-=1.0;
}
if(k == GLUT_KEY_RIGHT)
{
viewer[0]+=1.0;
}
display();
}
void keys(unsigned char key, int x, int y)
{
/* Use x, X, y, Y, z, and Z keys to move viewer */
if(key == 'x') theta[0]-= 1.0;
if(key == 'y') theta[1]-= 1.0;
if(key == 'z') theta[2]-= 1.0;
if(key == 's')
{
xixi[0]*=2;
xixi[1]*=2;
xixi[2]*=2;
}
if(key == 'S')
{
xixi[0]*=0.5;
xixi[1]*=0.5;
xixi[2]*=0.5;
}
display();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
/* Use a perspective view */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h) glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w,
2.0* (GLfloat) h / (GLfloat) w, 2.0, 20.0);
else glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h,
2.0* (GLfloat) w / (GLfloat) h, 2.0, 20.0);
/* Or we can use gluPerspective */
/* gluPerspective(45.0, w/h, -10.0, 10.0); */
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutSpecialFunc(keyl);
glutKeyboardFunc(keys);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
实验结果截图:
图像显示
绕X,Y,Z三轴的旋转:
Cube的移动:
放大缩小的功能:
(2)horse的代码
实验思路:整体思路与实验一相通,只是在读取horse.off时候花了很多时间去寻找方法,其次还需要自己去计算出normal法向量矩阵。
实验代码:
/* Rotating cube with viewer movement from Chapter 5 */
/* Cube definition and display similar to rotating--cube program */
/* We use the Lookat function in the display callback to point
the viewer, whose position can be altered by the x,X,y,Y,z, and Z keys.
The perspective view is set in the reshape callback */
#include <windows.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <fstream>
#include <string>
int nFaces, nVertices, nEdges;
GLfloat vertices[1000][3];
GLfloat normals[1000] [3];
int faces[10000][3];
void load_off(char* filename)
{
std::ifstream fin;
fin.open(filename);
std::string off;
std::getline(fin, off);//读入首行字符串"OFF"
fin>>nVertices>>nFaces>>nEdges; //读入点、面、边数目
GLfloat x, y, z;
for (int i=0; i<nVertices; i++)
{
fin>> x >> y >> z; //逐行读入顶点坐标;
vertices[i][0]=x;
vertices[i][1]=y;
vertices[i][2]=z;
}
int n, vid1, vid2, vid3;
for (int i=0; i<nFaces; i++)
{
fin>> n >> vid1 >> vid2 >>vid3; //逐行读入面的顶点序列;
faces[i][0]=vid1;
faces[i][1]=vid2;
faces[i][2]=vid3;
}
fin.close();
}
void get_normals(int a, int b, int c)
{
GLfloat tmp1[3], tmp2[3];
for (int i = 0; i < 3; ++i)
{
tmp1[i] = vertices[b][i] - vertices[a][i];
tmp2[i] = vertices[c][i] - vertices[a][i];
}
normals[a][0] -= tmp1[1] * tmp2[2] - tmp1[2] * tmp2[1];
normals[a][1] -= tmp1[2] * tmp2[0] - tmp1[0] * tmp2[2];
normals[a][2] -= tmp1[0] * tmp2[1] - tmp1[1] * tmp2[0];
}
//从文件中获得数据
GLfloat colors[][3]= {0.0,0.0,0.0,255.0,255.0,255.0};
void polygon()
{
for (int i = 0; i < nFaces; ++i)
{
glColor3fv(colors[1]);
glBegin(GL_POLYGON);
for (int j = 0; j < 3; ++j)
{
glNormal3fv(normals[faces[i][j]]);
glVertex3fv(vertices[faces[i][j]]);
}
glEnd();
glColor3fv(colors[0]);
glBegin(GL_LINES);
glVertex3fv(vertices[faces[i][0]]);
glVertex3fv(vertices[faces[i][1]]);
glEnd();
glColor3fv(colors[0]);
glBegin(GL_LINES);
glVertex3fv(vertices[faces[i][1]]);
glVertex3fv(vertices[faces[i][2]]);
glEnd();
glColor3fv(colors[0]);
glBegin(GL_LINES);
glVertex3fv(vertices[faces[i][2]]);
glVertex3fv(vertices[faces[i][0]]);
glEnd();
}
}
void colorhorse()
{
polygon();
}
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
static GLdouble viewer[]= {0.0, 0.0, -5.0}; /* initial viewer location */
static GLdouble xixi[]= {1.0, 1.0, 1.0}; /* initial viewer location */
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Update viewer position in modelview matrix */
glLoadIdentity();
glTranslatef(viewer[0],viewer[1],viewer[2]);
glScalef(xixi[0],xixi[1],xixi[3]);
/* rotate cube */
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
colorhorse();
glFlush();
glutSwapBuffers();
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2;
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
display();
}
void keyl(GLint k,int x, int y)
{
if(k == GLUT_KEY_UP)
{
viewer[1]+=1.0;
}
if(k == GLUT_KEY_DOWN)
{
viewer[1]-=1.0;
}
if(k == GLUT_KEY_LEFT)
{
viewer[0]-=1.0;
}
if(k == GLUT_KEY_RIGHT)
{
viewer[0]+=1.0;
}
display();
}
void keys(unsigned char key, int x, int y)
{
/* Use x, X, y, Y, z, and Z keys to move viewer */
if(key == 'x') theta[0]-= 1.0;
if(key == 'y') theta[1]-= 1.0;
if(key == 'z') theta[2]-= 1.0;
if(key == 's')
{
xixi[0]*=2;
xixi[1]*=2;
xixi[2]*=2;
}
if(key == 'S')
{
xixi[0]*=0.5;
xixi[1]*=0.5;
xixi[2]*=0.5;
}
display();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
/* Use a perspective view */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h) glFrustum(-2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w,
2.0* (GLfloat) h / (GLfloat) w, 2.0, 20.0);
else glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h,
2.0* (GLfloat) w / (GLfloat) h, 2.0, 20.0);
/* Or we can use gluPerspective */
/* gluPerspective(45.0, w/h, -10.0, 10.0); */
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char **argv)
{
load_off("C:\\horse.off");
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorhorse");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutSpecialFunc(keyl);
glutKeyboardFunc(keys);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
实验结果截图:
1.图像显示:
2.按X,Y,Z三轴的旋转
4.上下左右移动:
5.放大缩小功能:
六、实验反思
在实验过程中,通过查找资料,替换掉了gllookat函数,而用了glTranslatef和glScalef和glRotatef函数实现的放大缩小,按XYZ轴旋转等功能。在实验二中了解了glNormal3fv和glVertex3fv和glColor3fv函数的作用之后才得以画出马的图形,后面的函数并不需要改变。