图形学实验(1)--OpenGL 入门
生活随笔
收集整理的這篇文章主要介紹了
图形学实验(1)--OpenGL 入门
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- OpenGL vs2019環境配置
- 實驗內容熟悉:顯示一個茶壺
- 圖形的繪制和圖元的生成算法
- 理解glut程序框架
- 繪制基本圖形
- 基本圖元生成程序框架(畫直線圓)
- 問題與解決
- 程序
- 反走樣
- 顯示字符
- 不同屬性的點和線
- 掃描填充算法
OpenGL vs2019環境配置
OpenGL vs2019環境配置
注意每次新開項目都要 在“項目”中,選擇“管理NuGet程序包”,并在瀏覽中搜索“nupengl",兩個都要安裝。
實驗內容熟悉:顯示一個茶壺
關于glNewList() OpenGL顯示列表
OpenGL glViewport()函數
圖形的繪制和圖元的生成算法
理解glut程序框架
- 繪制簡單圖形
添加下面代碼
不知道為啥我算出來的那個值看起來少了?用0.25效果還行
或者
繪制封閉多邊形,只有線
改一下前面三角的顏色(好吧是我電腦色差的問題)
繪制基本圖形
多邊形的繪制要從凹點開始繪制
#include <GL/glut.h> void display();int main(int argc, char* argv[]) {//初始化工具包glutInit(&argc, argv);//設置顯示模式glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);//設置窗口屬性glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("1812030065 李詩雨");//調用繪圖函數glutDisplayFunc(display);//進入循環glutMainLoop();return 0; }void display() {//設定背景色,并把背景色設置為窗口顏色glClearColor(0.0, 0.0, 0.0, 0.0);glClear(GL_COLOR_BUFFER_BIT);//繪制多邊形圖形//以凹點為起始開始繪制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();//開始執行glFlush(); }- 添加顏色
哈哈哈哈好丑
- 問題:實驗要求填色用雙緩存區,我用了之后窗口變成白色
解決:雙緩存 用glutSwapBuffers();代替glFlush,這個函數的作用是交換兩個緩沖區的內容,并把隱藏的渲染好的顯示出來。
基本圖元生成程序框架(畫直線圓)
唉把這個寫完是真的不容易
很多原本第一次看都難哭的東西,都看幾遍至少都能看懂了,重要是耐心。
問題與解決
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控制,真沒看懂怎么回事,設置斷點調試的時候跟直接運行結果不一樣。具體可能是框架的原因吧,暫時先放這里。
//對畫線動畫進行控制if (n == 1){cout << "DDA算法:各點坐標\n";}else if(n==0){return;}還有這個也很迷,就是直線還挺好理解,放到圓那邊就稍微有點暈,弄錯了會出現一直閃的效果。
//繪制到比上一幀多一個像素點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;//動畫時繪制點的數目 int m_drawmode = 1;//繪制模式 // 1 DDA算法畫直線 // 2 中點Bresenham算法畫直線 // 3 改進Bresenham算法畫直線 // 4 八分法繪制圓 // 5 四分法繪制橢圓(選作)//初始化窗口 void initial(); //窗口大小改變時調用的登記函數 void ChangeSize(GLsizei w, GLsizei h); //設置鍵盤回調函數 void Keyboard(unsigned char key, int x, int y); //設置時間回調函數 void TimerFunc(int value); //在窗口中繪制圖形 void Redraw(); //繪制坐標線 void DrawCordinateLine(); //繪制一個點,這里用一個正方形代表一個點 void PutPixel(GLsizei x, GLsizei y); //參數說明:x0,y0 起始點 // x1,y1 終止點 // n 掃描轉換時從起點開始輸出的點的數目,用于動畫 // 1 DDA算法畫直線 void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); // 2 中點Bresenham算法畫直線 void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); // 3 改進Bresenham算法畫直線 void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n); //參數說明:x0,y0 圓心坐標 // r 半徑 // n 掃描轉換時從起點開始輸出的點的數目,用于動畫 // 4 八分法繪制圓 void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r, GLsizei n); // 5 四分法繪制橢圓(選作) //參數說明:x0,y0 圓心坐標 // a b 長半軸為a 短半軸為b // n 掃描轉換時從起點開始輸出的點的數目,用于動畫 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);//鍵盤響應回調函數glutTimerFunc(100, TimerFunc, 1);//窗口初始化initial();glutMainLoop();//啟動主glut事件處理循環return 0;}void initial() {//設置清除色,并設置窗口背景色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;//設置視區glViewport(0, 0, w, h);//重置坐標系統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 恢復為 0" << endl;glutPostRedisplay(); }void TimerFunc(int value) {if (m_pointnumber == 0) value = 1;m_pointnumber = value;//用現有的參數重新繪圖(即動畫中新的一幀)glutPostRedisplay();//注意,該函數與其他的回調函數不一樣的地方在于該函數只會被激發一次。為了實現連//續的動畫,必須在定時器函數中再次重新設置定時器回調函數。glutTimerFunc(50, TimerFunc, value + 1); }void Redraw() {//用當前背景色填充窗口glClear(GL_COLOR_BUFFER_BIT);//畫坐標線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);//坐標線為黑色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) {//繪制矩形所在的坐標?glRectf(x * 10, y * 10, x * 10 + 10, y * 10 + 10); }void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設置顏色glColor3f(1.0f, 0.0f, 0.0f);//對畫線動畫進行控制if (n == 1){cout << "DDA算法:各點坐標\n";}else if(n==0){return;}//畫線算法實現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)就決定了要畫像素的數目for (i = 0; i <= epsl; i++) {PutPixel((int)(x + 0.5), (int)(y + 0.5));//繪制到比上一幀多一個像素點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;//超出窗口坐標if (x >= 25 || y >= 25) break;} }void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "中點BresenhamLine算法:各點坐標及判別式的值\n";}else if (n == 0) {return;}//畫線算法實現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 畫線參數不同 d = dx - 2 * min(abs(dx), abs(dy));//max(abs(dx), abs(dy)))就決定了要畫像素的數目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;}//繪制到比上一幀多一個像素點if (i >= n - 1) {cout << "n=" << n << ", x=" << x << ", y=" << y << ", 判別式 d="<< d << endl << endl;break;}//超出窗口坐標if (x >= 25 || y >= 25) break;} }void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {//設置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法:各點坐標及判別式的值\n";}else if (n == 0) {return;}//畫線算法實現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 和 相關參數 取決于 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;}//繪制到比上一幀多一個像素點if (i >= n) {cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判別式 e="<< e << endl << endl;break;}//超出窗口坐標if (x >= 25 || y >= 25) break;} }void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r, GLsizei n) {//設置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法畫圓:各點坐標及判別式的值\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++; //超出窗口坐標if (x >= 25 || y >= 25) break;}}void BresenhamEllipse(GLsizei x0, GLsizei y0, GLsizei a, GLsizei b, GLsizei n) {//設置顏色glColor3f(1.0f, 0.0f, 0.0f);if (n == 1){cout << "BresenhamLine算法畫橢圓:各點坐標及判別式的值\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--;}//超出窗口坐標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--;}//超出窗口坐標if (x >= 25 || y >= 25) break;}}}
反走樣
原來 changesize的函數不是通用啊。。。。
#include <windows.h> #include <gl/glut.h> #include <iostream> using namespace std; //指定顯示列表 GLuint lineList; //初始化窗口 void initial(); //窗口大小改變時調用的登記函數 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事件處理循環return 0;}void initial() {//設置清除色,并設置窗口背景色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;//設置視區glViewport(0, 0, w, h);//重置坐標系統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);//使用混合函數glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//指定混合函數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事件處理循環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() {//設置清除色,并設置窗口背景色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(); }不同屬性的點和線
#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); //用當前背景色填充窗口glColor3f(0.0f, 0.0f, 0.0f); //設置當前的繪圖繪圖RGB顏色//繪制不同大小的點GLfloat sizes[2]; //保存繪制點的尺寸范圍GLfloat step = 0.125; //保存繪制點尺寸的步長GLfloat curSize; //當前繪制的點的大小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的點劃線glLineWidth(3);glLineStipple(1, 0xFF0C);glBegin(GL_LINES);glVertex3f(25.0, 80.0, 0.0);glVertex3f(225.0, 80.0, 0.0);glEnd();//增加重復因子繪制的點劃線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命令隊列 } void ChangeSize(int w, int h) {winWidth = w; winHeight = h;glViewport(0, 0, w, h); //指定窗口的顯示區域glMatrixMode(GL_PROJECTION); //設置投影參數glLoadIdentity();gluOrtho2D(0.0, winWidth, 0.0, winHeight); }掃描填充算法
要在項目下新建一個輸入坐標的 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,將多邊形的較低頂點在 nScanLine上的邊,裝入邊表 g_pEdgeList 的 第 nScanLine 分量中{g_pEdgeList[i].nScanLine = nScanLine;for (int j = 0; j < g_polyPoints.n; ++j) //遍歷多邊形的頂點,找到滿足條件的邊{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(當前掃描線)的邊結點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; //對當前活動邊表 g_pActiveEdgeList[j].pItem 進行填充while (pNext && bEven){bFill = !bFill;if (bFill) //通過bFill控制填充區間的始點{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) //此循環將活動邊表 g_pActiveEdgeList[kk].pItem 每個結點的x變為x+1/k,修正后的結點順序正好倒序了{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) //此循環將邊表 g_pEdgeList[kk].pItem 中第kk掃描線的邊結點信息倒序插在 活動邊表 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)}//這里為了簡單所以把分配的內存放在vector容器中,方便刪除vector<EdgeItem*>::iterator itr = g_pItemVector.begin();vector<EdgeItem*>::iterator endItr = g_pItemVector.end();while (itr != endItr){delete (*itr);++itr;}g_pItemVector.clear(); }//繪制坐標線 void DrawCordinateLine(void) {int i = 0;//坐標線為黑色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();} //繪制一個點,這里用一個正方形表示一個點。 void display(void) {glClear(GL_COLOR_BUFFER_BIT);//畫出坐標線DrawCordinateLine();// Fill a polygonglColor3f(1.0f, 0.0f, 0.0f);activEdgeListFillPolygon();DrawPolygonLine();glutSwapBuffers(); }void reshape(GLsizei w, GLsizei h) {if (h == 0)h = 1;// 設置視區尺寸glViewport(0, 0, w, h);// 重置坐標系統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; }總結
以上是生活随笔為你收集整理的图形学实验(1)--OpenGL 入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM 之 内存分配与回收策略
- 下一篇: 长尾关键词有什么作用?要怎么用?