zoukankan      html  css  js  c++  java
  • 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赋初值的代码。不知道为什么看起来圆的线条粗了一些,唉不想讨论了就让往事随风(……)。

    结果展示

     

  • 相关阅读:
    問題集リンク(DEV I)
    認定Platformデベロッパー 試験範囲
    React 学习资源
    IIS
    小学校
    リストに項番をつける
    七、JavaScript函数
    六、JavaScript数组
    五、JavaScript流程控制
    四、JavaScript操作符
  • 原文地址:https://www.cnblogs.com/RDaneelOlivaw/p/6624927.html
Copyright © 2011-2022 走看看