2024年4月1日发(作者:)

实验5 OpenGL模型视图变换

一、实验目的:

理解掌握OpenGL程序的模型视图变换。

二、实验内容:

(1)阅读实验原理,运行示范实验代码,理解掌握OpenGL程序的模型视图变换;

(2)根据示范代码,尝试完成实验作业;

三、实验原理:

在代码中,视图变换必须出现在模型变换之前,但可以在绘图之前的任何时候执行投

影变换和视口变换。

y()程序中绘图函数潜在的重复性强调了:在指定的视图变换之前,应该使用

glLoadIdentity()函数把当前矩阵设置为单位矩阵。

2.在载入单位矩阵之后,使用gluLookAt()函数指定视图变换。如果程序没有调用

gluLookAt(),那么照相机会设定为一个默认的位置和方向。在默认的情况下,照相机位于

原点,指向Z轴负方向,朝上向量为(0,1,0)。

3.一般而言,display()函数包括:视图变换 + 模型变换 + 绘制图形的函数(如

glutWireCube())。display()会在窗口被移动或者原来先遮住这个窗口的东西被一开时,被

重复调用,并经过适当变换,保证绘制的图形是按照希望的方式进行绘制。

4.在调用glFrustum()设置投影变换之前,在reshape()函数中有一些准备工作:视口

变换 + 投影变换 + 模型视图变换。由于投影变换,视口变换共同决定了场景是如何映射

到计算机的屏幕上的,而且它们都与屏幕的宽度,高度密切相关,因此应该放在reshape()

中。reshape()会在窗口初次创建,移动或改变时被调用。

OpenGL中矩阵坐标之间的关系:物理坐标*模型视图矩阵*投影矩阵*透视除法*规范

化设备坐标——〉窗口坐标

(1)视图变换函数gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0,)设

置照相机的位置。把照相机放在(0,0,5),镜头瞄准(0,0,0),朝上向量定为(0,

1,0)朝上向量为照相机指定了一个唯一的方向。如果没有调用gluLookAt,照相机就设

定一个默认的位置和方向,在默认情况下,照相机位于原点,指向Z轴的负方向,朝上向

量为(0,1,0)glLoadIdentity()函数把当前矩阵设置为单位矩阵。

(2)使用模型变换的目的是设置模型的位置和方向

(3)投影变换,指定投影变换类似于为照相机选择镜头,可以认为这种变换的目的是

确定视野,并因此确定哪些物体位于视野之内以及他们能够被看到的程度。

除了考虑视野之外,投影变换确定物体如何投影到屏幕上,OpenGL提供了两种基本

类型的投影,1、透视投影:远大近小;2、正投影:不影响相对大小,一般用于建筑和CAD

应用程序中

(4)视口变换视口变换指定一个图象在屏幕上所占的区域

(5)绘制场景

四、实验代码:

#include

#include

static int year = 0, day = 0;

void init(void)

{

glClearColor (0.0, 0.0, 0.0, 0.0);

glShadeModel (GL_FLAT);

}

void display(void)

{

glClear (GL_COLOR_BUFFER_BIT);

glColor3f (1.0, 1.0, 1.0);

glPushMatrix();

glutWireSphere(1.0, 20, 16); /* draw sun */

glRotatef ((GLfloat) year, 0.0, 1.0, 0.0);

glTranslatef (2.0, 0.0, 0.0);

glRotatef ((GLfloat) day, 0.0, 1.0, 0.0);

glutWireSphere(0.2, 10, 8); /* draw smaller planet */

glPopMatrix();

glutSwapBuffers();

}

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

}

void keyboard (unsigned char key, int x, int y)

{

switch (key) {

case 'd':

day = (day + 10) % 360;

glutPostRedisplay();

break;

case 'D':

day = (day - 10) % 360;

glutPostRedisplay();

break;

case 'y':

year = (year + 5) % 360;

glutPostRedisplay();

break;

case 'Y':

year = (year - 5) % 360;

glutPostRedisplay();

break;

case 27:

exit(0);

break;

default:

break;

}

}

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutKeyboardFunc(keyboard);

glutMainLoop();

return 0;

}

五、结果截屏:

实验六:Bezier曲线生成

一、实验目的:

了解曲线的生成原理,掌握几种常见的曲线生成算法,利用VC+OpenGL实现Bezier

曲线生成算法。

二、实验内容:

(1) 结合示范代码了解曲线生成原理与算法实现,尤其是Bezier曲线;

(2) 调试、编译、修改示范程序。

三、实验原理:

