[XJTUSE]计算机图形学第二章作业,使用OpenGL编程实现DDA、中点画线和Bresenham算法和中点画圆法

首先是Windows10 + Visual Studio 2019 搭建OpenGL环境可以查看如下链接:

萌新向!!!Windows10 + Visual Studio 2019 搭建OpenGL环境(图文教程) - 哔哩哔哩 (bilibili.com)

//使用PC端浏览器打开,Android端似乎被删除了

一、计算机图形学第二章作业

1、题目描述

第二章 作业

1. 编程实现DDA、中点画线和Bresenham算法,对比它们的效率。

2. 编程实现中点画圆法。(重点关注算法原理和伪代码)

2、题目一

2.1关于DDA的实现

2.1.1算法原理

原理:根据直线的参数微分方程计有dy=m*dx

Step1:首先将给定端点作为了输入参数;

Step2:其次初始化,初值加上0.5保证精度;

Step3:比较起止点的水平以及垂直的差值较大的大数作为计算步数steps;

Step4:然后每步计算dx,dy分别为差数并除以steps;

Step5:最后,从起始点开始来确定相邻两点间的增量并且进行递推计算。

2.1.2算法实现

具体代码如下:

#include <Windows.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>

void DDAline()
{
	int x1=101,y1=101,x2=499,y2=499;
	int steps;
	float m, x, y, dx, dy;

	x = x1 + 0.5f;
	y = y1 + 0.5f;
	steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);

	dx = (float)(x2 - x1) / steps;
	dy = (float)(y2 - y1) / steps;

	//计算直线斜率和截距
	m = (float)(y2 - y1) / (float)(x2 - x1);
	float b = y2 - m * x2;
	glClear(GL_COLOR_BUFFER_BIT);
	glPointSize(1.0f);
	glBegin(GL_POINTS);
	for (int i = 0; i < steps; i++) {
			glVertex2f((x + 400 / 2)/400.0-1.6, (400 / 2 - y)/400.0+0.5);
			x=x+dx;
			y=y+dy;
	}
	glEnd();
	glFlush();
}

int main(int argc, char * argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("DrawLineByDDA");
	glutDisplayFunc(&DDAline);
	glutMainLoop();
	return 0;
}

2.1.3结果展示

2.2中点画线

2.2.1算法原理

原理:构造判别式:d=F(M)=F(xp+1,yp+0.5) =a(xp+1)+b(yp+0.5)+c

其中a=y0-y1, b=x1-x0, c=x0 y 1-x1 y 0

d<0M L(Q)下方,取右上方P 2为下一个象素

d>0M L(Q)上方,取右下方P 1为下一个象素

d=0,选P 1 或 P 2均可,约定取P 1为下一个象素

Step1:画线从(x0, y0 )开始,d的初值 d 0=F(x0+1, y0+0.5)=F(x0, y0)+a+0.5b =a+0.5ba=y0-y1, b=x1-x0

可以用2d代替d来摆脱小数,提高效率。

Step2:令 d 0=2a+b, d1=2a, d2=2a+2b,我们有如下算法 。

Step3:若当前象素处于d ³ 0情况,则取正右方象素P1 (xp+1, yp), 要判下一个象素位置,应计算 d 1=F(xp+2, yp+0.5)=a(xp+2)+b(yp+0.5)=d+a; 增量为a

d<0时,则取右上方象素P 2 (xp+1, yp+1)。要判断再下一象素,则要计算 d 2= F(xp+2, yp+1.5)=a(xp+2)+b(yp+1.5)+c=d+a+b ;增量为ab

Step4:画出对应的点

2.2.2算法实现

具体代码如下:

#include <Windows.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>

float X[65536], Y[65536];
int cnt = 0;

void MidPointline(int x1, int y1, int x2, int y2)
{
	int a, b, d1, d2, d, x, y;
	a = y1 - y2;b = x2 - x1;d = 2 * a + b;
	d1 = 2 * a;d2 = 2 * (a + b);
	x = x1; y = y1;
	X[0] = x;Y[0] = y;cnt++;
	while (x < x2)
	{
		if (d < 0)
		{
			x++;y++;d += d2;
		}
		else
		{
			x++;d += d1;
		}
		X[cnt] = x;Y[cnt] = y;cnt++;
	}
}



