# 图形学实验三:基于 OpenGL 的图形学编程初探

# 原 OpenGL 示例代码简单绘制图形:

# cube.cpp

#include <windows.h>
#include <glut.h>
void init(void) 
{
  glClearColor (0.0, 0.0, 0.0, 0.0);
  glShadeModel (GL_FLAT);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *   
 Anything you want to display on the screen, draw it here. * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *  Clear the screen.  Set the current color to white.
 *  Draw the wire frame cube. 
 */
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    glLoadIdentity ();	/*  clear the matrix	*/
//--------------- you can define your own transformation-----------
    glTranslatef (1.0, 0.0, -5.0);	 
    glScalef (1.0, 1.0, 2.0);	 
//---------------- you can draw something else here-----------
    glutWireCube (1.0);  /*  draw the cube	*/
    glFlush();
}
/*  Called when the window is first opened and whenever 
 *  the window is reconfigured (moved or resized).
 */
void reshape (int w, int h)
{
	/*  define the projection  */
    glMatrixMode (GL_PROJECTION); 
    glLoadIdentity ();
    glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);	 
    glMatrixMode (GL_MODELVIEW);	/*  back to modelview matrix	*/
    glViewport (0, 0, w, h);	/*  define the viewport	*/
}
/*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   //define size and the relative positon of the applicaiton window on the display
   glutInitWindowSize (500, 500); 
   glutInitWindowPosition (100, 100);
 	//init the defined window with "argv[1]" as topic showed on the top the window
   glutCreateWindow (argv[0]);
	// opengl setup
   init ();
	//define callbacks
   glutDisplayFunc(display); 
   glutReshapeFunc(reshape);
   //enter the loop for display
   glutMainLoop();
   return 0;
}

# lines.cpp

/*  
 *  lines.c  
 *  This program demonstrates different line stipples and widths.
 */
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <glut.h>
#define	drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
	glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
void myinit (void) {
    /*  background to be cleared to black	*/
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
}
void display(void)
{
    int i;
    glClear (GL_COLOR_BUFFER_BIT);
/*  draw all lines in white	*/
    glColor3f (1.0, 1.0, 1.0);
/*  in 1st row, 3 lines drawn, each with a different stipple	*/
    glEnable (GL_LINE_STIPPLE);
    glLineStipple (1, 0x0101);	/*  dotted	*/
    drawOneLine (50.0, 125.0, 150.0, 125.0);
    glLineStipple (1, 0x00FF);	/*  dashed	*/
    drawOneLine (150.0, 125.0, 250.0, 125.0);
    glLineStipple (1, 0x1C47);	/*  dash/dot/dash	*/
    drawOneLine (250.0, 125.0, 350.0, 125.0);
/*  in 2nd row, 3 wide lines drawn, each with different stipple	*/
    glLineWidth (5.0);
    glLineStipple (1, 0x0101);
    drawOneLine (50.0, 100.0, 150.0, 100.0);
    glLineStipple (1, 0x00FF);
    drawOneLine (150.0, 100.0, 250.0, 100.0);
    glLineStipple (1, 0x1C47);
    drawOneLine (250.0, 100.0, 350.0, 100.0);
    glLineWidth (1.0);
/*  in 3rd row, 6 lines drawn, with dash/dot/dash stipple,	*/
/*  as part of a single connect line strip			*/
    glLineStipple (1, 0x1C47);
    glBegin (GL_LINE_STRIP);
    for (i = 0; i < 7; i++)
	glVertex2f (50.0 + ((GLfloat) i * 50.0), 75.0);
    glEnd ();
/*  in 4th row, 6 independent lines drawn,	*/
/*  with dash/dot/dash stipple			*/
    for (i = 0; i < 6; i++) {
	drawOneLine (50.0 + ((GLfloat) i * 50.0), 
	    50.0, 50.0 + ((GLfloat)(i+1) * 50.0), 50.0);
    }
/*  in 5th row, 1 line drawn, with dash/dot/dash stipple	*/
/*  and repeat factor of 5			*/
    glLineStipple (5, 0x1C47);
    drawOneLine (50.0, 25.0, 350.0, 25.0);
    glFlush ();
}
/*  Called when the window is first opened and whenever 
 *  the window is reconfigured (moved or resized).
 */
void  myReshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluOrtho2D (0.0, 400.0, 0.0, 150.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();	
}
/*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
	   glutInit(&argc, argv);
	   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
	      //define size and the relative positon of the applicaiton window on the display
	   glutInitWindowSize (400, 150); 
	   glutInitWindowPosition (0, 0);
	   //init the defined window with "argv[1]" as topic showed on the top the window
	   glutCreateWindow (argv[0]);
	   // opengl setup
	   myinit ();
	   //define callbacks
	   glutReshapeFunc(myReshape);		  
	   glutDisplayFunc(display); 
	   //enter the loop for display
	   glutMainLoop();
	   return 0;	   
}

# aim.cpp

/*
 *  aim.c
 *  This program calculates the fovy (field of view angle
 *  in the y direction), by using trigonometry, given the
 *  size of an object and its size.
 */