Bezier曲线是通过一组多边形折线的顶点来定义的。如果折线的顶点固定不变,则由

其定义的Bezier曲线是唯一的。在折线的各顶点中,只有第一点和最后一点在曲线上且作

为曲线的起始处和终止处,其他的点用于控制曲线的形状及阶次。曲线的形状趋向于多边

形折线的形状,要修改曲线,只要修改折线的各顶点就可以了。因此,多边形折线又称Bezier

曲线的控制多边形,其顶点称为控制点。

三次Bezier曲线,有四个控制点,其数学表示如下:

四、实验代码:

#include

#include

#include

#include

using namespace std;

struct Point {

int x, y;

};

Point pt[4], bz[11];

vector vpt;

bool bDraw;

int nInput;

void CalcBZPoints()

{

float a0,a1,a2,a3,b0,b1,b2,b3;

a0=pt[0].x;

a1=-3*pt[0].x+3*pt[1].x;

a2=3*pt[0].x-6*pt[1].x+3*pt[2].x;

a3=-pt[0].x+3*pt[1].x-3*pt[2].x+pt[3].x;

b0=pt[0].y;

b1=-3*pt[0].y+3*pt[1].y;

b2=3*pt[0].y-6*pt[1].y+3*pt[2].y;

b3=-pt[0].y+3*pt[1].y-3*pt[2].y+pt[3].y;

float t = 0;

float dt = 0.01;

for(int i = 0; t<1.1; t+=0.1, i++)

{

bz[i].x = a0+a1*t+a2*t*t+a3*t*t*t;

bz[i].y = b0+b1*t+b2*t*t+b3*t*t*t;

}

}

void ControlPoint(vector vpt)

{

glPointSize(2);

for(int i=0; i<(); i++)

{

glBegin (GL_POINTS);

glColor3f (1.0f, 0.0f, 0.0f); glVertex2i (vpt[i].x,vpt[i].y);

glEnd ();

}

}

void PolylineGL(Point *pt, int num)

{

glBegin (GL_LINE_STRIP);

for(int i=0;i

{

glColor3f (1.0f, 1.0f, 1.0f);

glVertex2i (pt[i].x,pt[i].y);

}

glEnd ();

}

void myDisplay()

{

glClear(GL_COLOR_BUFFER_BIT);

glColor3f (1.0f, 1.0f, 1.0f);

if (() > 0) {

ControlPoint(vpt);

}

if(bDraw)

{

PolylineGL(pt, 4);

CalcBZPoints();

PolylineGL(bz, 11);

}

glFlush();

}

void Init()

{

glClearColor(0.0, 0.0, 0.0, 0.0);

glShadeModel(GL_SMOOTH);

printf("Please Click left button of mouse to input control point of Bezier

Curve!n");

}

void Reshape(int w, int h)

{

glViewport(0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);

}

void mouse(int button, int state, int x, int y)

{

switch (button)

{

case GLUT_LEFT_BUTTON:

if (state == GLUT_DOWN)

{

if (nInput == 0)

{

pt[0].x = x;

pt[0].y = 480 - y;

nInput = 1;

();

_back(pt[0]);

bDraw = false;

glutPostRedisplay();//

}

else if (nInput == 1)

{

pt[1].x = x;

pt[1].y = 480 - y;

_back(pt[1]);

nInput = 2;

glutPostRedisplay();//

}

else if (nInput == 2)

{

pt[2].x = x;

pt[2].y = 480 - y;

_back(pt[2]);

nInput = 3;

glutPostRedisplay();//

}

else if (nInput == 3)

{

pt[3].x = x;

pt[3].y = 480 - y;

bDraw = true;

_back(pt[3]);

nInput = 0;

glutPostRedisplay();//

}

}

break;

default:

break;

}

}

int main(int argc, char *argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);

glutInitWindowPosition(100, 100);

glutInitWindowSize(640, 480);

glutCreateWindow("Hello World!");

Init();

glutDisplayFunc(myDisplay);

glutReshapeFunc(Reshape);

glutMouseFunc(mouse);

glutMainLoop();

return 0;

}

五、结果截屏:

实验7 OpenGL光照

一.实验目的:

了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效

果。

二.实验内容:

(1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验不同的光照

与材质系数;

(2)运行示范代码1,了解光照与材质函数使用。

三.实验原理:

为在场景中增加光照,需要执行以下步骤:

(1) 设置一个或多个光源,设定它的有关属性;

(2) 选择一种光照模型;

(3) 设置物体的材料属性。

四、实验代码:

#include

#include

// Initialize material property, light source, lighting model, and depth buffer.

void init(void)

{

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess[] = { 50.0 };

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat Light_Model_Ambient[] = { 0.2 , 0.2 , 0.2 , 1.0 }; //

glClearColor (0.0, 0.0, 0.0, 0.0);

glShadeModel (GL_SMOOTH);

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);

glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);

glLightModelfv( GL_LIGHT_MODEL_AMBIENT , Light_Model_Ambient ); //

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

}

