本文最后更新于2020年11月15日,已超过 3 个月没更新!

图形学实验三:基于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()函数是绘制三个顶点坐标,原函数分别绘制三个顶点和四个顶点,绘制出标准的三角形和矩形,在原来的顶点坐标进行修改,实现不同形状三角形和四边形的绘制。


疏影横斜水清浅,暗香浮动月黄昏