计算机图形学第二次上机实验 课程实验报告
写在前面:这是我的图形学上机报告,代码都是自己写的,实测通过,查阅了许多资料,现以链接的形式给出
若遇到其他问题,希望大家多动手多查资料,不要蒙混过关,这样才能有收获。
最后希望这份报告能够帮到大家~
目录
一、实验目的
- 掌握配置glut库的步骤
- 测试运行示例代码
- 掌握并编写中点线算法和中点圆算法
二、实验环境
1.codeblocks-17.12
2.Windows10 SDK 10.0.17134.0
三、实验内容
1.立方体放缩变换
问题重述:利用OpenGL实现一个立方体关于参考点(10.0,20.0,10.0)进行放缩变换,放缩因子为(2.0,1.0,0.5)。
为了使放缩效果更佳,我将整个图形进行了旋转,又由于矩阵堆栈是先进先出的,故变换代码框架为:
glRotatef(45,1,1,1);//绕着向量(1,1,1)所指定的轴旋转45°
glPushMatrix();//保存矩阵状态
glTranslatef(10,20,10);//从原点平移到原处,T2
glPushMatrix();
glScalef(2,1,0.5);//放缩变换,S
glPushMatrix();
glTranslatef(-10,-20,-10);//从当前平移至原点,T1
glPushMatrix();
glColor3f(1.0,0.0,0.0);
glutWireCube(10.0);
运行效果:
变换前
变换后
2.对称变换
问题重述:利用OpenGL实现一个矩形关于y=x+5对称的新图形。
变换的关键就是先通过平移将对称轴经过原点,再旋转与坐标轴平行。进行对称变换,然后再变换回去。
主要变换代码如下
glTranslatef(0,5,0);//T2,y平移5个单位
glPushMatrix();
glRotated(45,0,0,1);//R2,逆时针旋转45度
glPushMatrix();
glScaled(1,-1,1);//S,放缩变换
glPushMatrix();
glRotated(-45,0,0,1);//R1 逆顺时针旋转45度,与x轴重合
glPushMatrix();
glTranslated(0,-5,0);//T1 y平移-5个单位
glPushMatrix();
glColor3f(1,0,0);
glRectf(-5,10,0,50);//x1=T2*R2*S*R1*T1*x
注意矩阵堆栈是先进先出即可。
运行结果为
3.键盘回调函数实现三角形旋转
问题重述:通过定义键盘回调函数,每按一次空格键,让三个点依次完成画点、画线、画三角形、让三角形平移和缩放,并让三角形沿三角形中心旋转起来。
问题的关键在于注册回调函数以及如何使三角形旋转,由于问题较为复杂,我将分段说明。
3.1定义全局变量以及模式
需要使用的全局变量为
int currentMode = 0;//当前模式数
int enable=0;//是否旋转
int angle = 0; //当前旋转角度
int step = 1; //每次的角度递增值
const int ModeNums = 7;//模式总数
窗口回调函数RenderScene定义各个模式为
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
switch(currentMode)
{
case 0:
displayc();//画点
glPointSize(4);
glBegin(GL_POINTS);
glColor3f(0,1.0,0.0);
break;
case 1:displayc();//画开折线
glBegin(GL_LINE_STRIP);
glColor3f(1.0,0,0.0);
break;
case 2: displayc();//画闭折线
glBegin(GL_LINE_LOOP);
glColor3f(0.0,0.0,1.0);
break;
case 3: displayc();//画填充三角形
glBegin(GL_TRIANGLES);
glColor3f(1.0,0,1.0);
break;
case 4:displayc();//平移
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslated(2,2,0);
glBegin(GL_TRIANGLES);
glColor3f(0,0,0);
break;
case 5:displayc();//放缩
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScaled(1.5,1.5,1);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
break;
case 6:
Rotate();//旋转
break;
}
glVertex2f( -6.0, -3.0 );
glVertex2f( 4.0, -4.0 );
glVertex2f( 2.0, 7.0 );
glEnd();
glFlush();
glutSwapBuffers();
glLoadIdentity();
if(enable==1)
glutPostRedisplay();
}
一共有7个模式。
3.2键盘回调函数
对于字符值键盘回调函数,可以用
glutKeyboardFunc(myKey); //为当前窗口设置键盘回调函数。
进行注册,其实现为:
void myKey( unsigned char key, int x, int y)
//响应ASCII对应键,鼠标的当前x和y位置也被返回。
{
switch(key)
{
case ' ': currentMode = (currentMode+1)%ModeNums;
glutPostRedisplay();
break;
case 'r':enable=1;
glutPostRedisplay();
break;
case 's':enable=0;
glutPostRedisplay();
break;
case 27: exit(-1);
}
}
对于上下左右特殊按键的键盘回调函数,可以用
glutSpecialFunc(SpecialKey);
进行注册,其实现为:
void SpecialKey(int key,int x,int y)
{
switch(key)
{
case GLUT_KEY_UP:
step++;
break;
case GLUT_KEY_DOWN:
step--;
break;
}
}
3.3实现三角形的旋转
3.3.1初始化双缓冲区
之前我没有注意到自己仅仅使用了单缓冲区,导致动画效果很差,后来详细查找了一下glutInitDisplayMode函数的参数列表:
函数原型void glutInitDisplayMode(unsigned int mode),函数功能为设置初始显示模式。
函数功能:设置初始显示模式。
函数原型:void glutInitDisplayMode(unsigned int mode);
mode | mode可取以下值或其组合:
值 |
对应宏定义 |
意义 |
GLUT_RGB |
0x0000 |
指定 RGB 颜色模式的窗口 |
GLUT_RGBA |
0x0000 |
指定RGBA颜色模式的窗口 |
GLUT_INDEX |
0x0001 |
指定颜色索引模式的窗口 |
GLUT_SINGLE |
0x0000 |
指定单缓存窗口 |
GLUT_DOUBLE |
0x0002 |
指定双缓存窗口 |
GLUT_ACCUM |
0x0004 |
窗口使用累加缓存 |
GLUT_ALPHA |
0x0008 |
窗口的颜色分量包含 alpha 值 |
GLUT_DEPTH |
0x0010 |
窗口使用深度缓存 |
GLUT_STENCIL |
0x0020 |
窗口使用模板缓存 |
GLUT_MULTISAMPLE |
0x0080 |
指定支持多样本功能的窗口 |
GLUT_STEREO |
0x0100 |
指定立体窗口 |
GLUT_LUMINANCE |
0x0200 |
窗口使用亮度颜色模型 |
用“或“(|)操作符来建立想要的显示模式
想要流畅地显示动画,必须设置双缓冲区,而且我使用了RGB色彩空间,于是初始化语句为
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
3.3.2.通过不断地刷新并交换缓冲区实现旋转
1.当使能信号enable=1时可以旋转,于是先定义矩阵堆栈模式glMatrixMode(GL_MODELVIEW);
glLoadIdentity();//矩阵堆栈可以保存上次旋转结果
2.压入旋转角度angle+=step的旋转矩阵(我定义的三个点的中心刚好在原点,所以不需要计算旋转中心,默认原点就好)
angle=(angle+step)%360;
glRotated(angle,0,0,1);
3.画填充三角形并刷新画面和交换缓冲区
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
glVertex2f( -6.0, -3.0 );
glVertex2f( 4.0, -4.0 );
glVertex2f( 2.0, 7.0 );
glEnd();
glFlush();
glutSwapBuffers();//交换缓冲区保证有流畅动画
4.当使能信号enable=1时重复上述过程,实现旋转
if(enable==1)
glutPostRedisplay();
最后一种模式case=6时旋转,相应的窗口回调函数代码段为
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
switch(currentMode)
{……
case 6:
Rotate();//旋转
break;
}
glVertex2f( -6.0, -3.0 );
glVertex2f( 4.0, -4.0 );
glVertex2f( 2.0, 7.0 );
glEnd();
glFlush();
glutSwapBuffers();
glLoadIdentity();
if(enable==1)
glutPostRedisplay();
}
Rotate函数实现为:
void Rotate()
{
//显示提示字符
……
//旋转
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
angle=(angle+step)%360;
glRotated(angle,0,0,1);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
}
3.4实现文字提示
Glut内置了字符提示函数
glRasterPos2d(double x,double y)
定义了光标位置,其中坐标为世界坐标,即(0,0)为世界坐标中心。
glutBitmapCharacter(font , character)
定义了字体和要显示的字符,仅限ASC||表中的字符,参数范围如下
font
设置字符的字体,选择范围如下:
GLUT_BITMAP_8_BY_13
GLUT_BITMAP_9_BY_15
GLUT_BITMAP_TIMES_ROMAN_10 字体:TIMES_ROMAN 大小:10
GLUT_BITMAP_TIMES_ROMAN_24 字体:TIMES_ROMAN 大小:24
GLUT_BITMAP_HELVETICA_10
GLUT_BITMAP_HELVETICA_12
GLUT_BITMAP_HELVETICA_18
character
要显示的字符。
我用以上两个内置函数实现了字符提示函数displayc
void displayc()
{
glColor3f(0, 0, 0);
char str[]="Press space to continue,press escape to exit!";
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2d(-39.5,20);
for(int i=0;i<sizeof(str);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str[i]);
}
glFlush();
}
以及Rotate函数中显示字符的代码段
//显示提示字符
char str[]="Press 'R' to Rotate,'S' to stop";
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2d(-25,20);
for(int i=0;i<sizeof(str);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str[i]);
}
char str1[]="Press Up to Speed up,Down to Slow down";
glRasterPos2d(-30,15);
for(int i=0;i<sizeof(str1);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str1[i]);
}
运行结果
1.画点
2.画开折线
3.画闭折线
4.画填充三角形
5.平移
6.放缩
7.旋转
四、实验心得
此次实验我查阅了大量资料,终于在详细了解了许多OpenGL函数之后实现了一个简单的动画以及键盘回调函数,在最后代码运行无误,画面能正确响应键盘的时候内心还是很开心的。
五、源代码
1.立方体放缩
#include"windows.h"
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <glut.h>
void init()
{
glClearColor(1.0,1.0,1.0,1.0);
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(45,1,1,1);//绕着向量(1,1,1)所指定的轴旋转45°
glPushMatrix();//保存矩阵状态
glTranslatef(10,20,10);//从原点平移到原处,T2
glPushMatrix();
glScalef(2,1,0.5);//放缩变换,S
glPushMatrix();
glTranslatef(-10,-20,-10);//从当前平移至原点,T1
glPushMatrix();
glColor3f(1.0,0.0,0.0);
glutWireCube(10.0);
//glFlush();
glLoadIdentity();
glRotatef(45,1,1,1);//绕着向量(1,1,1)所指定的轴旋转45°
//画x坐标轴
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,0,0);
glVertex3f(40,0,0);
glEnd();
//画y坐标轴
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,0,0);
glVertex3f(0,40,0);
glEnd();
//画z坐标轴
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,0,0);
glVertex3f(0,0,40);
glEnd();
glFlush();
}
void ChangeSize(GLsizei w,GLsizei h)
{
GLfloat aspectRatio;
if(h==0)
h = 1;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
aspectRatio = (GLfloat)w/(GLfloat)h;
if(w<=h)
glOrtho(-50.0,50.0,-50.0/aspectRatio,50.0/aspectRatio,-50.0,50.0);
else
glOrtho(-50.0*aspectRatio,50.0*aspectRatio,-50.0,50.0,-50.0,50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main()
{
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutCreateWindow("Scale_Cube");
init();
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutMainLoop();
return 0;
}
2.旋转变换
#include<windows.h>
#include <GL/glut.h>
void init()
{
glClearColor(1.0,1.0,1.0,0.0);
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0,0,0.5);
glRectf(-5,10,0,50);
//原矩阵
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,0,0);
glVertex3f(80,0,0);
glEnd();
//x轴
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,0,0);
glVertex3f(0,80,0);
glEnd();
//y轴
glBegin(GL_LINES);
glColor3f(0,1,0);
glVertex3f(-50,-45,0);
glVertex3f(50,55,0);
glEnd();
glTranslatef(0,5,0);//T2,y平移5个单位
glPushMatrix();
glRotated(45,0,0,1);//R2,逆时针旋转45度
glPushMatrix();
glScaled(1,-1,1);//S,放缩变换
glPushMatrix();
glRotated(-45,0,0,1);//R1 逆顺时针旋转45度,与x轴重合
glPushMatrix();
glTranslated(0,-5,0);//T1 y平移-5个单位
glPushMatrix();
glColor3f(1,0,0);
glRectf(-5,10,0,50);//x1=T2*R2*S*R1*T1*x
glFlush();
}
void ChangeSize(GLsizei w,GLsizei h)
{
float ratio;
if(h==0)
h = 1;
ratio = (GLfloat)w/(GLfloat)h;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
gluOrtho2D(-100.0,100.0,-100.0/ratio,100.0/ratio);
else
gluOrtho2D(-100.0*ratio,100.0*ratio,-100.0,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main()
{
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowPosition(400,300);
glutInitWindowSize(300,300);
glutCreateWindow("Geometric transformation 2");
init();
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutMainLoop();
return 0;
}
3.旋转三角形
#include"windows.h"
#include <stdlib.h>
#include <stdio.h>
#include <glut.h>
#include<gl.h>
#include <stdlib.h>
#include <string>
int currentMode = 0;
int enable=0;//是否旋转
int angle = 0; //当前旋转角度
int step = 1; //每次的角度递增值
const int ModeNums = 7;
typedef struct {
float x,y;
}point;
void Rotate();
void init()
{
glClearColor(1.0,1.0,1.0,1.0);
}
void myKey( unsigned char key, int x, int y) //响应ASCII对应键,鼠标的当前x和y位置也被返回。
{
switch(key)
{
case ' ': currentMode = (currentMode+1)%ModeNums;
glutPostRedisplay();
break;
case 'r':enable=1;
glutPostRedisplay();
break;
case 's':enable=0;
glutPostRedisplay();
break;
case 27: exit(-1);
}
}
void SpecialKey(int key,int x,int y)
{
switch(key)
{
case GLUT_KEY_UP:
step++;
break;
case GLUT_KEY_DOWN:
step--;
break;
}
}
void displayc()
{
glColor3f(0, 0, 0);
char str[]="Press space to continue,press escape to exit!";
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2d(-39.5,20);
for(int i=0;i<sizeof(str);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str[i]);
}
glFlush();
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
switch(currentMode)
{
case 0:
displayc();//画点
glPointSize(4);
glBegin(GL_POINTS);
glColor3f(0,1.0,0.0);
break;
case 1:displayc();//画开折线
glBegin(GL_LINE_STRIP);
glColor3f(1.0,0,0.0);
break;
case 2: displayc();//画闭折线
glBegin(GL_LINE_LOOP);
glColor3f(0.0,0.0,1.0);
break;
case 3: displayc();//画填充三角形
glBegin(GL_TRIANGLES);
glColor3f(1.0,0,1.0);
break;
case 4:displayc();//平移
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslated(2,2,0);
glBegin(GL_TRIANGLES);
glColor3f(0,0,0);
break;
case 5:displayc();//放缩
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScaled(1.5,1.5,1);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
break;
case 6:
Rotate();//旋转
break;
}
glVertex2f( -6.0, -3.0 );
glVertex2f( 4.0, -4.0 );
glVertex2f( 2.0, 7.0 );
glEnd();
glFlush();
glutSwapBuffers();//交换缓冲区保证有流畅动画
glLoadIdentity();
if(enable==1)
glutPostRedisplay();
}
void Rotate()
{
glColor3f(0, 0, 0);//设置黑色绘制颜色
//显示提示字符
char str[]="Press 'R' to Rotate,'S' to stop";
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2d(-25,20);
for(int i=0;i<sizeof(str);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str[i]);
}
char str1[]="Press Up to Speed up,Down to Slow down";
glRasterPos2d(-30,15);
for(int i=0;i<sizeof(str1);i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13,str1[i]);
}
//旋转
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
angle=(angle+step)%360;
glRotated(angle,0,0,1);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
}
void ChangeSize(GLsizei w,GLsizei h)
{
float ratio;
if(h==0)
h = 1;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
ratio = (float)w/(float)h;
//gluOrtho2D(-10.0,10.0,-10.0,10.0);
if(w<=h)
gluOrtho2D(-40.0,40.0,-40.0/ratio,40.0/ratio);
else
gluOrtho2D(-40.0*ratio,40.0*ratio,-40.0,40.0);
glMatrixMode(GL_MODELVIEW);
}
int main()
{
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowPosition(50,50);
glutInitWindowSize(360,360);
glutCreateWindow("KeyboardFunc");
init();
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(myKey); //为当前窗口设置键盘回调函数。
glutSpecialFunc(SpecialKey);
printf("Press space to continue,press escape to exit!\n");
glutMainLoop();
return 0;
}