void display(void)

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//glutSolidSphere (1.0, 20, 16);

glutSolidTeapot(0.5);

glFlush ();

}

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,

1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);

else

glOrtho (-1.5*(GLfloat)w/(GLfloat)h,

1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMainLoop();

return 0;

}

五、结果截屏:

实验8 OpenGL交互

一、实验目的:

理解掌握一个OpenGL程序的常见交互方法。

二、实验内容:

(1) 运行示范实验代码1,掌握程序鼠标交互方法,尝试为其添加键盘与菜单控制,

实现同样功能;

(2)运行示范实验代码2,掌握程序鼠标坐标获取与绘图方法,尝试为其添加绘制直

线功能;

(3)结合上述两步,能否实现通过鼠标右键菜单切换实现一个简单的绘图程序,可以

绘制直线、三角形、正方形等常见图形?

三、实验原理:

要想在OpenGL中处理鼠标事件非常的方便,GLUT已经为我们的注册好了函数,只

要我们提供一个方法。使用函数glutMouseFunc,就可以帮我们注册我们的函数,这样当

发生鼠标事件时就会自动调用我们的方法。

函数的原型是:

void glutMouseFunc(void(*func)(int button,int state,int x,int y));

参数:func:处理鼠标click事件的函数的函数名。

从上面可以看到,处理鼠标单击事件的函数,一定有4个参数。第一个参数表明哪个

鼠标键被按下或松开,这个变量可以是下面的三个值中的一个:

GLUT_LEFT_BUTTON

GLUT_MIDDLE_BUTTON

GLUT_RIGHT_BUTTON

第二个参数表明,函数被调用发生时,鼠标的状态,也就是是被按下,或松开,可能

取值如下:

GLUT_DOWN

GLUT_UP

当函数被调用时,state的值是GLUT_DOWN,那么程序可能会假定将会有个

GLUT_UP事件,甚至鼠标移动到窗口外面,也如此。然而,如果程序调用glutMouseFunc

传递NULL作为参数,那么GLUT将不会改变鼠标的状态。剩下的两个参数(x,y)提供了

鼠标当前的窗口坐标(以左上角为原点)。

四、实验代码:

#include

#include

#include

#define DEGREES_TO_RADIANS 3.14159/180.0

static GLfloat spin = 0.0;

GLfloat x = 0.0;

GLfloat y = 0.0;

GLfloat size = 50.0;

GLfloat angle = 2.0;

GLsizei wh = 500, ww = 500;

void square()

{

glBegin(GL_QUADS);

glVertex2f(x,y);

glVertex2f(-y,x);

glVertex2f(-x,-y);

glVertex2f(y,-x);

glEnd();

}

void spinDisplay(void)

{

spin = spin + 2.0;

if (spin > 360.0) spin = spin - 360.0;

x=125.0 * cos(DEGREES_TO_RADIANS*spin);

y=125.0 * sin(DEGREES_TO_RADIANS*spin);

glutPostRedisplay();

}

void mydisplay()

{

glClear(GL_COLOR_BUFFER_BIT);

glColor3f(1.0, 1.0, 1.0);

square();

glutSwapBuffers();

}

void init()

{

glClearColor (0.0, 0.0, 0.0, 1.0);

}

void myreshape(GLint w, GLint h) {

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glOrtho(-w/2, w/2, -h/2, h/2, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);

ww = w;

wh = h;

}

void mymouse(GLint button, GLint state, GLint wx, GLint wy)

{

if(button ==GLUT_RIGHT_BUTTON && state == GLUT_DOWN)

exit(0);

if(button ==GLUT_LEFT_BUTTON && state == GLUT_DOWN)

glutIdleFunc(spinDisplay);

if(button== GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)

glutIdleFunc(NULL);

}

void main(int argc, char** argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

glutInitWindowSize(500,500);

glutInitWindowPosition(0,0);

glutCreateWindow("double");

init();

glutDisplayFunc(mydisplay);

glutReshapeFunc(myreshape);

glutMouseFunc(mymouse);

glutIdleFunc(spinDisplay);

glutMainLoop();

}

五、结果示例: