OpenGL光柵化作業:【bresenham算法】GL_POINTS為基礎畫圓


As usual先讀題。

2.3 Draw a Circle

Implement your circle rasterization algorithm in OpenGL. You can only use integer arithmetic in your code.

  • Input: A point as the center of a circle and a radius, that make 3 integers
  • Output: A circle in a window
  • You can only use the GL_POINTS as primitives. Others primitives or build-in draw is not allowed to use.

嘛,所以其實也是跟前面畫線段的算法一樣,也是用GL_POINTS畫出足夠多且密集的離散點在視覺意義上產生一個圓形。有很多類似的地方,控制輸入范圍為[-500,500]區間的整數再規格化到[-1,1]的浮點數等等,這些分析,就不廢話了直接看前面那篇講畫線段的前半截就好。

由於在畫圓方面沒有什么思路,所以參考了一下網上的畫圓算法。注明參考出處:http://www.cnblogs.com/gamesky/archive/2012/09/03/2668932.html

並且

由於數學確實差(……)所以也沒有做算法推導,直接用了以上這篇博文推導出的結論。也就是:

【先假設圓心的坐標為原點】。

先算出從(0, r)到(r/√2, r/√2)之間的1/8圓弧的點的坐標值,其他部分直接用軸對稱和中心對稱變換,最后畫出完整的圓形。

也就是計算出那特定的1/8圓弧上的點的坐標(x,y),再繪制出相應的(x, -y), (-x, y), (-x, -y), (y, x), (-y, x), (y, -x), (-y, -x)。

 

而那1/8圓弧上因為x上的變化比y大,所以在x方向上取樣,在y方向上量化。遞推思想就是:

d0=1-r

if d<0  d=d+2*x+3

if d>=0  d=d+2*(x-y)+5, y=y-1

x=x+1

 

並且直接在glBegin()和glEnd()之間用一個while(y>x)的循環,繪制出(x,y)和它相應的對稱點就好,也不需要用畫線段時導入數組的辦法了(畢竟哪里一不小心就下標越界還占內存orz)。當然這里在調用glVertex的時候傳入的參數(1)首先要是浮點數,所以仍然要做一個規格化處理normalize()。(2)要考慮到圓心坐標其實未必是原點的情況,對得到的浮點數坐標還要做一個浮點圓心坐標(fcx, fcy)的平移。

也就是

  while(y>x) {
                float fx=normalize(x);
                float fy=normalize(y);
                //(x,y) (-x,-y) (-x,y) (x,-y)
                glVertex2f(fcx+fx,fcy+fy);
                glVertex2f(fcx-fx,fcy-fy);
                glVertex2f(fcx-fx,fcy+fy);
                glVertex2f(fcx+fx,fcy-fy);
                
                //(y,x) (-y,-x) (-y,x) (y,-x)
                glVertex2f(fcx+fy,fcy+fx);
                glVertex2f(fcx-fy,fcy-fx);
                glVertex2f(fcx-fy,fcy+fx);
                glVertex2f(fcx+fy,fcy-fx);
                
                if(d<0) {
                    d=d+2*x+3;
                } else {
                    d=d+2*(x-y)+5;
                    --y;
                }
                ++x;
            }

其次就是畫完y>x部分的1/8圓弧和與其對稱的圓弧之外,我發現這樣寫其實沒有考慮到x=y,x=-y的點的情況。雖然這樣圓看起來也沒什么影響,但由於強迫症,所以還是加上一段:

            //need the 4 points on the diagonal
            float diagonal=float(r)/sqrt(2);
            glVertex2f(fcx+diagonal,fcy+diagonal);
            glVertex2f(fcx-diagonal,fcy+diagonal);
            glVertex2f(fcx+diagonal,fcy-diagonal);
            glVertex2f(fcx-diagonal,fcy+diagonal);

不過我想了一下,在前面的while循環判斷條件改成y>=x可能就好了,雖然可能會出現重復繪制的情況(……),不過寫都寫了就這樣吧呵呵呵呵呵呵呵

 

然后如果看了前面那篇參考博文的內容,其他反正都挺好懂的就不講廢話了直接上完全代碼。

 1 #include <iostream>
 2 #include <math.h>
 3 #include <GLFW/glfw3.h>
 4 using namespace std;
 5 //g++ -o demo circle.cpp -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo
 6 float normalize(int input) {
 7     return float(input)/500;
 8 }
 9 
