计算机图形学——实验五 基本图形学算法及着色器初步编程

实验五 基本图形学算法及着色器初步编程

实验项目性质:验证性实验

所属课程名称:计算机图形学A

实验计划学时:3学时

一、实验目的

  1. 理解基本图形元素光栅化的基本原理,理解直线裁剪算法的原理;
  2. 掌握直线的光栅化算法:DDA和Bresenham算法;
  3. 掌握直线裁剪算法:Cohen-Surtherland算法;

二、实验内容

  1. 编程实现DDA算法Bresenham算法生成直线。
  2. 实现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裁剪算法,通过代码进行修改、调试运行,最终实现直线的裁剪。通过此次实验,学习了使用不同的算法实现直线的光栅化和裁剪,收获颇多,对图形学的知识有了进一步的学习。

猜你喜欢

转载自blog.csdn.net/weixin_48388330/article/details/123193645