实验五 基本图形学算法及着色器初步编程
实验项目性质:验证性实验
所属课程名称:计算机图形学A
实验计划学时:3学时
一、实验目的
- 理解基本图形元素光栅化的基本原理,理解直线裁剪算法的原理;
- 掌握直线的光栅化算法:DDA和Bresenham算法;
- 掌握直线裁剪算法:Cohen-Surtherland算法;
二、实验内容
- 编程实现DDA算法和Bresenham算法生成直线。
- 实现Cohen-Surtherland直线裁剪算法,调试、编译、修改程序。
三、实验代码
1.直线光栅化DDA算法
//DDA算法 #include <GL/glut.h> void LineDDA(int x0, int y0, int x1, int y1) { int x, dy, dx, y; float m; dx = x1 - x0; dy = y1 - y0; m = dy / dx; y = y0; glColor3f(1.0f, 1.0f, 0.0f); glPointSize(1); for (x = x0; x <= x1; x++) { glBegin(GL_POINTS); glVertex2i(x, (int)(y + 0.5)); glEnd(); y += m; } } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(25.0, 25.0, 75.0, 75.0); glPointSize(5); glBegin(GL_POINTS); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.0f, 0.0f); glEnd(); LineDDA(0, 0, 200, 300); glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(100.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(180.0f, 240.0f); glEnd(); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); } int main(int argc, char * argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("Hello World!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutMainLoop(); return 0; }
要求:
根据所给的直线光栅化的示范源程序,在计算机上编译运行,输出正确结果(示范代码有错误,指出并改正)。
2.直线光栅化Bresenham算法
# include "stdafx.h" # include <GL/glut.h> # include <windows.h> # include <math.h> void MidBresenhamLine(int x0, int y0, int x1, int y1) { int dx, dy, d, UpIncre, DownIncre, x, y; if(x0>x1) { x = x1; x1 = x0; x0 = x; y = y1; y1 = y0; y0 = y; } x = x0; y = y0; dx = x1 - x0; dy = y1 - y0; glColor3f(1.0f, 1.0f, 0.0f); glPointSize(1); if(dx>dy) { d=dx-2*dy; UpIncre=2*dx-2*dy; DownIncre=-2*dy; while(x<=x1) { glBegin(GL_POINTS); glVertex2i(x,y); glEnd(); x++; if(d<0) { y++; d+=UpIncre; } else d+=DownIncre; } } } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(25.0, 25.0, 75.0, 75.0); glPointSize(5); glBegin(GL_POINTS); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.0f, 0.0f); glEnd(); MidBresenhamLine(0,0,300,200); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 400.0, 0.0, 400.0); } int main(int argc, char * argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(600, 600); glutCreateWindow("Hello World!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutMainLoop(); return 0; }
要求:
示范代码给出了0<k<1的Bresenham算法,要求将代码补充完整,实现所有直线的Bresenham算法。
3.Cohen-Surtherland直线裁剪算法
#include <gl/glut.h> #include <stdio.h> #include <stdlib.h> #define LEFT_EDGE 1 #define RIGHT_EDGE 2 #define BOTTOM_EDGE 4 #define TOP_EDGE 8 void LineGL(int x0, int y0, int x1, int y1) { glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(x0, y0); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(x1, y1); glEnd(); } struct Rectangle { float xmin, xmax, ymin, ymax; }; Rectangle rect; int x0, y0, x1, y1; int CompCode(int x, int y, Rectangle rect) { int code = 0x00; if (y < rect.ymin) code = code | 4; if (y > rect.ymax) code = code | 8; if (x > rect.xmax) code = code | 2; if (x < rect.xmin) code = code | 1; return code; } int cohensutherlandlineclip(Rectangle rect, int &x0, int &y0, int &x1, int &y1) { int accept, done; float x, y; accept = 0; done = 0; int code0, code1, codeout; code0 = CompCode(x0, y0, rect); code1 = CompCode(x1, y1, rect); do { if (!(code0 | code1)) { accept = 1; done = 1; } else if (code0 & code1) done = 1; else { if (code0 != 0) codeout = code0; else codeout = code1; if (codeout&LEFT_EDGE) { y = y0 + (y1 - y0)*(rect.xmin - x0) / (x1 - x0); x = (float)rect.xmin; } else if (codeout&RIGHT_EDGE) { y = y0 + (y1 - y0)*(rect.xmax - x0) / (x1 - x0); x = (float)rect.xmax; } else if (codeout&BOTTOM_EDGE) { x = x0 + (x1 - x0)*(rect.ymin - y0) / (y1 - y0); y = (float)rect.ymin; } else if (codeout&TOP_EDGE) { x = x0 + (x1 - x0)*(rect.ymax - y0) / (y1 - y0); y = (float)rect.ymax; } if (codeout == code0) { x0 = x; y0 = y; code0 = CompCode(x0, y0, rect); } else { x1 = x; y1 = y; code1 = CompCode(x1, y1, rect); } } } while (!done); if (accept) LineGL(x0, y0, x1, y1); return accept; } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); LineGL(x0, y0, x1, y1); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); rect.xmin = 100; rect.xmax = 300; rect.ymin = 100; rect.ymax = 300; x0 = 450, y0 = 0, x1 = 0, y1 = 450; printf("Press key 'c' to clip!\nPress key 'r' to Restore!\n"); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'c': cohensutherlandlineclip(rect, x0, y0, x1, y1); glutPostRedisplay(); break; case 'r': Init(); glutPostRedisplay(); break; case 'x': exit(0); break; default: break; } } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(640, 480); glutCreateWindow("Hello world!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
要求:
请分别给出直线的三种不同位置情况,测试实验代码是否存在问题,如果有请调试改正。
4.选做题:实现Liang-Barsky裁剪算法。
四、实验代码
1.
//DDA算法 #include <GL/glut.h> void LineDDA(int x0, int y0, int x1, int y1) { float x, dy, dx, y; float m; dx = x1 - x0; dy = y1 - y0; m = dy / dx; y = y0; glColor3f(1.0f, 1.0f, 0.0f); glPointSize(1); for (x = x0; x <= x1; x++) { glBegin(GL_POINTS); glVertex2i(x, (int)(y + 0.5)); glEnd(); y += m; } } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(25.0, 25.0, 75.0, 75.0); glPointSize(5); glBegin(GL_POINTS); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.0f, 0.0f); glEnd(); LineDDA(0, 0, 200, 300); glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(100.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(180.0f, 240.0f); glEnd(); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("Hello World!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutMainLoop(); return 0; }
2.
//# include "stdafx.h" # include <GL/glut.h> # include <windows.h> # include <math.h> void MidBresenhamLine(int x0, int y0, int x1, int y1) { int dx, dy, d, UpIncre, DownIncre, x, y; if (x0 > x1) { x = x1; x1 = x0; x0 = x; y = y1; y1 = y0; y0 = y; } x = x0; y = y0; dx = x1 - x0; dy = y1 - y0; glColor3f(1.0f, 1.0f, 0.0f); glPointSize(1); if (dx > dy) { d = dx - 2 * dy; UpIncre = 2 * dx - 2 * dy; DownIncre = -2 * dy; while (x <= x1) { glBegin(GL_POINTS); glVertex2i(x, y); glEnd(); x++; if (d < 0) { y++; d += UpIncre; } else d += DownIncre; } } else { d = dy - 2 * dx; UpIncre = 2 * dy - 2 * dx; DownIncre = -2 * dx; while (y <= y1) { glBegin(GL_POINTS); glVertex2i(x, y); glEnd(); y++; if (d < 0) { x++; d += UpIncre; } else d += DownIncre; } } } void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(25.0, 25.0, 75.0, 75.0); glPointSize(5); glBegin(GL_POINTS); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.0f, 0.0f); glEnd(); MidBresenhamLine(0, 0, 200, 300); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 400.0, 0.0, 400.0); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(600, 600); glutCreateWindow("Hello World!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutMainLoop(); return 0; }
3.
#include <gl/glut.h> #include <stdio.h> #include <stdlib.h> #define LEFT_EDGE 1 #define RIGHT_EDGE 2 #define BOTTOM_EDGE 4 #define TOP_EDGE 8 void LineGL(int x0, int y0, int x1, int y1) { glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(x0, y0); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(x1, y1); glEnd(); } struct Rectangle { float xmin, xmax, ymin, ymax; }; struct Rectangle rect; int x0, y0, x1, y1; int CompCode(int x, int y, struct Rectangle rect) { int code = 0x00; if (y < rect.ymin) code = code | 4; if (y > rect.ymax) code = code | 8; if (x > rect.xmax) code = code | 2; if (x < rect.xmin) code = code | 1; return code; } int cohensutherlandlineclip(struct Rectangle rect, int& x0, int& y0, int& x1, int& y1) { int accept, done; float x, y; accept = 0; done = 0; int code0, code1, codeout; code0 = CompCode(x0, y0, rect); code1 = CompCode(x1, y1, rect); do { if (!(code0 | code1)) { accept = 1; done = 1; } else if (code0 & code1) done = 1; else { if (code0 != 0) codeout = code0; else codeout = code1; if (codeout & LEFT_EDGE) { y = y0 + (y1 - y0) * (rect.xmin - x0) / (x1 - x0); x = (float)rect.xmin; } else if (codeout & RIGHT_EDGE) { y = y0 + (y1 - y0) * (rect.xmax - x0) / (x1 - x0); x = (float)rect.xmax; } else if (codeout & BOTTOM_EDGE) { x = x0 + (x1 - x0) * (rect.ymin - y0) / (y1 - y0); y = (float)rect.ymin; } else if (codeout & TOP_EDGE) { x = x0 + (x1 - x0) * (rect.ymax - y0) / (y1 - y0); y = (float)rect.ymax; } if (codeout == code0) { x0 = x; y0 = y; code0 = CompCode(x0, y0, rect); } else { x1 = x; y1 = y; code1 = CompCode(x1, y1, rect); } } } while (!done); if (accept) LineGL(x0, y0, x1, y1); else { x0 = 0; y = 0; x1 = 0; y1 = 0; LineGL(x0, y0, x1, y1); } return accept; } void myDisplay() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); LineGL(x0, y0, x1, y1); glFlush(); } void Init() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); rect.xmin = 100; rect.xmax = 300; rect.ymin = 100; rect.ymax = 300; x0 = 0, y0 = 450, x1 = 400, y1 = 40; printf("Press key 'c' to clip!\nPress key 'r' to Restore!\n"); } void Reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'c': cohensutherlandlineclip(rect, x0, y0, x1, y1); glutPostRedisplay(); break; case 'r': Init(); glutPostRedisplay(); break; case 'x': exit(0); break; default: break; } } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(640, 480); glutCreateWindow("Hello world!"); Init(); glutDisplayFunc(myDisplay); glutReshapeFunc(Reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
4.
#include <windows.h> #include <GL/glut.h> #include <math.h> #include<stdio.h> #include <iostream> float xmin, xmax, ymin, ymax; using namespace std; void myinit(void) { glShadeModel(GL_FLAT); glClearColor(1.0, 1.0, 1.0, 0.0); } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) gluOrtho2D(0.0, 1.0, 0.0, 1.0 * (GLfloat)h / (GLfloat)w); else gluOrtho2D(0.0, 1.0 * (GLfloat)w / (GLfloat)h, 0.0, 1.0); glMatrixMode(GL_MODELVIEW); } int Clip(float p, float q, float* tL, float* tU) { int flag = 1;/*flag为标志变量0表示舍弃1表示可见*/ float r; if (p < 0.0) { r = q / p; if (r > *tU) flag = 0; else if (r > *tL) { *tL = r;/*m取进入点最大参数值*/ } } else if (p > 0.0) { r = q / p; if (r < *tL) flag = 0; else if (r < *tU) { *tU = r;/*n取离开点的最小值*/ } } else if (q < 0 && p == 0) //平行于边界而且在界外的线 flag = 0; return flag; } void myclip() // line clipping algorithm { float dx, dy, x1, tL, tU, x2, y1, y2; tL = 0, tU = 1.0; printf("请输入线段的两个顶点坐标x1,y1,x2,y2:\n"); //scanf("%f%f%f%f", &x1, &y1, &x2, &y2); cin >> x1 >> y1 >> x2 >> y2; glBegin(GL_LINES); glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(x1, y1); // line startpoint glVertex2f(x2, y2); // line endpoint glEnd(); dx = x2 - x1; if (Clip(-dx, x1 - xmin, &tL, &tU)) if (Clip(dx, xmax - x1, &tL, &tU)) { dy = y2 - y1; if (Clip(-dy, y1 - ymin, &tL, &tU)) if (Clip(dy, ymax - y1, &tL, &tU)) { if (tU < 1.0) { x2 = x1 + tU * dx;//通过n求得裁剪后的p2端点 y2 = y1 + tU * dy; } if (tL > 0.0) { x1 = x1 + tL * dx;//通过m求得裁剪后的p1端点 y1 = y1 + tL * dy; } glBegin(GL_LINES); glColor4f(1.0, 0.0, 0.0, 1.0); glVertex2f(x1, y1); // clipped line startpoint glVertex2f(x2, y2); // clipped line endpoint glEnd(); } } } void display(void) { glClear(GL_COLOR_BUFFER_BIT); printf("请分别输入矩形的左右下上边界:\n"); //scanf("%f%f%f%f", &xmin, &xmax, &ymin, &ymax); cin >> xmin >> xmax >> ymin >> ymax; glColor4f(1.0, 1.0, 0.0, 0.75); glBegin(GL_POLYGON); glVertex2f(xmin, ymin); // Bottom Left glVertex2f(xmax, ymin); // Bottom Left glVertex2f(xmax, ymax); // Bottom Right glVertex2f(xmin, ymax); // Bottom Right glEnd(); myclip(); glFlush(); } /* Main Loop * Open window with initial window size, title bar, * RGBA display mode, and handle input events. */ int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); //define size and the relative positon of the applicaiton window on the display glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); //init the defined window with "argv[1]" as topic showed on the top the window glutCreateWindow(argv[0]); // opengl setup myinit(); //define callbacks glutDisplayFunc(display); glutReshapeFunc(myReshape); //enter the loop for display glutMainLoop(); return 1; }
五、实验结果与心得
1.
编辑
2.
编辑编辑编辑
3.
编辑编辑
编辑编辑
编辑编辑
4.
编辑
本次实验对DDA和Bresenham算法进行调试,实现了直线的光栅化;以及直线裁剪算法Cohen-Surtherland和Liang-Barsky裁剪算法,通过代码进行修改、调试运行,最终实现直线的裁剪。通过此次实验,学习了使用不同的算法实现直线的光栅化和裁剪,收获颇多,对图形学的知识有了进一步的学习。