void midPoints()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glPointSize(1.0f);
	glBegin(GL_POINTS);
	for (int i = 0; i < cnt; i++) {
		glVertex2f((X[i] + 400 / 2) / 400.0 - 1.6, (400 / 2 - Y[i]) / 400.0 + 0.5);
	}
	glEnd();
	glFlush();
}

int main(int argc, char* argv[])
{
	MidPointline(101, 101, 499, 499);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("DrawLineBymidPoints");
	glutDisplayFunc(&midPoints);
	glutMainLoop();
	return 0;
}

2.2.3结果展示

2.3实现Bresenham算法

2.3.1算法原理

原理如下:

Step1:设定interChange、Xsign、Ysign便于判断位置并计算误差初值e = 2 * min - max;(min和max分别为水平距离和垂直距离的最值)

Step2:设置点(Xi, Yi) 的颜色值,并求下一误差ei+1;

If ei >= 0 then ei+1 =ei+m-1;

else ei+1 = ei + m;

Step3:根据不同象限,确定X和Y变化符号的正负,进行下一次(2)(3)循环直至结束;

2.3.2算法实现

#include <Windows.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>

void B()
{
	int x1 = 101, y1 = 101, x2 = 499, y2 = 499;
	int x, y, dx, dy, e, xSign, ySign, interChange = 0;
	dx = abs(x2 - x1);
	dy = abs(y2 - y1);

	float m = (float)(y2 - y1) / (float)(x2 - x1);
	float b = y2 - m * x2;

	if (dx < dy) {
		int temp;
		interChange = 1;
		temp = dx;
		dx = dy;
		dy = temp;
	}

	xSign = (x2 > x1) ? 1 : -1;
	ySign = (y2 > y1) ? 1 : -1;
	x = x1;
	y = y1;
	e = 2 * dy - dx;
	glClear(GL_COLOR_BUFFER_BIT);
	glPointSize(1.0f);
	glBegin(GL_POINTS);
	for (int i = 0; i <= dx; i++) {
		glVertex2f((x + 400.0 / 2) / 400.0 - 1.6, (400.0 / 2 - y) / 400.0 + 0.5);
		if (e > 0) {
			e = e - 2 * dx;
			if (interChange)
				x += xSign;
			else
				y += ySign;
		}
		if (interChange)
			y += ySign;
		else
			x += xSign;
		e = e + 2 * dy;
	}
	glEnd();
	glFlush();
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("DrawLineByBresenham");
	glutDisplayFunc(&B);
	glutMainLoop();
	return 0;
}

2.3.3结果展示

2.4三种方法效率的比较

DDA算法:

复杂度:加法+取整

优点:避免了y=kx+b 方程中的浮点乘法。

缺点:需浮点数加法及取整运算,不利于硬件实现。

中点算法:

中点算法与DDA相比,主要是加法运算和浮点数运算,但是优化后,省去了浮点运算。

主要优点:算法简单,无乘除,只有移位操作,尤其适用硬件实现

Bresenham算法:

Bresenham算法是计算机图形学使用最广泛的直线光栅化算法。Bresenham算法是每个象素只需一个整数加法,其优点还有就是可以用于其他二次曲线。

3、题目二

3.1算法原理

        中点画圆法利用的也是类似于Bresenham直线算法的思想,利用判别式选择像素,只需做简单的整数运算。

        在平面直角坐标系的四个象限中第二象限的1/8圆为例,若确定了一个像素点为($x_{p},y_{p}$),那么下一个点要么是右方的P1,要么是右下方的P2。

        构造函数一个函数F(x,y)=$x^{2}$+$y^{2}$-$R^{2}$,当F大于0时,点在圆外,反之则在圆内。

        图中的M是P1和P2的中点,所以M=($x_{p}$+1,$y_{p}-0.5$),当F(M)<0时,M在圆内,说明P1离圆弧更近,反之M在圆外,P2更近。

根据以上原理,可构造判别式:

   当$d_{p}$<0时,取P1为下一像素,下一像素判别式为:

    当$d_{p}$>0时,取P2为下一像素,下一像素判别式为:

     我们按顺时针方式生成八分圆,所以第一个像素为(0,R),初始判别式为:

   1.25-R可以简化成1-R,去除浮点数运算,因为运算过程中增量都为整数,所以减去0.25是不会影响符号的。

