实验二 直线生成算法
实验类型:设计型 实验学时:2实验要求:必修
一、实验目的
理解基本图形元素光栅化的基本原理,掌握一种基本图形元素光栅化算法,利用OpenGL实现直线光栅化的DDA算法。
二、实验内容
1.根据所给的直线光栅化的示范源程序,在计算机上编译运行,输出正确结果;
2.指出示范程序采用的算法,以此为基础将其改造为中点线算法或Bresenham算法,写入实验报告;
3.根据示范代码,将其改造为圆的光栅化算法,写入实验报告;
4.了解和使用OpenGL的生成直线的命令,来验证程序运行结果。
三、实验原理
下面介绍下OpenGL画线的一些基础知识和glutReshapeFunc()函数。
(1)数学上的直线没有宽度,但OpenGL的直线则是有宽度的。同时,OpenGL的直线必须是有限长度,而不是像数学概念那样是无限的。可以认为,OpenGL的“直线”概念与数学上的“线段”接近,它可以由两个端点来确定。这里的线由一系列顶点顺次连结而成,有闭合和不闭合两种。
前面的实验已经知道如何绘“点”,那么OpenGL是如何知道拿这些顶点来做什么呢?是一个一个的画出来,还是连成线?或者构成一个多边形?或是做其它事情呢?为了解决这一问题,OpenGL要求:指定顶点的命令必须包含在glBegin函数之后,glEnd函数之前(否则指定的顶点将被忽略),并由glBegin来指明如何使用这些点。
则这两个点将分别被画出来。如果将GL_POINTS替换成GL_LINES,则两个点将被认为是直线的两个端点,OpenGL将会画出一条直线。还可以指定更多的顶点,然后画出更复杂的图形。另一方面,glBegin支持的方式除了GL_POINTS和GL_LINES,还有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每种方式的大致效果如图2所示:
图2 OpenGL几何图元类型 |
基础:
升级1:
升级三:
紫色的要求写出通用算法:
四、实验示范代码(略)
五、实验步骤
1 在Windows xp/win7操作环境下,启动VC;
2 建立W32 Console Application 的应用工程;
3 建立源程序编辑环境,进行编辑源程序。
4 调试运行程序,完成实验。
六、实验结果处理
演示结果并保存相关文件。
七、实验注意事项
注意编程环境的配置,即在Windows环境下,OpenGL扩展库相关文件的配置,把头文件“GL.H”、库文件“OPENGL32.LIB”和动态链接库“OPENGL32.DLL”配置到相应的目录下。
八、预习与思考题
预习:阅读课本相关内容,仔细阅读示范代码。
思考题:如何实现图线颜色和线宽的交互选择。
九、实验报告要求
1、实验报告中应包括相关操作步骤和程序代码和运行效果截图。
2.书写实验报告时要结构合理,层次分明,在分析描述的时候,需要注意语言的流畅。
基础代码:
#include "pch.h"
#include <iostream>
#include<GL/glut.h>
void LineDDA(float x0, float y0, float x1, float 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, (float)(y + 0.5));
glEnd();
y += m;
}
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glRectf(25., 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, 200);//传参画黄色线条
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;
}
升级1:
#include "pch.h"
#include <iostream>
using namespace std;
#include<GL/glut.h>
int color1=0, color2=0, color3=0;
int numbercolor;//定义线段颜色
int LineSize;//定义线段宽度;
void changecolor(int numbercolor)
{
if (numbercolor == 1) color1 = 1;
else if (numbercolor == 2) color2 = 1;
else if (numbercolor == 3) color3 = 1;
else if (numbercolor == 4) { color1 = 1; color2 = 1; }
else if (numbercolor == 5) { color2 = 1; color3 = 1; }
else if (numbercolor == 6) { color1 = 1; color3 = 1; }
else if (numbercolor == 7) { color1 = 1; color2 = 1; color3= 1; }
else cout << "数据不合法!";
}
void LineDDA(float x0, float y0, float x1, float y1)
{
float x, dy, dx, y;
float m;//定义变量表示斜率
dx = x1 - x0;
dy = y1 - y0;
m = dy / dx;
y = y0;
glColor3f(color1, color2, color3);
glPointSize(LineSize);
for (x = x0; x <= x1; x++)
{
glBegin(GL_POINTS);
glVertex2i(x, (float)(x + 0.5));
glEnd();
y += m;
}
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);//画左起第一个大矩形
glRectf(25.0, 25.0, 75.0, 75.0);
glRectf(120.0, 200.0, 125, 205.0);//画第二个小矩形
glPointSize(5);
glBegin(GL_POINTS);
glColor3f(color1, color2, color3); glVertex2f(0.0, 0.0);
glEnd();
LineDDA(0.0, 0.0, 200, 200);//画左起第一条线
glBegin(GL_LINES);//左起画第二条线
glColor3f(1.0, 0.0, 0.0); glVertex2f(100, 0);
glColor3f(0.0, 1.0, 0.0); glVertex2f(180.0, 240.0);
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[])
{
cout << "画线颜色按以下约定:"<<endl;
cout << " 红 绿 兰 黄 青 玫瑰 白"<<endl;
cout << "1(100); 2(010); 3(001); 4(110); 5(011); 6(101); 7(111)"<<endl;
cout << "请输入画线颜色(1-7) :";
cin >> numbercolor;
cout << "请输入线段宽度(1-10):";
cin >> LineSize;
changecolor(numbercolor);
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;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门提示:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
升级2:
#include "pch.h"
#include<math.h>
#include<GL/glut.h>
#include <iostream>
using namespace std;
float PI = 3.1415926f;
int instruction,n;
void plantCircle(float R,float color1,float color2,float color3){
int i = 0,n = 1000;//控制n的大小来相对精确画圆
glColor3f(color1, color2, color3);//设置圆形的颜色
glBegin(GL_POLYGON);
for (i = 0; i < n; i++)
glVertex2f(R*cos(2 * PI*i / n), R*sin(2 * PI*i / n));//通过数学计算定义顶点
glEnd();
}
void plantLine(float pi,float pi_Add,float R,float r)//绘制菱形边线、边心连线
{
for (pi; pi <= 2 * PI; pi += pi_Add ){ //调试过程中,发现PI/6如果表达成:(1/6)*PI会产生不必要的麻烦
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_STRIP);
if (n == 1) { glVertex2f(0, R); glVertex2f(0, -R); }
else {
glVertex2f(0.0, 0.0);
glVertex2f(r*sin(pi - pi_Add), r*cos(pi - pi_Add));//float r = 0.3;
glVertex2f(R*sin(pi - pi_Add / 2), R*cos(pi - pi_Add / 2));//float R= 0.52;
glVertex2f(0.0, 0.0);
glVertex2f(r*sin(pi), r*cos(pi));
glVertex2f(R*sin(pi - pi_Add / 2), R*cos(pi - pi_Add / 2));//float R= 0.52;
}
glEnd();
}
}
void plantLingxing(float pi, float pi_add, float R, float r)/*绘制菱形的函数*/{
for (pi; pi <= 2 * PI; pi += pi_add){
glBegin(GL_POLYGON);
glVertex2f(0.0, 0.0);
glVertex2f(r*sin(pi - pi_add), r*cos(pi - pi_add));//float r = 0.3;
glVertex2f(R*sin(pi - pi_add / 2), R*cos(pi - pi_add / 2));//float R= 0.52;
glVertex2f(r*sin(pi), r*cos(pi));
glEnd();
}
}
void myDisplay(void){
glClear(GL_COLOR_BUFFER_BIT);
if (instruction == 1){
plantCircle(0.52, 14 / 255.0, 0.0, 140 / 255.0);//绘制蓝色大背景的圆形
glColor3f(1.0, 1.0, 1.0);//定义12角星的颜色
plantLingxing(PI / 12, PI / 6,0.52,0.3);
plantCircle(0.28, 14 / 255.0, 0.0, 140 / 255.0);//绘制12角星内部的大蓝色圆
plantCircle(0.26, 1.0, 1.0, 1.0);//绘制12角星内部的小圆
}
else
{/*团中央的徽*/
if (n == 5){
plantCircle(0.52, 1.0, 1.0, 0.0);
plantCircle(0.48, 1.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 0.0);
plantLingxing(PI / n, 2 * PI / n, 0.48, 0.2);
plantLine(PI / n, 2 * PI / n, 0.48, 0.2);
}
else{/*普通图形*/
plantCircle(0.52, 1.0, 0.0, 1.0);//绘制粉色大圆
glColor3f(1.0, 1.0, 1.0);
plantLingxing(PI / n, 2 * PI / n, 0.52, 0.24);
plantLine(PI / n, 2 * PI / n, 0.52, 0.24);//glBegin() 与 glEnd()之间只能加一个操作函数,否则出错(无法显示)
}
}
glFlush();
}
void Init(){
glClearColor(0.0, 0.0, 0.0, 0.0);//方框背景置白
glShadeModel(GL_FLAT);
}
int main(int argc, char *argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
cout << "说明:图案形式选择1:绘制国民党党徽;"<<endl;
cout << "图案形式选择不为1,顶点数输入5:绘制共青团团徽!" << endl;
cout << "其余绘制花型图案!" << endl;
cout<<"请图案形式(1:国民党党徽, 其余不为1):" << endl;
cin >> instruction;
if (instruction != 1){
cout << "请输入多边形的顶点数(1<n<100):" << endl;
cin >> n;
}
glutInitWindowSize(600, 600);
glutCreateWindow("Hello world!");
Init();
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}
结果即为实验要求!