【实验名称】 基本的OpenGL编程及基本图元绘制
【实验目的】
1. 熟悉OpenGL的应用工具包GLUT的安装和使用。
2. 掌握基本的OpenGL编程方法。
3. 掌握显示窗口的显示方法。
4. 掌握二维图形点、线、多边形的绘制方法。
【实验原理】
OpenGL 是一种跨平台的图形编程 API,它提供了一系列的函数和数据结构,用于绘制各种形状的 2D 和 3D 图形。在 OpenGL 中,绘制图形的基本单位是图元(Primitive),比如点(Point)、线段(Line Segment)和三角形(Triangle)等。绘制图形的过程可以分为两个阶段:几何阶段和光栅化阶段。
在几何阶段中,OpenGL 会根据通过 API 提供的数据生成各种形状的图元,比如点、线、三角形等。常用的 API 函数包括 glVertex* 系列函数和 glDraw* 系列函数。glVertex* 函数用于设置当前绘制点的坐标,而 glDraw* 函数则用于根据已有的坐标信息生成各种不同的图元。
在光栅化阶段中,OpenGL 会根据生成的图元信息将颜色和深度等属性分配给屏幕上的每个像素点。常用的 API 函数包括 glClearColor、glDepthFunc、glEnable 和 glDisable 等。
【实验内容】
1. 练习基本的OpenGL编程方法。
(1)配置OpenGL,能在VC下通过编译。
(2)阅读并运行simple.c,熟悉最简单的OpenGL程序结构。
(3)阅读并运行改进的simple2.c,掌握OpenGL程序的通用结构。给simple2.c中的函数加注释。
#include <GL/glut.h> /* glut.h includes gl.h and glu.h*/
void display(void)// 显示回调函数
{
/* 清空窗口 */
glClear(GL_COLOR_BUFFER_BIT);
/* 绘制单位正方形多边形 */
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
/* 刷新OpenGL缓冲区 */
glFlush();
}
void init()//设置OPENGL状态
{
/* 设置清空颜色为黑色 ,不透明窗口*/
glClearColor(0.0, 0.0, 0.0, 0.0);
/* 设置填充颜色为白色 */
glColor3f(1.0, 1.0, 1.0);
/* 设置标准正交视图和裁剪范围 */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}
int main(int argc, char** argv)
{
/* 初始化模式并在屏幕左上角打开一个窗口 */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(300, 300); 显示回调函数
glutInitWindowPosition(0, 0);
glutCreateWindow("simple");
glutDisplayFunc(display);//显示回调函数
init();//显示回调函数
glutMainLoop();//显示回调函数
}
2. 可尝试做如下修改:
(a)改变窗口的位置,尺寸,标题;
glutInitWindowSize(400, 400); // 修改窗口大小为400x400
glutInitWindowPosition(100, 100); // 修改窗口位置为(100, 100)
glutCreateWindow("New Title"); // 修改窗口标题为"New Title"
(b)改变窗口背景色和矩形颜色;
在display函数
glColor3f(1.0, 0.0, 0.0); // 修改填充颜色为红色
在init函数
glClearColor(0.2, 0.3, 0.4, 0.0); // 修改清空颜色为浅蓝色
z
(c),还可以只显示矩形的一部分(通过设置正投影参数(glOrtho函数的参数)和矩形四个顶点的坐标来完成)。
将正投影参数修改为glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0),这样只显示矩形的一部分。同时也修改了矩形的顶点坐标来适应新的正投影参数
3.发挥想象,编程实现在窗口中绘制若干图形及设置它们的属性,并回答问题:
(1)绘制若干改变矩形的尺寸和其在窗口中的位置个点,分别设置每个点的颜色和大小。
#include <GL/glut.h>
void display() {
glClear(GL_COLOR_BUFFER_BIT);
// 绘制第一个矩形
glColor3f(1.0, 0.0, 0.0); // 设置颜色为红色
glPointSize(5.0); // 设置点的大小为5.0
glBegin(GL_POINTS);
glVertex2f(-0.5, 0.5);
glEnd();
// 绘制第二个矩形
glColor3f(0.0, 1.0, 0.0); // 设置颜色为绿色
glPointSize(10.0); // 设置点的大小为10.0
glBegin(GL_POINTS);
glVertex2f(0.5, 0.5);
glEnd();
// 绘制第三个矩形
glColor3f(0.0, 0.0, 1.0); // 设置颜色为蓝色
glPointSize(15.0); // 设置点的大小为15.0
glBegin(GL_POINTS);
glVertex2f(-0.5, -0.5);
glEnd();
// 绘制第四个矩形
glColor3f(1.0, 1.0, 0.0); // 设置颜色为黄色
glPointSize(20.0); // 设置点的大小为20.0
glBegin(GL_POINTS);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 400);
glutCreateWindow("Points");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
思考题1:glPointSize()可以放在glBegin()和glEnd()函数对之间吗?
不可以。glPointSize()函数用于设置点的大小,它是一个全局状态,只需设置一次即可影响整个渲染过程。因此,glPointSize()函数只能在glBegin()和glEnd()函数之外调用,以设置整个渲染过程中所有点的大小。
如果在glBegin()和glEnd()函数之间调用glPointSize()函数,将会导致OpenGL无法正确解析渲染指令,从而产生错误。
- 绘制若干条直线段。设置线段的颜色,线型和线宽。
#include <GL/glut.h>
void display() {
glClear(GL_COLOR_BUFFER_BIT);
// 绘制第一条红色直线段
glColor3f(1.0, 0.0, 0.0);
glLineWidth(1.0);
glBegin(GL_LINES);
glVertex2f(-0.8, 0.8);
glVertex2f(-0.4, 0.7);
glEnd();
// 绘制第二条绿色直线段
glColor3f(0.0, 1.0, 0.0);
glLineWidth(2.0);
glBegin(GL_LINES);
glVertex2f(0.2, 0.6);
glVertex2f(0.6, 0.6);
glEnd();
// 绘制第三条蓝色直线段
glColor3f(0.0, 0.0, 1.0);
glLineWidth(4.0);
glBegin(GL_LINES);
glVertex2f(-0.6, -0.4);
glVertex2f(-0.2, -0.4);
glEnd();
// 绘制第四条紫色直线段
glColor3f(1.0, 0.0, 1.0);
glLineWidth(8.0);
glLineStipple(3, 0xcccc);
glBegin(GL_LINES);
glVertex2f(0.4, -0.6);
glVertex2f(0.8, -0.6);
glEnd();
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 400);
glutCreateWindow("Colored Lines");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
思考题1:以下命令会显示什么样的线段?
glEnable(GL_LINE_STIPPLE);
glColor3f(0.0, 1.0, 0.0);
glLineWidth(2.0);
glLineStipple(3, 0xcccc);
glDisable(GL_LINE_STIPPLE);
讨论:glDisable(GL_LINE_STIPPLE); 此语句放置的位置不同对画线的影响
这组命令将会显示一条绿色的虚线,线宽为2.0,并且使用了线型模式。具体来说:glEnable(GL_LINE_STIPPLE) 启用了线型模式;glColor3f(0.0, 1.0, 0.0) 设置线段的颜色为绿色;glLineWidth(2.0) 设置线段的宽度为2.0;glLineStipple(3, 0xcccc) 设置了线型模式,其中第一个参数3表示重复3次,第二个参数0xcccc表示线型模式的模式值;glDisable(GL_LINE_STIPPLE) 禁用了线型模式。
glDisable(GL_LINE_STIPPLE)语句的放置位置会影响绘制线段时是否使用线型模式。具体来说:如果glDisable(GL_LINE_STIPPLE)语句在绘制线段之前调用,那么绘制的线段将不会使用线型模式,即使之前调用了glLineStipple启用了线型模式;如果glDisable(GL_LINE_STIPPLE)语句在绘制线段之后调用,那么绘制的线段将会使用线型模式,因为在绘制之前启用了线型模式。
思考题2:以下命令会显示什么样的线段?
glShadeModel(GL_SMOOTH);
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(0.0, 0.5);
glColor3f(0.0, 0.0, 1.0);
glVertex2f(0.5, -0.5);
glEnd();
将glShadeModel(GL_SMOOTH)改为glShadeModel(GL_FLAT),其余命令不变,结果又会如何?
这段代码会显示一条从红色渐变到蓝色的线段。在这段代码中,首先使用glShadeModel(GL_SMOOTH)设置了光照模式为平滑着色。然后使用glBegin(GL_LINES)开始绘制线段,接着使用glColor3f设置了两个顶点的颜色,最后使用glVertex2f绘制了两个顶点。根据代码中的设置,绘制的线段会从红色渐变到蓝色。这是因为在平滑着色模式下,OpenGL会对线段的颜色进行插值,使得线段上的颜色呈现出平滑的过渡效果。
如果将glShadeModel(GL_SMOOTH)改为glShadeModel(GL_FLAT),则绘制的线段将会显示为两个不同颜色的线段,第一个顶点为红色,第二个顶点为蓝色,而不会有颜色的渐变效果。
- 绘制若干个多边形。设置多边形的颜色,显示模式,隐藏某些边。
#include <GL/glut.h>
void display() {
glClear(GL_COLOR_BUFFER_BIT);
// 绘制第一个多边形
glColor3f(1.0, 0.0, 0.0); // 设置颜色为红色
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 设置显示模式为填充
glBegin(GL_POLYGON);
glVertex2f(-0.8, 0.8);
glVertex2f(-0.4, 0.8);
glVertex2f(-0.6, 0.6);
glEnd();
// 绘制第二个多边形
glColor3f(0.0, 1.0, 0.0); // 设置颜色为绿色
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 设置显示模式为线框
glBegin(GL_POLYGON);
glVertex2f(-0.1, 0.6);
glEdgeFlag(GL_FALSE);
glVertex2f(0.1, 0.6);
glEdgeFlag(GL_TRUE);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
// 绘制第三个多边形
glColor3f(0.0, 0.0, 1.0); // 设置颜色为蓝色
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置显示模式为点
glBegin(GL_POLYGON);
glVertex2f(-0.6, -0.4);
glVertex2f(-0.2, -0.4);
glVertex2f(-0.4, -0.6);
glEnd();
// 绘制第四个多边形
glColor3f(1.0, 1.0, 0.0); // 设置颜色为黄色
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 设置显示模式为填充
glBegin(GL_POLYGON);
glVertex2f(0.4, -0.6);
glVertex2f(0.8, -0.6);
glVertex2f(0.6, -0.8);
glEnd();
glFlush();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 400);
glutCreateWindow("Polygons");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
思考题1:以下命令会显示什么样的多边形?
glShadeModel(GL_SMOOTH);
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(-0.5, -0.5);
glColor3f(0.0, 1.0, 0.0);
glVertex2f(-0.5, 0.5);
glColor3f(0.0, 0.0, 1.0);
glVertex2f(0.5, 0.5);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(0.5, -0.5);
glEnd();
将glShadeModel(GL_SMOOTH)改为glShadeModel(GL_FLAT),其余命令不变,结果又会如何?
将glBegin(GL_POLYGON)改为glBegin(GL_QUADS),分别尝试在SMOOTH和FLAT模式下的结果。
思考题2:以下程序段分别会显示什么样的多边形?
(a)
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
(b)
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
(c)
glPolygonMode( GL_FRONT_AND_BACK, GL_POINT);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
这些程序段分别会显示以下多边形:
(a) glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); 这段代码会显示一个填充的红色正方形,因为使用了glPolygonMode将多边形的填充模式设置为GL_FILL,并且使用glColor3f设置了颜色为红色。
(b) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); 这段代码会显示一个边框为黄色的正方形,因为使用了glPolygonMode将多边形的填充模式设置为GL_LINE,并且使用glColor3f设置了颜色为黄色。
(c) glPolygonMode( GL_FRONT_AND_BACK, GL_POINT); 这段代码会显示一个由四个顶点组成的正方形的顶点,因为使用了glPolygonMode将多边形的填充模式设置为GL_POINT,并且使用glColor3f设置了颜色为黄色。
思考题3:下面多边形的哪些边不可见?
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glEdgeFlag(GL_FALSE);
glVertex2f(-0.5, 0.5);
glEdgeFlag(GL_TRUE);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
在这段代码中,通过使用glEdgeFlag(GL_FALSE)和glEdgeFlag(GL_TRUE)来控制边的可见性。当glEdgeFlag(GL_FALSE)被设置时,表示当前顶点与下一个顶点之间的边不可见,而glEdgeFlag(GL_TRUE)则表示边可见。
因此,在这段代码中,第一个边和第四个边是不可见的,因为它们分别由第一和第四个顶点与第二和第三个顶点组成,而这两个边之间的边标记为不可见。而第二和第三个边是可见的,因为它们的边标记为可见。
【小结或讨论】
初始化环境: 在编写OpenGL程序之前,需要进行OpenGL环境的初始化,包括设置显示模式、窗口大小、窗口标题等。
设置颜色和清屏: 使用glClearColor设置清屏颜色,glColor3f设置绘图颜色。glClear用于清空屏幕。
绘制基本图元: 使用glBegin和glEnd之间的代码块绘制点、线段、多边形等基本图元。通过glVertex2f设置顶点坐标。
刷新显示和进入主循环: 使用glFlush刷新显示,确保图形被正确绘制。通过glutMainLoop进入主循环,等待用户交互。