计算机图形学报告1
西安电子科技大学
计算机图形学 课程实验报告
实验名称 第一次上机实验
计算机 学院 1803012 班
姓名 曹王欣 学号 18030100167
同作者
实验日期 2020 年 月 日
实验地点 实验批次
指导教师评语:
指导教师: 年 月 日 |
实验报告内容基本要求及参考格式 一、实验目的 二、实验所用仪器(或实验环境) 三、实验基本原理及步骤(或方案设计及理论计算) 四、实验数据记录(或仿真及软件设计) 五、实验结果分析及回答问题(或测试环境及测试结果) |
- 简单图元的绘制(借鉴lec3课件)
- 在屏幕上绘制几何图元(如下图所示),自定义坐标和颜色。
第一次实验主要是熟悉opengl的绘图与使用,用到的基本函数如下:在glbegin和glend()之间写入点,然后glbegin()之中可以设置图元的属性,比如
//画点
glBegin(GL_POINTS);
//画线段
glBegin(GL_LINES);
//画开折线
glBegin(GL_LINE_STRIP);
//画闭折线
glBegin(GL_LINE_LOOP);
//画填充多边形
glBegin(GL_POLYGON);
//画四边形
glBegin(GL_QUADS);
//画连接四边形
glBegin(GL_QUAD_STRIP);
//画三角形
glBegin(GL_TRIANGLES);
//画连续三角形
glBegin(GL_TRIANGLE_STRIP);
//画扇形三角形
glBegin(GL_TRIANGLE_FAN);
总体的程序如下:
#include <GL/glut.h>
#include <cstdio>
#include <cmath>
void myinit()
{
glClearColor(1, 1.0, 1.0, 1.0);
}
void ChangeSize(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-20.0, 20.0, -20.0 * (GLfloat)h / (GLfloat)w, 20.0 * (GLfloat)h / (GLfloat)w, -50.0, 50.0);
else
glOrtho(-20.0 * (GLfloat)h / (GLfloat)w, 20.0 * (GLfloat)h / (GLfloat)w, -20.0, 20.0, -50.0, 50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void DrawMyObjects()
{
//画点
glBegin(GL_POINTS);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(-10.0, 11.0);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(-9.0, 10.0);
glColor3f(0.0, 1.0, 1.0);
glVertex2f(-8.0, 12.0);
glEnd();
//画线段
glBegin(GL_LINES);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(-11.0, 8.0);
glVertex2f(-8.0, 7.0);
glColor3f(1.0, 1.0, 1.0);
glVertex2f(-10.0, 9.0);
glVertex2f(-7.0, 6.0);
glEnd();
//画开折线
glBegin(GL_LINE_STRIP);
glColor3f(0.0, 1.0, 0.0);
// glPointSize(5);
glVertex2f(-10.0, 9.0);
glVertex2f(4.0, 6.0);
glVertex2f(6.0, 8.0);
glVertex2f(-5.5, 6.5);
glEnd();
//画闭折线
glBegin(GL_LINE_LOOP);
glColor3f(0.0, 1.0, 1.0);
glVertex2f(7.0, 7.0);
glVertex2f(8.0, 8.0);
glVertex2f(9.0, 6.5);
glVertex2f(10.3, 7.5);
glVertex2f(11.5, 6.0);
glVertex2f(7.5, 6.0);
glEnd();
//画填充多边形
glBegin(GL_POLYGON);
glColor3f(0.5, 0.3, 0.7);
glVertex2f(-9.0, 2.0);
glVertex2f(-8.0, 3.0);
glVertex2f(-10.3, 0.5);
glVertex2f(-7.5, -2.0);
glVertex2f(-5.0, -3.0);
glEnd();
//画四边形
glBegin(GL_QUADS);
glColor3f(0.7, 0.5, 0.2);
glVertex2f(0.0, 2.0);
glVertex2f(-1.0, 3.0);
glVertex2f(-3.3, 0.5);
glVertex2f(-0.5, -1.0);
glColor3f(0.5, 0.7, 0.2);
glVertex2f(3.0, 2.0);
glVertex2f(2.0, 3.0);
glVertex2f(0.0, 0.5);
glVertex2f(2.5, -1.0);
glEnd();
//画连接四边形
glBegin(GL_QUAD_STRIP);
glVertex2f(6.0, -2.0);
glVertex2f(5.5, 1.0);
glVertex2f(8.0, -1.0);
glColor3f(0.8, 0.0, 0.0);
glVertex2f(9.0, 2.0);
glVertex2f(11.0, -2.0);
glColor3f(0.0, 0.0, 0.8);
glVertex2f(11.0, 2.0);
glVertex2f(13.0, -1.0);
glColor3f(0.0, 0.8, 0.0);
glVertex2f(14.0, 1.0);
glEnd();
//画三角形
glBegin(GL_TRIANGLES);
glColor3f(0.2, 0.5, 0.7);
glVertex2f(-10.0, -5.0);
glVertex2f(-12.3, -7.5);
glVertex2f(-8.5, -6.0);
glColor3f(0.2, 0.7, 0.5);
glVertex2f(-8.0, -7.0);
glVertex2f(-7.0, -4.5);
glVertex2f(-5.5, -9.0);
glEnd();
//画连续三角形
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(-1.0, -8.0);
glVertex2f(-2.5, -5.0);
glColor3f(0.8, 0.8, 0.0);
glVertex2f(1.0, -7.0);
glColor3f(0.0, 0.8, 0.8);
glVertex2f(2.0, -4.0);
glColor3f(0.8, 0.0, 0.8);
glVertex2f(4.0, -6.0);
glEnd();
//画扇形三角形
glBegin(GL_TRIANGLE_FAN);
glVertex2f(8.0, -6.0);
glVertex2f(10.0, -3.0);
glColor3f(0.8, 0.2, 0.5);
glVertex2f(12.5, -4.5);
glColor3f(0.2, 0.5, 0.8);
glVertex2f(13.0, -7.5);
glColor3f(0.8, 0.5, 0.2);
glVertex2f(10.5, -9.0);
glEnd();
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
glPointSize(5);
DrawMyObjects();
glFlush();
}
int main(int argc,char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("画图");
myinit();
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutMainLoop();
return 0;
}
实验截图如下:
- 算法模拟题(借鉴lec3课件,可二选一实现)
- 采用中点线算法在屏幕上画一条直线。
- 采用中点圆算法在屏幕上画一个圆。
对于实验1,中点线算法的实验原理如下:
若d0 ->M在直线上方->取E;
此时再下一个象素的中点判别式为
d1=F(xp+2, yp+0.5)
=a(xp+2)+b(yp+0.5)+c
= a(xp +1)+b(yp +0.5)+c +a =d+a;
我的代码中的核心部分如下:
if ((fabs(dx) > fabs(dy)) && dy > 0)
{
GLint d1 = 2 * a;
GLint d2 = 2 * (a + b);
GLint d = 2 * a + b;
while (x0 < x1)//斜率0到1
{
i++;
if (d < 0)
{
x0++;
y0++;
d += d2;
}
else
{
x0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) > fabs(dy)) && dy < 0)//斜率大于-1小于0
{
GLint d1 = 2 * a;
GLint d2 = 2 * (a - b);
GLint d = 2 * a - b;
while (x0 < x1)
{
i++;
if (d > 0)
{
x0++;
y0--;
d += d2;
}
else
{
x0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) <= fabs(dy)) && dy > 0)//斜率大于1
{
GLint d1 = 2*b;
GLint d2 = 2*a+2*b;
GLint d =a +2*b;
while (y0 < y1)
{
i++;
if (d > 0)
{
x0++;
y0++;
d += d2;
}
else
{
y0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) <= fabs(dy)) && dy < 0)//斜率小于-1
{
GLint d1 = -2 * b;
GLint d2 = 2 * a - 2 * b;
GLint d = a - 2 * b;
while (y0 > y1)
{
i++;
if (d < 0)
{
x0++;
y0--;
d += d2;
}
else
{
y0--;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
可以看到,我对每一个斜率为k的情况都做了分析,分别是k<-1,-1<k<0,0<k<1,k>1这四种情况,全部采用了中点线算法,最后使用drawline(10, 80, 60, 10); // 更改画线范围,
Drawline(10,80,60,10)的情况表示从(10,80)画到(60,10)的线段,使用中点线算法结果如下:这里,我调用了四次drawline,分别对应以上的四种情况
请观察我的代码
drawline(10, 80, 60, 10); // 在这里更改你的画线范围
drawline(10, 10, 60, 80);
drawline(10, 50, 40, 20);
drawline(10, 20, 60, 30);
截图如下:
全部的源程序如下:
#include <GL/glut.h>
#include <cstdlib>
#include <cmath>
void ChangeToStandard(GLint& x0, GLint& y0, GLint& x1, GLint y1)
{
if (x1 < x0)
{
GLint tmpx = x1;
GLint tmpy = y1;
x1 = x0;
x0 = tmpx;
y1 = y0;
y0 = tmpy;
}
}
typedef struct {
GLint x, y;
}Pixel;
void init()
{
glClearColor(1, 1, 1, 1);
}
int Midpoint(GLint x0, GLint y0, GLint x1, GLint y1,Pixel points[])//可以画四种线段,也就是所有的情况都能画出来,斜率不论正负,不论大于一还是小于1
{
ChangeToStandard(x0, y0, x1, y1);//保证x0<x1;
GLint dx = x1 - x0;
GLint dy = y1 - y0;
GLint a = y0 - y1, b = x1 - x0, c = x1 * y0 - x0 * y1;
int i = 0;
points[i].x = x0;
points[i].y = y0;
if ((fabs(dx) > fabs(dy)) && dy > 0)
{
GLint d1 = 2 * a;
GLint d2 = 2 * (a + b);
GLint d = 2 * a + b;
while (x0 < x1)//斜率0到1
{
i++;
if (d < 0)
{
x0++;
y0++;
d += d2;
}
else
{
x0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) > fabs(dy)) && dy < 0)//斜率大于-1小于0
{
GLint d1 = 2 * a;
GLint d2 = 2 * (a - b);
GLint d = 2 * a - b;
while (x0 < x1)
{
i++;
if (d > 0)
{
x0++;
y0--;
d += d2;
}
else
{
x0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) <= fabs(dy)) && dy > 0)//斜率大于1
{
GLint d1 = 2*b;
GLint d2 = 2*a+2*b;
GLint d =a +2*b;
while (y0 < y1)
{
i++;
if (d > 0)
{
x0++;
y0++;
d += d2;
}
else
{
y0++;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
if ((fabs(dx) <= fabs(dy)) && dy < 0)//斜率小于-1
{
GLint d1 = -2 * b;
GLint d2 = 2 * a - 2 * b;
GLint d = a - 2 * b;
while (y0 > y1)
{
i++;
if (d < 0)
{
x0++;
y0--;
d += d2;
}
else
{
y0--;
d += d1;
}
points[i].x = x0;
points[i].y = y0;
}
}
return i;
}
void drawline(GLint x0, GLint y0, GLint x1, GLint y1)
{
Pixel points[100];
int num = Midpoint(x0, y0, x1, y1, points);
glBegin(GL_POINTS);
for (int i = 0; i <= num; i++)
{
glVertex2i(points[i].x, points[i].y);
}
glEnd();
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.f);
glPointSize(2);
drawline(10, 80, 60, 10); // 在这里更改你的画线范围
drawline(10, 10, 60, 80);
drawline(10, 50, 40, 20);
drawline(10, 20, 60, 30);
glFlush();
}
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat aspectRatio;
if (h == 0)
h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
aspectRatio = (GLfloat)w / (GLfloat)h;
if (w <= h)
glOrtho(-100.0, 100.0, -100.0 / aspectRatio, 100.0 / aspectRatio, 1.0, -1.0);
else
glOrtho(-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc,char **argv)
{
//在drawline之中可以更改画线段的范围;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutCreateWindow("中点线算法,在drawline里面改线段");
init();
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutMainLoop();
return 0;
}
对于实验2,中点圆算法的实现如下:
我们可以利用八分圆特性,只要画其中一个八分圆,然后对称就能获得整个圆:
void CirclePoints (float x,float y,int color)
{
WritePixel (x, y, color);
WritePixel (y, x, color);
WritePixel (y, -x, color);
WritePixel (x, -y, color);
WritePixel (-x, -y, color);
WritePixel (-y, -x, color);
WritePixel (-y, x, color);
WritePixel (-x, y, color);
}
实验思路的伪代码如下,方法就是判断中点的位置,然后判断是右像素还是右下像素:
MidpointCircle1(int r, int color)
{
int x,y;
float d;
x=0; y=r; d=1.25-r;
WritePixel(x,y,color);
while(x<y)
{
if(d<0){ d+ = 2*x+3; x++ }
else{d+ = 2*(x-y) + 5; x++;y--; }
WritePixel(x,y,color);
}
}
我的具体实现中的核心代码就是
void circleMidpoint(GLint xc, GLint yc, GLint redius)
{
screenPt circlept;
GLint p = 1 - redius;
circlept.setCoords(0, redius);
void circleplotpoints(GLint, GLint, screenPt);
circleplotpoints(xc,yc,circlept);
while (circlept.getx() < circlept.gety())
{
circlept.incrementx();
if (p < 0)
{
p +=1 + 2 * circlept.getx();
}
else
{
circlept.decrementy();
p += 2 * (circlept.getx() - circlept.gety()) + 1;
}
circleplotpoints(xc, yc, circlept);
}
}
这里的代码用于画第二个八分圆,然后对称即可
具体代码实现如下:
#include <GL/glut.h>
class screenPt
{
private:
GLint x, y;
public:
screenPt()
{
x = y = 0;
}
void setCoords(GLint xCoordValue, GLint yCoordValue)
{
x = xCoordValue;
y = yCoordValue;
}
GLint getx()
{
return x;
}
GLint gety()
{
return y;
}
void incrementx()
{
x++;
}
void decrementy()
{
y--;
}
};
void setPixel(GLint xcoord, GLint yCoord)
{
glBegin(GL_POINTS);
glVertex2i(xcoord, yCoord);
glEnd();
}
void circleMidpoint(GLint xc, GLint yc, GLint redius)
{
screenPt circlept;
GLint p = 1 - redius;
circlept.setCoords(0, redius);
void circleplotpoints(GLint, GLint, screenPt);
circleplotpoints(xc,yc,circlept);
while (circlept.getx() < circlept.gety())
{
circlept.incrementx();
if (p < 0)
{
p +=1 + 2 * circlept.getx();
}
else
{
circlept.decrementy();
p += 2 * (circlept.getx() - circlept.gety()) + 1;
}
circleplotpoints(xc, yc, circlept);
}
}
void circleplotpoints(GLint xc,GLint yc,screenPt circlePt)
{
setPixel(xc + circlePt.getx(), yc + circlePt.gety());
setPixel(xc - circlePt.getx(), yc + circlePt.gety());
setPixel(xc + circlePt.getx(), yc - circlePt.gety());
setPixel(xc - circlePt.getx(), yc - circlePt.gety());
setPixel(xc + circlePt.gety(), yc + circlePt.getx());
setPixel(xc - circlePt.gety(), yc + circlePt.getx());
setPixel(xc + circlePt.gety(), yc - circlePt.getx());
setPixel(xc - circlePt.gety(), yc - circlePt.getx());
}
void init()
{
glClearColor(1, 1, 1, 1);
}
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat aspectRatio;
if (h == 0)
h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
aspectRatio = (GLfloat)w / (GLfloat)h;
if (w <= h)
glOrtho(-100.0, 100.0, -100.0 / aspectRatio, 100.0 / aspectRatio, 1.0, -1.0);
else
glOrtho(-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void show()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0f, 0.0f,1.0f);
glPointSize(5);
circleMidpoint(0, 0, 50);
glFlush();
}
int main(int argc,char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutCreateWindow("中点圆算法");
init();
glutDisplayFunc(show);
glutReshapeFunc(ChangeSize);
glutMainLoop();
return 0;
}
实验截图如下,可以看到我画出了一个完整的圆: