实验五 基本图形学算法及着色器初步编程
实验项目性质:验证性实验
所属课程名称:计算机图形学A
实验计划学时:3学时
一、实验目的
- 理解基本图形元素光栅化的基本原理,理解直线裁剪算法的原理;
- 掌握直线的光栅化算法:DDA和Bresenham算法;
- 掌握直线裁剪算法:Cohen-Surtherland算法;
二、实验内容
- 编程实现DDA算法和Bresenham算法生成直线。
- 实现Cohen-Surtherland直线裁剪算法,调试、编译、修改程序。
三、实验代码
1.直线光栅化DDA算法
//DDA算法
#include
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
# include
# include
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
3.Cohen-Surtherland直线裁剪算法
#include
#include
#include
#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
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
# include
# include
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
#include
#include
#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
#include
#include
#include
#include
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裁剪算法,通过代码进行修改、调试运行,最终实现直线的裁剪。通过此次实验,学习了使用不同的算法实现直线的光栅化和裁剪,收获颇多,对图形学的知识有了进一步的学习。