#include <windows.h>
#include <stdio.h>   
#include <math.h>
#include <glut.h>
void myinit (void) {
    glShadeModel (GL_FLAT);
}
/*  Clear the screen.  Set the current color to white.
 *  Draw the wire frame cube and sphere.
 */
void   display (void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
	//about front and back facing facets and facet cullig
//  	glCullFace(GL_BACK);
// 	glCullFace(GL_FRONT);
  	glEnable(GL_CULL_FACE);
    glLoadIdentity ();
/*	glTranslatef() as viewing transformation	*/
    glTranslatef(-1.5f,0.0f,-15.0f);
	glBegin(GL_TRIANGLES); // Drawing Using Triangles
	glVertex3f( 1.2f, 1.0f, 0.0f); // Top
	glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
	glVertex3f( 1.0f,-1.0f, 5.0f); // Bottom Right
	glEnd();
	//definition of front facing polygon
 	glFrontFace(GL_CW);
    glTranslatef(3.0f,0.0f,0.0f);
	glBegin(GL_QUADS); // Draw A Quad
	glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left
	glVertex3f( 1.0f, 1.0f, 2.0f); // Top Right
	glVertex3f( 1.2f,-1.0f, -1.0f); // Bottom Right
	glVertex3f(-0.5f,-1.2f, 1.0f); // Bottom Left
	glEnd(); // Done Drawing The Quad
    glFlush();
}
#define PI  3.1415926535
/*  atan2 () is a system math routine which calculates
 *  the arctangent of an angle, given length of the 
 *  opposite and adjacent sides of a right triangle.
 *  atan2 () is not an OpenGL routine.
 */
GLdouble calculateAngle (double size, double distance)
{
    GLdouble radtheta, degtheta;
    
    radtheta = 2.0 * atan2 (size/2.0, distance);
    degtheta = (180.0 * radtheta) / PI;
    printf ("degtheta is %lf\n", degtheta);
    return ((GLdouble) degtheta);
}
/*  Called when the window is first opened and whenever 
 *  the window is reconfigured (moved or resized).
 */
