【OpenGL】计算机图形学实验二:基本图形的生成技术(直线、圆、椭圆生成算法)

实验二:基本图形的生成技术

(直线、圆、椭圆生成算法)

1、实验目的和要求

熟悉并掌握基本图形,特别是直线、圆和椭圆的基本生成算法,并能够用C++上机实现。

2、实验设备

PC机、CodeBlocks\VS系列\OpenGL安装包

3、实验内容及原理

分别用中点法、数值微分法、Bresenham法绘制任意直线,用Bresenham绘制圆,用中点法绘制椭圆(选做),并比较各种算法的差别。

实验原理(基本知识)

DDA数值微分算法:由于直线的一阶导数是连续的,且\Delta x\Delta y是成比例的,因此可以通过在当前位置\left( x_i,y_i \right)分别加上两个小增量\varepsilon \varDelta x\varepsilon \varDelta y\varepsilon是无穷小的正数)来求出下一点\left( x_{i+1}, y_{i+1} \right)x, y坐标。即有

\left\{ \begin{array}{c} x_{i+1}=x_i+\varepsilon \varDelta x\\ y_{i+1}=y_i+\varepsilon \varDelta y\\\end{array} \right.

中点Bresenham算法:每次在最大位移方向上走一步,而另一个方向是走步还是不走步取决于误差项的判别。

Bresenham法:基本原理同“中点Bresenham算法”。在中点Bresanham算法改进而来。只需要检查误差项e的符号即可确定某一列的像素。

4、实验源程序代码、运行结果

4.1 中点法绘制直线

4.1.1源程序代码

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

void resize(GLsizei w, GLsizei h) {
    if (h == 0) {
        h = 1;
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h) {
        glOrtho(-200.0f, 200.0f, -200.0f, 200.f * h / w, 1.0f, -1.0f);
    } else {
        glOrtho(-200.0f, 200.0f * w / h, -200.0f, 200.0f, 1.0f, -1.0f);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawPixel(int x, int y) {
    glBegin(GL_POINTS);
        glVertex2i(x, y);
    glEnd();
}

// MidBresenhamLine
void MidBresenhamLine(vector<int> p0, vector<int> p1) {
    int x0 = p0[0], y0 = p0[1],
        x1 = p1[0], y1 = p1[1];

    // 两种特殊情况: x0 == x1 || y0 == y1
    if (x0 == x1) {
        if (y0 > y1) {
            swap(y0, y1);
        }
        for (int i = y0; i <= y1; i++) {
            drawPixel(x0, i);
        }
        return ;
    } else if (y0 == y1) {
        if (x0 > x1) {
            swap(x0, x1);
        }
        for (int i = x0; i <= x1; i++) {
            drawPixel(i, y0);
        }
        return ;
    }

    int kRev = (y1 - y0) / (x1 - x0);
    bool isKGT1 = false;                                     // 1 : K is greater than 1
    bool isKNeg = (y1 - y0) * (x1 - x0) >= 0 ? false : true; // 1 : K is negative
    if (abs(kRev) >= 1) { // |k| > 1
        swap(x0, y0);
        swap(x1, y1);
        isKGT1 = true;
    }

    if (isKGT1) {
        if (isKNeg) {
            if (y0 < y1) {
                swap(y0, y1);
                swap(x0, x1);
            }
        } else {
            if (y0 > y1) {
                swap(y0, y1);
                swap(x0, x1);
            }
        }

    } else {
        if (x0 > x1) {
            swap(y0, y1);
            swap(x0, x1);
        }
    }

    int x = x0, y = y0;
    int dx = x1 - x0, dy = y1 - y0;
    
    int d = isKNeg ? -dx - 2 * dy : dx - 2 * dy;

    int incDLT0  = !isKNeg ? 2 * dx - 2 * dy : -2 * dy         ; // d < 0
    int incDGTE0 = !isKNeg ? -2 * dy         : -2 * dy - 2 * dx; // d >= 0
    cout << incDGTE0 <<' ' << incDLT0 << endl;
    while (x <= x1) {
//        cout << d << endl;
        if (isKGT1) {
            drawPixel(y, x);
        } else {
            drawPixel(x, y);
        }

        x++;
        if (d < 0) {
            if (!isKNeg) {
                y++;
            }
            d += incDLT0;
        } else {
            if (isKNeg) {
                y--;
            }
            d += incDGTE0;
        }
    }
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1, 0, 0);

    vector<int> p0(2), p1(2);
    p0[0] = 0, p0[1] = 0;
    p1[0] = -50, p1[1] = 100;
    MidBresenhamLine(p1, p0);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(10, 10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutCreateWindow("MidBresenhamLine");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    // setRC
    glClearColor(1, 1, 1, 1);

    glutMainLoop();

    return 0;
}

4.1.2运行结果

4.2 数值微分法绘制直线

4.2.1源程序代码

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

void resize(GLsizei w, GLsizei h) {
    if (h == 0) {
        h = 1; 
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h) {
        glOrtho(-200.0f, 200.0f, -200.0f, 200.f * h / w, 1.0f, -1.0f);
    } else {
        glOrtho(-200.0f, 200.0f * w / h, -200.0f, 200.0f, 1.0f, -1.0f);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawPixel(int x, int y) {
    glBegin(GL_POINTS);
        glVertex2i(x, y);
    glEnd();
}

// DDALine
void DDALine(vector<int> p0, vector<int> p1) {
    // 两种特殊情况: x0 == x1 || y0 == y1
    if (p0[0] == p1[0]) {
        if (p0[1] > p1[1]) {
            swap(p0[1], p1[1]);
        }
        for (int i = p0[1]; i <= p1[1]; i++) {
            drawPixel(p0[0], i);
        }
        return ;
    } else if (p0[1] == p1[1]) {
        if (p0[0] > p1[0]) {
            swap(p0[0], p1[0]);
        }
        for (int i = p0[0]; i <= p1[0]; i++) {
            drawPixel(i, p0[1]);
        }
        return ;
    }

    int dx = p1[0] - p0[0],
        dy = p1[1] - p0[1];
    double epsilon = 1 / max(abs(dx), abs(dy));
    double xInc = dx * epsilon, // X方向的增量
           yInc = dy * epsilon; // Y方向的增量

    double currX = p0[0], currY = p0[1]; // 当前X, Y坐标的值
    for (int i = 0; i <= max(abs(dx), abs(dy)); i++) {
        drawPixel(int(currX + 0.5), int(currY +0.5));
        currX += xInc;
        currY += yInc;
    }

}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1, 0, 0);

    vector<int> p0(2), p1(2);

    p0[0] = 10, p0[1] = 0;
    p1[0] = 100, p1[1] = 0;

    DDALine(p0, p1);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(400,400);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutCreateWindow("DDALine");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    // setRC
    glClearColor(1, 1, 1, 1);

    glutMainLoop();

    return 0;
}

4.2.2运行结果

4.3 Bresenham法绘制直线

4.3.1源程序代码

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

void resize(GLsizei w, GLsizei h) {
    if (h == 0) {
        h = 1;
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h) {
        glOrtho(-200.0f, 200.0f, -200.0f, 200.f * h / w, 1.0f, -1.0f);
    } else {
        glOrtho(-200.0f, 200.0f * w / h, -200.0f, 200.0f, 1.0f, -1.0f);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawPixel(int x, int y) {
    glBegin(GL_POINTS);
        glVertex2i(x, y);
    glEnd();
}

// BresenhamLine
void BresenhamLine(vector<int> p0, vector<int> p1) {
    int x0 = p0[0], y0 = p0[1],
        x1 = p1[0], y1 = p1[1];

    // 两种特殊情况: x0 == x1 || y0 == y1
    if (x0 == x1) {
        if (y0 > y1) {
            swap(y0, y1);
        }
        for (int i = y0; i <= y1; i++) {
            drawPixel(x0, i);
        }
        return ;
    } else if (y0 == y1) {
        if (x0 > x1) {
            swap(x0, x1);
        }
        for (int i = x0; i <= x1; i++) {
            drawPixel(i, y0);
        }
        return ;
    }

    int kRev = (y1 - y0) / (x1 - x0);

    bool isKGT1 = false; // 1 : K is greater than 1
    bool isKNeg = (y1 - y0) * (x1 - x0) >= 0 ? false : true; // 1 : K is negative
    if (abs(kRev) >= 1) { // |k| > 1
        swap(x0, y0);
        swap(x1, y1);
        isKGT1 = true;
    }

    if (isKGT1) {
        if (isKNeg) {
            if (y0 < y1) {
                swap(y0, y1);
                swap(x0, x1);
            }
        } else {
            if (y0 > y1) {
                swap(y0, y1);
                swap(x0, x1);
            }
        }

    } else {
        if (x0 > x1) {
            swap(y0, y1);
            swap(x0, x1);
        }
    }

    int x = x0, y = y0;
    int dx = x1 - x0, dy = y1 - y0;
    if (isKNeg) {
        dy = -dy;
    }

    int e = -dx;

    while (x <= x1) {
        if (isKGT1) {
            drawPixel(y, x);
        } else {
            drawPixel(x, y);
        }
        x++;
        e += 2 * dy;

        if (e > 0) {
            if (isKNeg) {
                y--;
            } else {
                y++;
            }
            e -= 2 * dx;
        }
    }


}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1, 0, 0);

    vector<int> p0(2), p1(2);
    p0[0] = 0, p0[1] = 0;
    p1[0] = 100, p1[1] = -150;
    BresenhamLine(p1, p0);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(10, 10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutCreateWindow("BresenhamLine");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    // setRC
    glClearColor(1, 1, 1, 1);

    glutMainLoop();

    return 0;
}

4.3.2运行结果

4.4 Bresenham法绘制圆

4.4.1源程序代码

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

void resize(GLsizei w, GLsizei h) {
    if (h == 0) {
        h = 1;
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h) {
        glOrtho(-200.0f, 200.0f, -200.0f, 200.f * h / w, 1.0f, -1.0f);
    } else {
        glOrtho(-200.0f, 200.0f * w / h, -200.0f, 200.0f, 1.0f, -1.0f);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawPixels(int x, int y) {
    glBegin(GL_POINTS);
        glVertex2i(x, y);
        glVertex2i(y, x);
        glVertex2i(-x, y);
        glVertex2i(y, -x);
        glVertex2i(x, -y);
        glVertex2i(-y, x);
        glVertex2i(-x, -y);
        glVertex2i(-y, -x);
    glEnd();
}

// BresenhamCircle
void BresenhamCircle(int r) {
    int x = 0, y = r;
    int d = 1 - r; // 判别式
    while (x <= y) {
        drawPixels(x, y);
        if (d < 0) {
            d += 2 * x + 3;
        } else {
            d += 2 * (x - y) + 5;
            y--;
        }
        x++;
    }
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1, 0, 0);

    BresenhamCircle(100);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(10, 10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutCreateWindow("BresenhamCircle");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    // setRC
    glClearColor(1, 1, 1, 1);

    glutMainLoop();

    return 0;
}

4.4.2运行结果

4.5中点法绘制椭圆

4.5.1源程序代码

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

void resize(GLsizei w, GLsizei h) {
    if (h == 0) {
        h = 1;
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    if (w <= h) {
        glOrtho(-200.0f, 200.0f, -200.0f, 200.f * h / w, 1.0f, -1.0f);
    } else {
        glOrtho(-200.0f, 200.0f * w / h, -200.0f, 200.0f, 1.0f, -1.0f);
    }

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void drawPixels(int x, int y) {
    glBegin(GL_POINTS);
        glVertex2i(x, y);
        glVertex2i(-x, y);
        glVertex2i(x, -y);
        glVertex2i(-x, -y);
    glEnd();
}

// MidBresenhamEllipse
void MidBresenhamEllipse(int a, int b) {
    double d1 = b * b + a * a * (-b + 0.25);
    int x = 0, y = b;
    drawPixels(x, y);
    while (b * b * (x + 1) < a * a * (y - 0.5)) {
        if (d1 <= 0) {
            d1 += b * b * (2 * x + 3);
            x++;
        } else {
            d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2);
            x++;
            y--;
        }
        drawPixels(x, y);
    }

    double d2 = b * b * (x + 0.5) * (x + 0.5) + a * a * (y - 1) * (y - 1) - a * a * b * b;
    while (y > 0) {
        if (d2 <= 0) {
            d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3);
            x++;
            y--;
        } else {
            d2 += a * a * (-2 * y + 3);
            y--;
        }

        drawPixels(x, y);
    }
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1, 0, 0);

    MidBresenhamEllipse(160, 80);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(10, 10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutCreateWindow("MidBresenhamEllipse");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);

    // setRC
    glClearColor(1, 1, 1, 1);

    glutMainLoop();

    return 0;
}

4.5.2运行结果

4.6各种算法的差别

4.6.1 DDA算法、中点Bresenham算法、Bresenham算法绘制的区别

DDA算法是一种增量算法,直观、容易实现。但是涉及浮点运算(currX, currY, xInc增量和yInc增量都是浮点类型),不利于硬件实现。

中点Bresenham算法的基本原理是每次在最大位移方向上走一步,另一个方向上走步还是不走步取决于误差项的判别。中点Bresenham算法在实现上比DDA算法更为复杂,但是增量可以通过整型实现,并且大部分运算都是加法和乘法,更加利于硬件实现,绘制效率也更高。该算法可以实现任意k值的直线段的绘制,《计算机图形学基础(第三版)》课本中给出了0≤k≤1时的实现代码,经过书本中的提示,我实现了其余情况的代码。

Bresenham算法是中点Bresenham算法的改进模式。其基本原理和中点Bresenham算法相同。它同样采用增量计算,对于每一列检查一个误差项的符号就可以确定该列的所求像素。

  • 3
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
计算机图形学实验OPENGL可视化 计算机图形学实验 opengl 三个实验 附有具体代码 跟VC6一样的 一、下载并安装glut库 opengl的glut库 GLUT不是OpenGL所必须的,但它会给我们的学习带来一定的方便,推荐安装。 Windows环境下的GLUT下载地址:(大小约为150k) http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip Windows环境下安装GLUT的步骤: 1、将下载的压缩包解开,将得到5个文件 2、在“我的电脑”中搜索“gl.h”,并找到其所在文件夹(Program Files\Microsoft Visual Studio\VC98\Include\GL文件夹”)。把解压得到的glut.h放到这个文件夹。 3、把解压得到的glut.lib和glut32.lib放到静态函数库所在文件夹(Program Files\Microsoft Visual Studio\VC98\lib”文件夹)。 4、把解压得到的glut.dll和glut32.dll放到操作系统目录下面的system32文件夹内。(典型的位置为:C:\Windows\System32) 、vc工程配置: 1)创建一个工程。glut 是一个console project ,你创建的时候必须创建console 以对应 . 2)链接OpenGL libraries。在Visual C++中先单击Project,再单击Settings,再找到Link单击, 在“分类”(Category)组合框里选择“输出”(output) ,再在“入口点”(Entry-point symbol)文本框里键入“mainCRTStartup” ,对一个现有的控制台应用程序,有一个简单的办法把它转换成Win32应用程序,这样可以摆脱那个命令行窗口。 3)单击Project Settings中的C/C++标签,将Preprocessor definitions 中的_CONSOLE改为__WINDOWS。最后单击OK。 增加下面的文件到“对象/库模块" (Object/library/modules):OpenGL32.lib glut32.lib glu32.lib (有时候不需要glut32.lib) 4)然后在stdafx.h文件中加入 #include #include #include #include #include 注意:#include 是需要的,不引入的话有时会报错。 完成后,就可以编写你自己的程序了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值