图形学实验(1)--OpenGL 入门
生活随笔
收集整理的這篇文章主要介紹了
图形学实验(1)--OpenGL 入门
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- OpenGL vs2019環(huán)境配置
- 實(shí)驗(yàn)內(nèi)容熟悉:顯示一個茶壺
- 圖形的繪制和圖元的生成算法
- 理解glut程序框架
- 繪制基本圖形
- 基本圖元生成程序框架(畫直線圓)
- 問題與解決
- 程序
- 反走樣
- 顯示字符
- 不同屬性的點(diǎn)和線
- 掃描填充算法
OpenGL vs2019環(huán)境配置
OpenGL vs2019環(huán)境配置
注意每次新開項(xiàng)目都要 在“項(xiàng)目”中,選擇“管理NuGet程序包”,并在瀏覽中搜索“nupengl",兩個都要安裝。
實(shí)驗(yàn)內(nèi)容熟悉:顯示一個茶壺
關(guān)于glNewList() OpenGL顯示列表
OpenGL glViewport()函數(shù)
圖形的繪制和圖元的生成算法
理解glut程序框架
- 繪制簡單圖形
添加下面代碼
不知道為啥我算出來的那個值看起來少了?用0.25效果還行
或者
繪制封閉多邊形,只有線
改一下前面三角的顏色(好吧是我電腦色差的問題)
繪制基本圖形
多邊形的繪制要從凹點(diǎn)開始繪制
#include <GL/glut.h> void display();int main(int argc, char* argv[]) {//初始化工具包glutInit(&argc, argv);//設(shè)置顯示模式glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);//設(shè)置窗口屬性glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("1812030065 李詩雨");//調(diào)用繪圖函數(shù)glutDisplayFunc(display);//進(jìn)入循環(huán)glutMainLoop();return 0; }void display() {//設(shè)定背景色,并把背景色設(shè)置為窗口顏色glClearColor(0.0, 0.0, 0.0, 0.0);glClear(GL_COLOR_BUFFER_BIT);//繪制多邊形圖形//以凹點(diǎn)為起始開始繪制glBegin(GL_POLYGON);glColor3f(1.0f, 1.0f, 1.0f);glVertex2f(-0.22f, 0.0f);glVertex2f(-0.4f,0.3f);glVertex2f(-0.1f, 0.3f);glVertex2f(0.0f, 0.5f);glVertex2f(0.1f, 0.3);glVertex2f(0.4f, 0.3);glVertex2f(0.22f, 0.0f);glVertex2f(0.4f, -0.3);glVertex2f(0.1f, -0.3);glVertex2f(0.0f, -0.5f);glVertex2f(-0.1f, -0.3);glVertex2f(-0.4f, -0.3f);glEnd();//開始執(zhí)行glFlush(); }- 添加顏色
哈哈哈哈好丑
- 問題:實(shí)驗(yàn)要求填色用雙緩存區(qū),我用了之后窗口變成白色
解決:雙緩存 用glutSwapBuffers();代替glFlush,這個函數(shù)的作用是交換兩個緩沖區(qū)的內(nèi)容,并把隱藏的渲染好的顯示出來。
基本圖元生成程序框架(畫直線圓)
唉把這個寫完是真的不容易
很多原本第一次看都難哭的東西,都看幾遍至少都能看懂了,重要是耐心。
問題與解決
char key 這個不能用switch 用了之后,雖然沒有報錯但是這段代碼以下都不能自動提示了。未弄清原因
void Keyboard(unsigned char key, int x, int y) {switch (key){case'1': m_drawmode = 1; break;case'2': m_drawmode = 2; break;case'3': m_drawmode = 3; break;case'4': m_drawmode = 4; break;case'5': m_drawmode = 5; break;default:break;}m_pointnumber = 0;}這個n控制,真沒看懂怎么回事,設(shè)置斷點(diǎn)調(diào)試的時候跟直接運(yùn)行結(jié)果不一樣。具體可能是框架的原因吧,暫時先放這里。
//對畫線動畫進(jìn)行控制if (n == 1){cout << "DDA算法:各點(diǎn)坐標(biāo)\n";}else if(n==0){return;}還有這個也很迷,就是直線還挺好理解,放到圓那邊就稍微有點(diǎn)暈,弄錯了會出現(xiàn)一直閃的效果。
//繪制到比上一幀多一個像素點(diǎn)if (i >= n-1) {cout <<"n="<<n<< ", x=" << x << ", y=" << y << ", 取整后 x="<< (int)(x + 0.5) << ", y=" << (int)(y + 0.5) << endl << endl;break;}程序
#include <windows.h> #include <gl/glut.h> #include <iostream> using namespace std; int m_pointnumber = 0;//動畫時繪制點(diǎn)的數(shù)目 int m_drawmode = 1;//繪制模式 // 1 DDA算法畫直線 // 2 中點(diǎn)Bresenham算法畫直線 // 3 改進(jìn)Bresenham算法畫直線 // 4 八分法繪制圓 // 5 四分法繪制橢圓(選作)//初始化窗口 void initial(); //窗口大小改變時調(diào)用的登記函數(shù) void ChangeSize(GLsizei w, GLsizei h); //設(shè)置鍵盤回調(diào)函數(shù) void Keyboard(unsigned char key, int x, int y); //設(shè)置時間回調(diào)函數(shù) void TimerFunc(int value); //在窗口中繪制圖形 void Redraw(); //繪制坐標(biāo)線 void DrawCordinateLine(); //繪制一個點(diǎn),這里用一個正方形代表一個點(diǎn) void PutPixel(GLsizei x, GLsizei y); //參數(shù)說明:x0,y0 起始點(diǎn) // x1,y1 終止點(diǎn) // n 掃描轉(zhuǎn)換時從起點(diǎn)開始輸出的點(diǎn)的數(shù)目,用于動畫 // 1 DDA算法畫直線 void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); // 2 中點(diǎn)Bresenham算法畫直線 void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); // 3 改進(jìn)Bresenham算法畫直線 void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); //參數(shù)說明:x0,y0 圓心坐標(biāo) // r 半徑 // n 掃描轉(zhuǎn)換時從起點(diǎn)開始輸出的點(diǎn)的數(shù)目,用于動畫 // 4 八分法繪制圓 void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r, GLsizei n); // 5 四分法繪制橢圓(選作) //參數(shù)說明:x0,y0 圓心坐標(biāo) // a b 長半軸為a 短半軸為b // n 掃描轉(zhuǎn)換時從起點(diǎn)開始輸出的點(diǎn)的數(shù)目,用于動畫 void BresenhamEllipse(GLsizei x0, GLsizei y0, GLsizei a, GLsizei b, GLsizei n);int main(int argc, char* argv[]) {//初始化工具包glutInit(&argc, argv);//初始化顯示模式和窗口屬性glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);glutInitWindowPosition(100, 100);glutInitWindowSize(600, 600);glutCreateWindow("1812030065李詩雨 基本圖元繪制程序");glutDisplayFunc(Redraw);glutReshapeFunc(ChangeSize);glutKeyboardFunc(Keyboard);//鍵盤響應(yīng)回調(diào)函數(shù)glutTimerFunc(100, TimerFunc, 1);//窗口初始化initial();glutMainLoop();//啟動主glut事件處理循環(huán)return 0;}void initial() {//設(shè)置清除色,并設(shè)置窗口背景色glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT); }void ChangeSize(GLsizei w, GLsizei h) {if (h == 0) h = 1;//設(shè)置視區(qū)glViewport(0, 0, w, h);//重置坐標(biāo)系統(tǒng)glMatrixMode(GL_PROJECTION_MATRIX);glLoadIdentity();//建立修剪空間的范圍if (w <= h)glOrtho(0.0f, 250.0f, 0.0f, 250.0f * h / w, 1.0f, -1.0f);elseglOrtho(0.0f, 250.0f * w / h, 0.0f, 250.0f, 1.0f, -1.0f); }void Keyboard(unsigned char key, int x, int y) {if (key == '1') m_drawmode = 1;if (key == '2') m_drawmode = 2;if (key == '3') m_drawmode = 3;if (key == '4') m_drawmode = 4;if (key == '5') m_drawmode = 5;m_pointnumber = 0;cout << "nm_pointer 恢復(fù)為 0" << endl;glutPostRedisplay(); }void TimerFunc(int value) {if (m_pointnumber == 0) value = 1;m_pointnumber = value;//用現(xiàn)有的參數(shù)重新繪圖(即動畫中新的一幀)glutPostRedisplay();//注意,該函數(shù)與其他的回調(diào)函數(shù)不一樣的地方在于該函數(shù)只會被激發(fā)一次。為了實(shí)現(xiàn)連//續(xù)的動畫,必須在定時器函數(shù)中再次重新設(shè)置定時器回調(diào)函數(shù)。glutTimerFunc(50, TimerFunc, value + 1); }void Redraw() {//用當(dāng)前背景色填充窗口glClear(GL_COLOR_BUFFER_BIT);//畫坐標(biāo)線DrawCordinateLine();switch (m_drawmode){case 1:DDACreatLine(0, 0, 20, 15, m_pointnumber); break;case 2:BresenhamLine(0, 20, 16, 0, m_pointnumber); break;case 3:Bresenham2Line(0, 20, 10, 0, m_pointnumber); break;case 4:BresenhamCircle(10,10,10, m_pointnumber); break;case 5:BresenhamEllipse(10, 10, 8 , 4, m_pointnumber); break;default:break;}glutSwapBuffers(); }void DrawCordinateLine() {glColor3f(0.0f, 0.0f, 0.0f);//坐標(biāo)線為黑色glBegin(GL_LINES);for (int i = 10; i <= 250; i += 10) {glVertex2f((float)i, 0.0f);glVertex2f((float)i, 250.0f);glVertex2f(0.0f, (float)i);glVertex2f(250.0f, (float)i);}glEnd(); }void PutPixel(GLsizei x, GLsizei y) {//繪制矩形所在的坐標(biāo)?glRectf(x * 10, y * 10, x * 10 + 10, y * 10 + 10); }void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設(shè)置顏色glColor3f(1.0f, 0.0f, 0.0f);//對畫線動畫進(jìn)行控制if (n == 1){cout << "DDA算法:各點(diǎn)坐標(biāo)\n";}else if(n==0){return;}//畫線算法實(shí)現(xiàn)GLsizei dx, dy, epsl, i;GLfloat x, y, xincre, yincre;dx = x1 - x0;dy = y1 - y0;x = x0; y = y0;//通過epsl可以通過斜率絕對值確定是x還是y每次自增1if (abs(dx) > abs(dy)) epsl = abs(dx);else epsl = abs(dy);//x y 的增量 例如 xincre=1,yincre=kxincre = (float)dx / epsl;yincre = (float)dy / epsl;//epsl 的值是dx或dy(epsl+1)就決定了要畫像素的數(shù)目for (i = 0; i <= epsl; i++) {PutPixel((int)(x + 0.5), (int)(y + 0.5));//繪制到比上一幀多一個像素點(diǎn)if (i >= n-1) {cout <<"n="<<n<< ", x=" << x << ", y=" << y << ", 取整后 x="<< (int)(x + 0.5) << ", y=" << (int)(y + 0.5) << endl << endl;break;}x += xincre;y += yincre;//超出窗口坐標(biāo)if (x >= 25 || y >= 25) break;} }void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設(shè)置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "中點(diǎn)BresenhamLine算法:各點(diǎn)坐標(biāo)及判別式的值\n";}else if (n == 0) {return;}//畫線算法實(shí)現(xiàn)GLsizei dx, dy;GLfloat x, y, d,xincre,yincre;dx = x1 - x0;dy = y1 - y0;x = x0; y = y0;//x y 的增量 xincre = (float)dx / abs(dx);yincre = (float)dy / abs(dy);//x還是y每次自增1 畫線參數(shù)不同 d = dx - 2 * min(abs(dx), abs(dy));//max(abs(dx), abs(dy)))就決定了要畫像素的數(shù)目for (int i = 0; i <= max(abs(dx), abs(dy)); i++) {PutPixel(x, y); if (d < 0) {//取Puif (max(abs(dx), abs(dy)) == abs(dx)) {y += yincre;}else {x += xincre;}d = d + 2 * max(abs(dx), abs(dy)) - 2 * min(abs(dx), abs(dy));}else {//取pdd = d - 2 * min(abs(dx), abs(dy));}if (max(abs(dx), abs(dy)) == abs(dx)) {x += xincre;}else {y += yincre;}//繪制到比上一幀多一個像素點(diǎn)if (i >= n - 1) {cout << "n=" << n << ", x=" << x << ", y=" << y << ", 判別式 d="<< d << endl << endl;break;}//超出窗口坐標(biāo)if (x >= 25 || y >= 25) break;} }void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設(shè)置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法:各點(diǎn)坐標(biāo)及判別式的值\n";}else if (n == 0) {return;}//畫線算法實(shí)現(xiàn)GLsizei dx, dy;GLfloat x, y, e, xincre, yincre;dx = x1 - x0;dy = y1 - y0;x = x0; y = y0;//x y 的增量 xincre = (float)dx / abs(dx);yincre = (float)dy / abs(dy);//x還是y每次自增1 和 相關(guān)參數(shù) 取決于 dx 和 dy 的絕對值大小 e = -max(abs(dx), abs(dy));for (int i = 0; i <= max(abs(dx), abs(dy)); i++) {PutPixel(x, y);e += 2 * min(abs(dx), abs(dy));//這個判別式 是距離 都是正的if (e > 0) {e -= 2 * max(abs(dx), abs(dy));if (max(abs(dx), abs(dy)) == abs(dx)) {y += yincre;}else {x += xincre;}}if (max(abs(dx), abs(dy)) == abs(dx)) {x += xincre;}else {y += yincre;}//繪制到比上一幀多一個像素點(diǎn)if (i >= n) {cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判別式 e="<< e << endl << endl;break;}//超出窗口坐標(biāo)if (x >= 25 || y >= 25) break;} }void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r, GLsizei n) {//設(shè)置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法畫圓:各點(diǎn)坐標(biāo)及判別式的值\n";}else if(n==0) {return;}GLsizei x, y, d, count;count = 0;x = 0; y = r; d = 1 - r;while ( x<=y){PutPixel(x0 + x, y0 + y); PutPixel(x0 + y, y0 + x);PutPixel(x0 - y, y0 + x); PutPixel(x0 - x, y0 + y);PutPixel(x0 - x, y0 - y); PutPixel(x0 - y, y0 - x);PutPixel(x0 + y, y0 - x); PutPixel(x0 + x, y0 - y);count++;if (count >= n) {cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判別式 d="<< d << endl << endl;break;}if (d < 0) {d += 2 * x + 3;}else {d += 2 * (x - y) + 5;y--;}x++; //超出窗口坐標(biāo)if (x >= 25 || y >= 25) break;}}void BresenhamEllipse(GLsizei x0, GLsizei y0, GLsizei a, GLsizei b, GLsizei n) {//設(shè)置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法畫橢圓:各點(diǎn)坐標(biāo)及判別式的值\n";}else if (n == 0) {return;}GLsizei x, y, count;GLfloat d1, d2;x = 0; y = b; count = 0;d1 = b * b + a * a * (-b + 0.25);while (b * b * (x + 1) <= a * a * (y - 0.5)){PutPixel(x0 + x, y0 + y); PutPixel(x0 - x, y0 - y);PutPixel(x0 - x, y0 + y); PutPixel(x0 + x, y0 - y);count++;if (count >= n) {cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判別式 d1="<< d1 << endl << endl;break;}if (d1 <= 0) {d1 += b * b * (2 * x + 3);x++;}else{d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2);x++; y--;}//超出窗口坐標(biāo)if (x >= 25 || y >= 25) break; }if (b * b * (x + 1) >= a * a * (y - 0.5)) {d2 = b * b * (x + 0.5) * (x + 0.5) + a * a * (y - 1) * (y - 1) - a * a * b * b;while (y >= 0){PutPixel(x0 + x, y0 + y); PutPixel(x0 - x, y0 - y);PutPixel(x0 - x, y0 + y); PutPixel(x0 + x, y0 - y);count++;if (count >= n) {cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判別式 d2="<< d2 << endl << endl;break;}if (d2 <= 0){d2 += b * b * (2 * x + 2) + a * a * (-2 * x + 3);x++; y--;}else {d2 += a * a * (-2 * x + 3);y--;}//超出窗口坐標(biāo)if (x >= 25 || y >= 25) break;}}}
反走樣
原來 changesize的函數(shù)不是通用啊。。。。
#include <windows.h> #include <gl/glut.h> #include <iostream> using namespace std; //指定顯示列表 GLuint lineList; //初始化窗口 void initial(); //窗口大小改變時調(diào)用的登記函數(shù) void ChangeSize(GLsizei w, GLsizei h);void Displayt(); void Displayw();int main(int argc, char* argv[]) {//初始化工具包glutInit(&argc, argv);//初始化顯示模式和窗口屬性glutInitDisplayMode(GLUT_SINGLE| GLUT_RGB);glutInitWindowSize(600, 600);glutCreateWindow("1812030065李詩雨 原始圖形");glutDisplayFunc(Displayt);glutReshapeFunc(ChangeSize);//窗口初始化initial();glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowPosition(300, 300);glutInitWindowSize(600, 600);glutCreateWindow("1812030065李詩雨 反走樣圖形");glutDisplayFunc(Displayw);glutReshapeFunc(ChangeSize);//窗口初始化initial();glutMainLoop();//啟動主glut事件處理循環(huán)return 0;}void initial() {//設(shè)置清除色,并設(shè)置窗口背景色glClearColor(1.0f, 1.0f, 1.0f, 0.0f);glLineWidth(12.0f);glColor4f(0.0, 0.6, 1.0, 1.0);lineList = glGenLists(1);//定義顯示列表glNewList(lineList, GL_COMPILE);glBegin(GL_LINE_LOOP);glVertex2f(1.0f, 1.0f);glVertex2f(4.0f, 2.0f);glVertex2f(2.0f, 5.0f);glEnd();glEndList(); }void ChangeSize(GLsizei w, GLsizei h) {if (h == 0) h = 1;//設(shè)置視區(qū)glViewport(0, 0, w, h);//重置坐標(biāo)系統(tǒng)glMatrixMode(GL_PROJECTION);glLoadIdentity();//建立修剪空間的范圍if (w <= h)gluOrtho2D(0.0, 5.0, 0.0, 6.0 *(GLfloat) h / (GLfloat)w);elsegluOrtho2D(0.0, 5.0 * (GLfloat)w / (GLfloat)h, 0.0, 6.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity(); }void Displayt() {glClear(GL_COLOR_BUFFER_BIT);glCallList(lineList);glFlush(); }void Displayw() {glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_LINE_SMOOTH);//使用反走樣glEnable(GL_BLEND);//使用混合函數(shù)glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//指定混合函數(shù)glCallList(lineList);glFlush(); }顯示字符
#include <windows.h> #include <gl/glut.h> #include <iostream> using namespace std; void Display(); void ChangeSize(GLsizei w, GLsizei h); void output(int x,int y,const char *string); int main(int argc, char* argv[]) {//初始化工具包glutInit(&argc, argv);//初始化顯示模式和窗口屬性glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowSize(600, 600);glutCreateWindow("1812030065李詩雨 字符顯示");glutDisplayFunc(Display);glutReshapeFunc(ChangeSize);//窗口初始化//initial();glutMainLoop();//啟動主glut事件處理循環(huán)return 0;}void ChangeSize(GLsizei w, GLsizei h) {glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0.0, w, 0.0, h); }void output(int x, int y, const char* string) {int len, i;glRasterPos2f(x, y);len = (int)strlen(string);for (int i = 0; i < len; i++) {glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);} }void Display() {//設(shè)置清除色,并設(shè)置窗口背景色glClearColor(1.0f, 1.0f, 1.0f, 0.0f);glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0f, 0.0f, 0.0f);output(100, 100, "hello!");glFlush(); }不同屬性的點(diǎn)和線
#include <windows.h> #include <gl/glut.h> #include <iostream> using namespace std; int winWidth = 400, winHeight = 300; //窗口的寬度和高度 void myDisplay(void); void ChangeSize(int w, int h);int main(int argc, char* argv[]) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 300);glutCreateWindow("1812030065 李詩雨");glutDisplayFunc(myDisplay);glutReshapeFunc(ChangeSize);glutMainLoop();return 0; } void myDisplay(void) {glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT); //用當(dāng)前背景色填充窗口glColor3f(0.0f, 0.0f, 0.0f); //設(shè)置當(dāng)前的繪圖繪圖RGB顏色//繪制不同大小的點(diǎn)GLfloat sizes[2]; //保存繪制點(diǎn)的尺寸范圍GLfloat step = 0.125; //保存繪制點(diǎn)尺寸的步長GLfloat curSize; //當(dāng)前繪制的點(diǎn)的大小glGetFloatv(GL_POINT_SIZE_RANGE, sizes);curSize = sizes[0];for (int i = 0; i < 25; i++){glPointSize(curSize);glBegin(GL_POINTS);glVertex3f(25.0 + i * 8, 200.0, 0.0);glEnd();curSize += step * 2;}//繪制一條寬度為5的直線glLineWidth(5);glBegin(GL_LINES);glVertex3f(25.0, 160.0, 0.0);glVertex3f(225.0, 160.0, 0.0);glEnd();//繪制一條虛線glEnable(GL_LINE_STIPPLE);glLineStipple(1, 0x00FF);glBegin(GL_LINES);glVertex3f(25.0, 120.0, 0.0);glVertex3f(225.0, 120.0, 0.0);glEnd();//繪制一條寬度為3的點(diǎn)劃線glLineWidth(3);glLineStipple(1, 0xFF0C);glBegin(GL_LINES);glVertex3f(25.0, 80.0, 0.0);glVertex3f(225.0, 80.0, 0.0);glEnd();//增加重復(fù)因子繪制的點(diǎn)劃線glLineStipple(4, 0xFF0C);glBegin(GL_LINES);glVertex3f(25.0, 40.0, 0.0);glVertex3f(225.0, 40.0, 0.0);glEnd();glDisable(GL_LINE_STIPPLE);glFlush(); //刷新OpenGL命令隊(duì)列 } void ChangeSize(int w, int h) {winWidth = w; winHeight = h;glViewport(0, 0, w, h); //指定窗口的顯示區(qū)域glMatrixMode(GL_PROJECTION); //設(shè)置投影參數(shù)glLoadIdentity();gluOrtho2D(0.0, winWidth, 0.0, winHeight); }掃描填充算法
要在項(xiàng)目下新建一個輸入坐標(biāo)的 polypoints.txt
#include <gl/glut.h> #include <iostream> #include <vector> #include <fstream> using namespace std;int Vertexs;typedef struct _EdgeItem {float x;int yMax;float reverseK; // 1/k_EdgeItem* next; }EdgeItem; vector<EdgeItem*> g_pItemVector;typedef struct _Point {int x;int y; }Point;typedef struct _EdgePtr {int nScanLine; // Current scan lineEdgeItem* pItem; // Pointer to edge item }EdgePtr;typedef struct _PolyPoints {Point* pPoint; // Pointer to pointsint n; // Number of pointsint yMax; // Max y of all pointsint yMin; // Min y of all points }PolyPoints;EdgePtr* g_pEdgeList; // Edge list EdgePtr* g_pActiveEdgeList; // Active edge list PolyPoints g_polyPoints; // Storage for points of polygonsifstream scin("polypoints.txt");void PutPixel(GLsizei x, GLsizei y) {glRectf(10 * x, 10 * y, 10 * x + 10, 10 * y + 10); }void inputPoints(void) {int n;scin >> n;Vertexs = n;if (n < 3){cout << "number of points can not be less than 3" << endl;exit(0);}g_polyPoints.n = n;g_polyPoints.pPoint = new Point[n];g_polyPoints.yMax = INT_MIN;g_polyPoints.yMin = INT_MAX;int x, y;for (int i = 0; i < n; ++i){scin >> x >> y;g_polyPoints.pPoint[i].x = x;g_polyPoints.pPoint[i].y = y;if (g_polyPoints.yMax < y){g_polyPoints.yMax = y;}if (g_polyPoints.yMin > y){g_polyPoints.yMin = y;}} } // Calculate the reverse of k float calculateReverseK(const Point& p1, const Point& p2) {return (float)(p2.x - p1.x) / (float)(p2.y - p1.y); }// Sort one scan line's list, first sort by x, if x is equal then sort by 1/k void sortOneScanLineEdgeList(EdgePtr& edgePtr) {// Sort by x (select sort)EdgeItem* pEdgeItem = edgePtr.pItem;EdgeItem* pNext;EdgeItem* pTmp;while (pEdgeItem){pNext = pEdgeItem->next;pTmp = pEdgeItem;while (pNext){if (pNext->x < pTmp->x){pTmp = pNext;}pNext = pNext->next;}if (pTmp != pEdgeItem){// Swap xfloat fTmp = pTmp->x;pTmp->x = pEdgeItem->x;pEdgeItem->x = fTmp;// Swap yMaxint iTmp = pTmp->yMax;pTmp->yMax = pEdgeItem->yMax;pEdgeItem->yMax = iTmp;// Swap 1/kfloat kTmp = pTmp->reverseK;pTmp->reverseK = pEdgeItem->reverseK;pEdgeItem->reverseK = kTmp;}pEdgeItem = pEdgeItem->next;}// When the x is the same, then sort by 1/kpEdgeItem = edgePtr.pItem;EdgeItem* pStart = NULL;EdgeItem* pEnd = NULL;while (pEdgeItem){// Find the start pointer and end pointer with the same x, then sort thempEnd = pStart = pEdgeItem;pNext = pStart->next;while (pNext && (pNext->x == pStart->x)){pEnd = pNext;pNext = pNext->next;}// Sort the edge list from pStart to pEnd by 1/k (select sort)while (pStart != pEnd){pTmp = pStart;pNext = pTmp->next;while (pNext != pEnd){if (pNext->reverseK < pTmp->reverseK){pTmp = pNext;}pNext = pNext->next;}// Swap valuesif (pTmp != pStart){// Swap xfloat fTmp = pTmp->x;pTmp->x = pStart->x;pStart->x = fTmp;// Swap yMaxint iTmp = pTmp->yMax;pTmp->yMax = pStart->yMax;pStart->yMax = iTmp;// Swap 1/kfloat kTmp = pTmp->reverseK;pTmp->reverseK = pStart->reverseK;pStart->reverseK = kTmp;}pStart = pStart->next;} // while (pStart != pEnd)pEdgeItem = pEnd->next;} } // Construct the edge list void constructEdgeList(void) {// Construct the edge listint nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;g_pEdgeList = new EdgePtr[nScanLines];memset(g_pEdgeList, 0, sizeof(EdgePtr) * nScanLines);Point* pPoint = g_polyPoints.pPoint;int nScanLine = g_polyPoints.yMin;EdgeItem* pEdgeItem = NULL;for (int i = 0; i < nScanLines; ++i, ++nScanLine) //對每一個掃描線 nScanLine,將多邊形的較低頂點(diǎn)在 nScanLine上的邊,裝入邊表 g_pEdgeList 的 第 nScanLine 分量中{g_pEdgeList[i].nScanLine = nScanLine;for (int j = 0; j < g_polyPoints.n; ++j) //遍歷多邊形的頂點(diǎn),找到滿足條件的邊{if (pPoint[j].y == nScanLine){int j1 = (j + g_polyPoints.n - 1) % g_polyPoints.n;int j2 = (j + 1) % g_polyPoints.n;// if point j1's y > nScanLine then add this edge to the current scanline's listif (pPoint[j1].y > nScanLine){pEdgeItem = new EdgeItem;pEdgeItem->reverseK = calculateReverseK(pPoint[j], pPoint[j1]);pEdgeItem->x = (float)pPoint[j].x;pEdgeItem->yMax = pPoint[j1].y;// Add pEdgeItem to the scanline's listpEdgeItem->next = g_pEdgeList[i].pItem;g_pEdgeList[i].pItem = pEdgeItem;}// if point j2's y > nScanLine then add this edge to the curretn scanline's listif (pPoint[j2].y > nScanLine){pEdgeItem = new EdgeItem;pEdgeItem->reverseK = calculateReverseK(pPoint[j], pPoint[j2]);pEdgeItem->x = (float)pPoint[j].x;pEdgeItem->yMax = pPoint[j2].y;// Add pEdgeItem to the scanline's listpEdgeItem->next = g_pEdgeList[i].pItem;g_pEdgeList[i].pItem = pEdgeItem;}} // if (pPoints[j].y == nScanLine)} // for (int j = 0; j < g_polyPoints.n; ++j)sortOneScanLineEdgeList(g_pEdgeList[i]);}// Init the active edge listg_pActiveEdgeList = new EdgePtr[nScanLines]; } // free the memory void destroy(void) {if (g_pActiveEdgeList){delete g_pActiveEdgeList;}int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;EdgeItem* pItem, * pNext;if (g_pEdgeList){for (int i = 0; i < nScanLines; ++i){if (g_pEdgeList[i].pItem){pItem = g_pEdgeList[i].pItem;pNext = pItem;while (pItem){pNext = pItem->next;delete pItem;pItem = pNext;}}}} } void init(void) {glClearColor(1.0f, 1.0f, 1.0f, 1.0f); }void activEdgeListFillPolygon(void) {int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;memset(g_pActiveEdgeList, 0, sizeof(EdgePtr) * nScanLines);int nScanLine = g_polyPoints.yMin;int i;for (i = 0; i < nScanLines; ++nScanLine, ++i) //找到第一個非空活動邊表 g_pActiveEdgeList[i].pItem{if (g_pEdgeList[i].pItem){g_pActiveEdgeList[i].pItem = g_pEdgeList[i].pItem;break;}}for (int j = i; j < nScanLines; ++j, ++nScanLine){if (g_pActiveEdgeList[j].pItem){// Delete the edge where yMax = nScanLine //填充之前先刪除ymax=y(當(dāng)前掃描線)的邊結(jié)點(diǎn)EdgeItem* pPre = NULL;EdgeItem* pNext = g_pActiveEdgeList[j].pItem;bool bEven = true;while (pNext){if (pNext->yMax == nScanLine){if (!pPre){g_pActiveEdgeList[j].pItem = pNext->next;pNext = pNext->next;}else{pPre->next = pNext->next;pNext = pNext->next;}}else{bEven = !bEven;pPre = pNext;pNext = pNext->next;}} // while (pNext)// Fill the scan line when bFill is truebool bFill = false;pNext = g_pActiveEdgeList[j].pItem; //對當(dāng)前活動邊表 g_pActiveEdgeList[j].pItem 進(jìn)行填充while (pNext && bEven){bFill = !bFill;if (bFill) //通過bFill控制填充區(qū)間的始點(diǎn){int x1 = (int)(pNext->x + 0.5);int x2 = (int)(pNext->next->x + 0.5);for (int i = x1; i <= x2; ++i){PutPixel(i, nScanLine);}}pNext = pNext->next;} // while (pNext)pNext = g_pActiveEdgeList[j].pItem;int kk = j + 1;if (kk < nScanLines){while (pNext) //此循環(huán)將活動邊表 g_pActiveEdgeList[kk].pItem 每個結(jié)點(diǎn)的x變?yōu)閤+1/k,修正后的結(jié)點(diǎn)順序正好倒序了{EdgeItem* pItem = new EdgeItem;pItem->x = pNext->x + pNext->reverseK;pItem->reverseK = pNext->reverseK;pItem->yMax = pNext->yMax;pItem->next = g_pActiveEdgeList[kk].pItem;g_pActiveEdgeList[kk].pItem = pItem;pNext = pNext->next;g_pItemVector.push_back(pItem);} // while (pNext)// Add edge list to active edge listpNext = g_pEdgeList[kk].pItem;EdgeItem* pTemp = NULL;while (pNext) //此循環(huán)將邊表 g_pEdgeList[kk].pItem 中第kk掃描線的邊結(jié)點(diǎn)信息倒序插在 活動邊表 g_pActiveEdgeList[kk].pItem 之前{pTemp = new EdgeItem;pTemp->reverseK = pNext->reverseK;pTemp->x = pNext->x;pTemp->yMax = pNext->yMax;g_pItemVector.push_back(pTemp);pTemp->next = g_pActiveEdgeList[kk].pItem;g_pActiveEdgeList[kk].pItem = pTemp;pNext = pNext->next;}sortOneScanLineEdgeList(g_pActiveEdgeList[kk]);}} // if (g_pActiveEdgeList[j].pItem)}//這里為了簡單所以把分配的內(nèi)存放在vector容器中,方便刪除vector<EdgeItem*>::iterator itr = g_pItemVector.begin();vector<EdgeItem*>::iterator endItr = g_pItemVector.end();while (itr != endItr){delete (*itr);++itr;}g_pItemVector.clear(); }//繪制坐標(biāo)線 void DrawCordinateLine(void) {int i = 0;//坐標(biāo)線為黑色glColor3f(0.0f, 0.0f, 0.0f);glBegin(GL_LINES);for (i = 10; i <= 250; i = i + 10){glVertex2f((float)(i), 0.0f);glVertex2f((float)(i), 250.0f);glVertex2f(0.0f, (float)(i));glVertex2f(250.0f, (float)(i));}glEnd(); }void DrawPolygonLine(void) {glColor3f(0.0f, 1.0f, 0.0f);glBegin(GL_LINE_LOOP);for (int i = 0; i < Vertexs; ++i){glVertex2i(10 * g_polyPoints.pPoint[i].x, 10 * g_polyPoints.pPoint[i].y);}glEnd();} //繪制一個點(diǎn),這里用一個正方形表示一個點(diǎn)。 void display(void) {glClear(GL_COLOR_BUFFER_BIT);//畫出坐標(biāo)線DrawCordinateLine();// Fill a polygonglColor3f(1.0f, 0.0f, 0.0f);activEdgeListFillPolygon();DrawPolygonLine();glutSwapBuffers(); }void reshape(GLsizei w, GLsizei h) {if (h == 0)h = 1;// 設(shè)置視區(qū)尺寸glViewport(0, 0, w, h);// 重置坐標(biāo)系統(tǒng)glMatrixMode(GL_PROJECTION);glLoadIdentity();//建立修剪空間的范圍if (w <= h)glOrtho(0.0f, 250.0f, 0.0f, 250.0f * h / w, 1.0, -1.0);elseglOrtho(0.0f, 250.0f * w / h, 0.0f, 250.0f, 1.0, -1.0); } void keyboard(unsigned char key, int x, int y) {switch (key){case 27: // 'VK_ESCAPE' destroy (); exit (0);break;default:break;} } int main(int argc, char** argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);glutInitWindowSize(600, 600);glutInitWindowPosition(100, 100);glutCreateWindow("1812030065 李詩雨 Optimized active edge list");init();inputPoints();constructEdgeList();glutDisplayFunc(display);glutReshapeFunc(reshape);glutKeyboardFunc(keyboard);glutMainLoop();destroy();return 0; }總結(jié)
以上是生活随笔為你收集整理的图形学实验(1)--OpenGL 入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM 之 内存分配与回收策略
- 下一篇: 告别世俗和平庸,告别臃肿和繁琐,拿来就用