void  myReshape(int w, int h)
{
    GLdouble theta;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    theta = calculateAngle (2.0, 5.0);
    gluPerspective(theta, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop		
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
void main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   //define size and the relative positon of the applicaiton window on the display
   glutInitWindowSize (500, 500); 
   glutInitWindowPosition (100, 100);
 	//init the defined window with "argv[1]" as topic showed on the top the window
   glutCreateWindow (argv[0]);
	// opengl setup
   myinit ();
	//define callbacks
   glutReshapeFunc(myReshape);
   glutDisplayFunc(display); 
  //enter the loop for display
   glutMainLoop();
}

# 实验报告

# 实验内容

  1. 解压 GlutLib.zip 文件,并按照 “glut 库安装.txt” 中的说明,安装 glut 库。
  2. 阅读文档 CreateProject.txt,建立自己的工程文件。
  3. 基于给定的源代码 cube.c 等分别建立工程文件,并编译执行。
  4. 仔细阅读程序注释,了解利用 OpenGL 进行计算机图形学编程的框架。
  5. 基于 aim.cpp、lines.cpp 两个源文件分别建立工程文件,调试通过并执行。
  6. 通过对给定代码进行局部修改,进一步了解部分函数的意义。
  7. 选作:基于 glut 和 OpenGL 实现用橡皮筋交互定义矩形的功能。

# 实验目的

  1. 掌握如何建立包含 OpenGL 库函数的工程文件;
  2. 熟悉如何利用 glut 进行 OpenGL 应用程序的窗口及输入、输出管理等;
  3. 熟悉 OpenGL 的函数。

# 实验要求

  1. 通过对给定程序的试运行,解释以下几个函数的作用及各参数的意义:
    glTranslatef(float x, float y, float z);
    glVertex3f(float x, float y, float z);
    glColor3f (float a, float b, float c);
    glLineWidth (float a);
    glutInitWindowSize (int a,int b);
    glutInitWindowPosition (int a,int b);
  2. 分析以下两个函数的区别:
    glVertex3f(float x, float y, float z);
    glVertex2f(float x, float y);
  3. 说明如何利用 glut 进行 OpenGL 应用程序的窗口及输入、输出管理。
  4. 分别展示对三个代码的修改,以及执行结果,对比与原来代码执行结果的不同,并说明原因(展示 2-3 个即可)。

# 实验结果

  1. 通过对给定程序的试运行,解释以下几个函数的作用及各参数的意义:
    glTranslatef(float x, float y, float z);
    作用:平移变换函数,
    参数意义:x,y,z 表示 x y z 轴
    glVertex3f(float x, float y, float z);
    作用:绘制三维顶点坐标,
    参数意义:三维坐标的 x y z 值
    glColor3f (float a, float b, float c);
    作用:颜色设置函数
    参数意义:a b c 表示 RGB 值
    glLineWidth (float a);
    作用:设置线段宽度,
    参数意义: a 表示宽度值
    glutInitWindowSize (int a,int b);
    作用:设置窗口大小
    参数意义: a b 表示窗口长宽值
    glutInitWindowPosition (int a,int b);
    作用:设置窗口位置
    参数意义: a,b 表示窗口左上角相对于桌面的坐标

  2. 分析以下两个函数的区别:
    glVertex3f(float x, float y, float z);
    glVertex2f(float x, float y);
    回答: glVertex3f 表示三维的坐标, glVertex2f 表示二维坐标,二维平面中 glVertex3f 把三维坐标映射到二维坐标系。由于屏幕是二维的,每个屏幕上的点对应于三维空间中的一条直线。反投影时提供的 z 坐标就是决定到底需要这直线上的哪一个点。

  3. 说明如何利用 glut 进行 OpenGL 应用程序的窗口及输入、输出管理。

    回答:
    (1)鼠标的输入输出管理:
    使用函数 glutMouseFunc() 就可以检测鼠标的输入,函数为
    void glutMouseFunc(void(*func)(int button,int state,int x,int y));
    参数 func :处理鼠标 click 事件的函数的函数名。
    第一个参数可能是以下几个中的一个:

    GLUT_LEFT_BUTTON   		//鼠标左键
    GLUT_MIDDLE_BUTTON 		//鼠标中键
    GLUT_RIGHT_BUTTON  		//鼠标右键
    // 下面两个是重构的OpenGL库函数中带的值,表示滚轮上下滚动的状态
    GLUT_WHEEL_UP
    GLUT_WHEEL_DOWN
    第二个参数可能是以下几个中的一个:
    GLUT_DOWN
    GLUT_UP
    //表示鼠标键的按下与放开。
    

    (2)键盘的输入输出管理
    使用函数 glutKeyboardFunc () 就可以检测键盘的输入,函数为:
    void glutKeyboardFunc(void(*func)(unsigned char key,int x,int y));
    参数:
    func : 处理普通按键消息的函数的名称。如果传递 NULL ,则表示 GLUT 忽略普通按键消息。
    第一个形参表示按下的键的 ASCII 码,另外两个表示键盘按下时鼠标的位置。
    (3)glut 的窗口管理函数:

    glutCreateWindow();
    glutCreateSubWindow();
    glutHideWindow();
    glutShowWindow();
    glutSetWindowTitle();
    glutPostRedisplay();
    glutSwapBuffers();
    glutFullScreen();
    glutPositionWindow();
    glutReshapeWindow();
    glutSetWindow();
    glutGetWindow();
    glutPopWindow();
    glutPushWindow();
    glutDestroyWindow();
    glutIconifyWindow();
    glutSetCursor();
    

    (4)输出管理
    glutDisplayFunc() 的使用方式是 glutDisplayFunc(display);
    void display(void) 函数为绘图函数。
    glutDisplayFunc(&display) 在程序运行时是自动调用的,即程序会自动调用 display 函数重绘窗口。调用的时机有以下几种:
    1. 窗口内容绘制
    2. 窗口大小改变
    3. 窗口重绘
    当然,这个函数不会单独出现,比如 :
    glutReshapeFunc(reshape); 函数先控制窗口大小改变时的操作。

  4. 分别展示对三个代码的修改,以及执行结果,对比与原来代码执行结果的不同,并说明原因(展示 2-3 个即可)。

    回答:

    (1)cube.sln
    原输出:

    imgbed.cn图床

    修改数据:
    glTranslatef (0.0, 0.0, -5.0);
    glScalef (1.0, 2.0, 1.0);
    改成:
    glTranslatef (1.0, 0.0, -5.0);
    glScalef (1.0, 1.0, 2.0);
    结果输出:

    imgbed.cn图床

    原因:
    glTranslatef (0.0, 0.0, -5.0); 将 X 轴平移了 1,glScalef (1.0, 2.0, 1.0); 将 y 轴缩放为原来的 1/2 ,z 轴伸长为原来的 2 倍,得到结果。

(2)aim.sln
原输出:

imgbed.cn图床

修改数据:

glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left

改成:

glVertex3f( 1.2f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 5.0f); // Bottom Right
glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left
glVertex3f( 1.0f, 1.0f, 2.0f); // Top Right
glVertex3f( 1.2f,-1.0f, -1.0f); // Bottom Right
glVertex3f(-0.5f,-1.2f, 1.0f); // Bottom Left

结果输出:

imgbed.cn图床

原因:
glVertex3f() 函数是绘制三个顶点坐标,原函数分别绘制三个顶点和四个顶点,绘制出标准的三角形和矩形,在原来的顶点坐标进行修改,实现不同形状三角形和四边形的绘制。