計算機圖形學第二次上機實驗 課程實驗報告
寫在前面:這是我的圖形學上機報告,代碼都是自己寫的,實測通過,查閱了許多資料,現以鏈接的形式給出
若遇到其他問題,希望大家多動手多查資料,不要矇混過關,這樣纔能有收穫。
最後希望這份報告能夠幫到大家~
目錄
一、實驗目的
- 掌握配置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;
}