3.2算法实现

#include <Windows.h>
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>

float X[65536], Y[65536];
const float R = 400.0;
int cnt = 0;

void CirclePoints(int x, int y, int offx, int offy)//利用对称性画整圆
{
    X[cnt] = (x + offx) / R; Y[cnt] = (y + offy) / R;cnt++;
    X[cnt] = (y + offx) / R; Y[cnt] = (x + offy) / R;cnt++;
    X[cnt] = (x + offx) / R; Y[cnt] = (-y + offy) / R;cnt++;
    X[cnt] = (-y + offx) / R; Y[cnt] = (x + offy) / R;cnt++;
    X[cnt] = (-x + offx) / R; Y[cnt] = (y + offy) / R;cnt++;
    X[cnt] = (y + offx) / R; Y[cnt] = (-x + offy) / R;cnt++;
    X[cnt] = (-x + offx) / R; Y[cnt] = (-y + offy) / R;cnt++;
    X[cnt] = (-y + offx) / R; Y[cnt] = (-x + offy) / R;cnt++;
}

void MidPointCircle(int x1, int y1, int r)
{
    int x, y, e;
    x = 0; y = r; e = 1 - r;
    CirclePoints(x, y, x1, y1);
    while (x <= y)
    {
        if (e < 0)
            e += 2 * x + 3;
        else
        {
            e += 2 * (x - y) + 5;
            y--;
        }
        x++;
        CirclePoints(x, y, x1, y1);
    }
}

void B()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glPointSize(1.0f);
	glBegin(GL_POINTS);
    for(int i=0;i<cnt;i++)
		glVertex2f(X[i],Y[i]);
	glEnd();
	glFlush();
}

int main(int argc, char* argv[])
{
    MidPointCircle(0, 0, 380);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("DrawMidPointCircle");
	glutDisplayFunc(&B);
	glutMainLoop();
	return 0;
}

3.3结果展示

二、参考资料

 [1]萌新向!!!Windows10 + Visual Studio 2019 搭建OpenGL环境(图文教程) - 哔哩哔哩 (bilibili.com)

[2]三种直线段绘制方法:DDA算法、B算法和中点分割法_独苍的博客-CSDN博客

[3]图形学入门(2)——圆生成算法(中点画圆法) - 走看看 (zoukankan.com)

  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实验一 OpenGL+GLUT开发平台搭建 5 小实验1: 开发环境设置 5 小实验2: 控制窗口位置和大小 6 小实验3:默认的可视化范围 6 小实验4:自定义可视化范围 7 小实验5: 几何对象变形的原因 8 小实验6: 视口坐标系及视口定义 8 小实验7:动态调整长宽比例,保证几何对象不变形 9 实验二 动和交互 10 小实验1: 单缓冲动技术 10 小实验2: 双缓冲动技术 11 小实验3:键盘控制 13 小实验4:鼠标控制【试着单击鼠标左键或者右键,试着按下鼠标左键后再移动】 14 实验三 几何变换、观察变换、三维对象 16 小实验1:二维几何变换 16 小实验2:建模观察(MODELVIEW)矩阵堆栈 17 小实验3:正平行投影1 19 小实验4:正平行投影2 19 小实验5:正平行投影3 20 小实验6:透射投影1 21 小实验6:透射投影2 22 小实验7:三维对象 24 实验四 光照模型和纹理映射 26 小实验1:光照模型1----OpenGL简单光照效果的关键步骤。 26 小实验2:光照模型2----光源位置的问题 28 小实验3:光照模型3----光源位置的问题 31 小实验4:光照模型4----光源位置的问题 33 小实验5:光照模型5----光源位置的问题 35 小实验6:光照模型6----光源位置的问题 38 小实验7:光照模型7----光源位置的动态变化 40 小实验8:光照模型8----光源位置的动态变化 43 小实验9:光照模型9---光源位置的动态变化 45 小实验10:光照模型10---聚光灯效果模拟 48 小实验11:光照模型11---多光源效果模拟 50 小实验12:光照效果和雾效果的结合 53 小实验13:纹理映射初步—掌握OpenGL纹理映射的一般步骤 56 小实验13:纹理映射—纹理坐标的自动生成(基于参数的曲面映射) 59 小实验14:纹理映射—纹理坐标的自动生成(基于参考面距离) 61

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值