10 //-400 100 200
11 int main() {
12     int r, cx,cy;
13     cout << "Please give the coordinate of the center of the circle? like 'x y'" << endl
14     << "Notice: x and y should be integers between 0 and 500" << endl;
15     cin >> cx >> cy;
16     cout << "Please give the radius r of the circle" << endl
17     << "Notice: r should be an integer between 0 and 500" << endl;
18     cin >> r;
19     float fcx=normalize(cx);
20     float fcy=normalize(cy);
21     
22     int x=0,y=r;
23     int d=1-r;
24     
25     
26     bool init = true;
27     if(!glfwInit()) {
28         cout << "Initialization failed" << endl;
29         init = false;
30         return -1;
31     }
32     
33     //create a window with its OpenGL context
34     GLFWwindow* window1 = glfwCreateWindow(640, 640, "Circle", NULL, NULL);
35     
36     if (!window1) {
37         cout << "Window or OpenGL context creation failed" << endl;
38         glfwTerminate();
39         return -1;
40     }
41     if(init&&window1) {
42         // Make the window's context current */
43         glfwMakeContextCurrent(window1);
44         
45         while (!glfwWindowShouldClose(window1)) {
46             // Keep running
47             /* Draw a triangle */
48             glBegin(GL_POINTS);
49             
50             glColor3f(1, 0.52, 0.0);    // Orange
51             //glVertex2f
52             
53             while(y>x) {
54                 float fx=normalize(x);
55                 float fy=normalize(y);
56                 //(x,y) (-x,-y) (-x,y) (x,-y)
57                 glVertex2f(fcx+fx,fcy+fy);
58                 glVertex2f(fcx-fx,fcy-fy);
59                 glVertex2f(fcx-fx,fcy+fy);
60                 glVertex2f(fcx+fx,fcy-fy);
61                 
62                 //(y,x) (-y,-x) (-y,x) (y,-x)
63                 glVertex2f(fcx+fy,fcy+fx);
64                 glVertex2f(fcx-fy,fcy-fx);
65                 glVertex2f(fcx-fy,fcy+fx);
66                 glVertex2f(fcx+fy,fcy-fx);
67                 
68                 if(d<0) {
69                     d=d+2*x+3;
70                 } else {
71                     d=d+2*(x-y)+5;
72                     --y;
73                 }
74                 ++x;
75             }
76             //need the 4 points on the diagonal
77             float diagonal=float(r)/sqrt(2);
78             glVertex2f(fcx+diagonal,fcy+diagonal);
79             glVertex2f(fcx-diagonal,fcy+diagonal);
80             glVertex2f(fcx+diagonal,fcy-diagonal);
81             glVertex2f(fcx-diagonal,fcy+diagonal);
82             
83             x=0;
84             y=r;
85          
86             
87             glEnd();

 

簡單說一下在代碼最初的調試更改出現過一些什么弱智問題。

當輸入圓心不是原點的時候,整個圓就支離破碎裂成了好幾塊,裂出的圓弧位置還不一樣。調試了半天發現原來是對稱那部分出了問題。把該加上fy的部分和fx的部分寫反了(……)。

 62                 //(y,x) (-y,-x) (-y,x) (y,-x)
 63                 glVertex2f(fcx+fy,fcy+fx);
 64                 glVertex2f(fcx-fy,fcy-fx);
 65                 glVertex2f(fcx-fy,fcy+fx);
 66                 glVertex2f(fcx+fy,fcy-fx);

還有就是圓看起來不夠圓,像個橢圓。其實就是應該把窗口尺寸調整到長寬一致的正方形就好了(……),因為長寬尺寸不一致的話x軸和y軸的單位長度就不一樣嘛。

 

另外就是繪制好了之后用鼠標調整窗口尺寸或者放大后,圖形就消失了(——!)。對照沒這個問題的線段繪制代碼看了半天,原來是為了保持窗口一直顯示圖形,glBegin()和glEnd()之間的代碼會反復循環地繪制直到窗口關閉。所以在glEnd()前要重新給x和y賦初值,不然后面就繪制不出來了。這個我以為已經改好了,剛才試着跑了一下發現交了作業的代碼忘記改這個了(——!),所以臨時加上去了給x和y賦初值的代碼。不知道為什么看起來圓的線條粗了一些,唉不想討論了就讓往事隨風(……)。

 

結果展示

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM