1. 程式人生 > >【OpenGL】使用DDA演算法畫線

【OpenGL】使用DDA演算法畫線

DDA(數字微分分析儀...好高大上的樣子)演算法其實就是利用直線方程來生成直線的演算法,給定起點(x0,y0)和終點(xEnd,yEnd),這條直線就唯一確定了,它的斜率是k=(yEnd-y0)/(xEnd-x0)。對於x方向我們取增量為1,那麼下一個x值,即xi+1=xi+1,這樣一來,y方向的增量就是斜率k,那麼yi+1=yi+k。利用這兩個加粗的方程,我們就可以遍歷這條直線,每到一個地方就把這裡的畫素點填充上顏色,一條直線就繪製好了,當然,具體的演算法實現有一些小細節,放到了註釋裡。

程式碼:

/*使用DDA演算法畫線*/
#include<iostream>
using namespace std;

#include<windows.h>
#include<math.h>
#include<gl/glut.h>

void myDisplay(void);//用這個函式來呼叫lineDDA
void setPixel(int x,int y);//教科書裡畫點的函式,在OpenGL中可以用glVertex來實現
int round(const float a);
void ChangeSize(GLsizei w, GLsizei h);
void lineDDA(int x0,int y0,int xEnd,int yEnd);

void myDisplay(void){
    //glClear(GL_COLOR_BUFFER_BIT);//好像沒這句話也可以啊。。初學好迷=。=
	lineDDA(50,50,200,200);
}

void setPixel(int x,int y){
	//用OpenGL自己的函式實現書上的setPixel
	glPointSize(5.0f);
	glBegin(GL_POINTS);
		glVertex2i(x,y);
	glEnd();
	glFlush();
}

int round(const float a){
	return int(a+0.5);
}

//視窗大小改變時呼叫的登記函式
void ChangeSize(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);
    else
        glOrtho(0.0f,250.0f*w/h,0.0f,250.0f,1.0,-1.0);
}

void lineDDA(int x0,int y0,int xEnd,int yEnd){
	glPointSize(3.0f);//設定畫素點大小
	int dx=xEnd-x0,dy=yEnd-y0,steps,k;
	float xIncrement,yIncrement,x=x0,y=y0;
	if(abs(dx)>abs(dy))//確定步長,誰大就取誰
		steps=abs(dx);
	else
		steps=abs(dy);
	xIncrement=float(dx)/float(steps);//增量當中有一個會為1,另一個會為斜率k
	yIncrement=float(dy)/float(steps);
	setPixel(round(x),round(y));//由於每次都加了小於1的增量,所以需要取整
	for(k=0;k<steps;k++){
		/*
		glBegin(GL_POINTS);
		glVertex2i((int)x,(int)y);
		glEnd();
		glFlush();
		*/
		x+=xIncrement;
		y+=yIncrement;
		setPixel(round(x),round(y));
	}
}

int main(int argc,char* argv[]){
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
	glutInitWindowPosition(200,200);
	glutInitWindowSize(400,400);
	glutCreateWindow("Daily Practice");
	glutDisplayFunc(&myDisplay);
	glutReshapeFunc(ChangeSize);
	glutMainLoop();
	return 0;
}

執行效果:


DDA簡單(好吧我是說在這種二維的情況下,今天老師提了一下三維的情形,感覺還是有點複雜的=。=),但是比較粗糙,取整的誤差會累積得越來越大,如果繪製的線比較長,畫素點比較多,偏離相對就比較大,第二是演算法整體耗時高,因為round和浮點運算比較耗時。