OpenGL 是一个图形 API,并不是一个独立的平台,它需要一个编程语言来工作。
具体来说:
OpenGL(Open Graphics Library)是一个跨编程语言、跨平台的图形编程程序接口,
OpenGL 是一个跨语言、跨平台的编程接口,它主要用于渲染 2D、3D 图像,OpenGL 所做的只是利用 GPU 进行图形相关的运算,你想用 GPU 来加速 2D 或 3D 图像的绘制,那么你用 OpenGL 就可以了。
在应用程序调用任何 OpenGL 的指令之前,需要安排首先创建一个 OpenGL 的上下文。这个上下文是一个非常庞大的状态机,保存了 OpenGL 中的各种状态,这也是 OpenGL 指令执行的基础。
官方 OpenGL 的文档里并没有提供一个 API 来进行窗口的创建和操作。为了支持窗口,Windows 提供 WGL 接口,MacOS 则有 CGL。
使用这些接口直接来创建窗口来显示图形通常非常麻烦,所以我们通常使用一个高水平的库来隐藏窗口的创建操作细节。这里使用的窗口库是GLUT。
GLUT 的两个主要目的,一是建立一个跨平台的函式库(事实上 GLUT 就是跨平台的),以及简化学习 OpenGL 的条件。透过 GLUT 编写 OpenGL 通常只需要增加几行额外 GLUT 的代码,而且不需要知道每个不同操作系统处理窗口的 API。
sudo apt update
sudo apt install libgl1-mesa-dev
sudo apt install freeglut3 freeglut3-dev
sudo apt install libglfw3 libglfw3-dev
sudo apt install libglew-dev
#include <GL/glut.h>
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-5, 5, -5, 5, 5, 15);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
return;
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0, 0);
glutWireTeapot(3); // 画个茶壶
glFlush();
return;
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(0, 0);
glutInitWindowSize(300, 300);
glutCreateWindow("OpenGL 3D View");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
编译、运行
$ gcc -o test3.out test3.c -lGL -lGLU -lglut
$ ./test3.out
#include <GL/glut.h>
#define ColoredVertex(c, v) \
do { \
glColor3fv(c); \
glVertex3fv(v); \
} while (0)
static int angle = 0;
static int rotateMode = 0;
void myDisplay(void)
{
static int list = 0;
if (list == 0) {
GLfloat PointA[] = {0.5f, 0.5f, -0.5f}, PointB[] = {0.5f, -0.5f, -0.5f},
PointC[] = {-0.5f, -0.5f, -0.5f}, PointD[] = {-0.5f, 0.5f, -0.5f},
PointE[] = {0.5f, 0.5f, 0.5f}, PointF[] = {0.5f, -0.5f, 0.5f},
PointG[] = {-0.5f, -0.5f, 0.5f}, PointH[] = {-0.5f, 0.5f, 0.5f};
GLfloat ColorA[] = {1, 0, 0}, ColorB[] = {0, 1, 0}, ColorC[] = {0, 0, 1}, ColorD[] = {1, 1, 0},
ColorE[] = {1, 0, 1}, ColorF[] = {0, 1, 1}, ColorG[] = {1, 1, 1}, ColorH[] = {0, 0, 0};
list = glGenLists(1);
glNewList(list, GL_COMPILE);
// 面1
glBegin(GL_POLYGON);
ColoredVertex(ColorA, PointA);
ColoredVertex(ColorE, PointE);
ColoredVertex(ColorH, PointH);
ColoredVertex(ColorD, PointD);
glEnd();
// 面2
glBegin(GL_POLYGON);
ColoredVertex(ColorD, PointD);
ColoredVertex(ColorC, PointC);
ColoredVertex(ColorB, PointB);
ColoredVertex(ColorA, PointA);
glEnd();
// 面3
glBegin(GL_POLYGON);
ColoredVertex(ColorA, PointA);
ColoredVertex(ColorB, PointB);
ColoredVertex(ColorF, PointF);
ColoredVertex(ColorE, PointE);
glEnd();
// 面4
glBegin(GL_POLYGON);
ColoredVertex(ColorE, PointE);
ColoredVertex(ColorH, PointH);
ColoredVertex(ColorG, PointG);
ColoredVertex(ColorF, PointF);
glEnd();
// 面5
glBegin(GL_POLYGON);
ColoredVertex(ColorF, PointF);
ColoredVertex(ColorB, PointB);
ColoredVertex(ColorC, PointC);
ColoredVertex(ColorG, PointG);
glEnd();
// 面6
glBegin(GL_POLYGON);
ColoredVertex(ColorG, PointG);
ColoredVertex(ColorH, PointH);
ColoredVertex(ColorD, PointD);
ColoredVertex(ColorC, PointC);
glEnd();
glEndList();
glEnable(GL_DEPTH_TEST);
}
// 已经创建了显示列表,在每次绘制正四面体时将调用它
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle / 10, 1, 0.5, 0.0);
glCallList(list);
glPopMatrix();
glutSwapBuffers();
}
void myIdle(void)
{
++angle;
if (angle >= 3600.0f) {
angle = 0.0f;
}
myDisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(700, 700);
glutCreateWindow("First OpenGL Program");
glutDisplayFunc(&myDisplay);
glutIdleFunc(&myIdle); //空闲调用
glutMainLoop();
return 0;
}
编译、运行
$ gcc test.c -o test.out -l GL -l glut
$ ./test.out
#include <GL/glut.h>
// 初始化参数
void init()
{
glClearColor(0.1, 0.1, 0.4, 0.0);
glShadeModel(GL_SMOOTH);
}
void DrawMyObjects(void)
{
/* draw some points */
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();
/* draw some line_segments */
glBegin(GL_LINES);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(-11.0, 8.0);
glVertex2f(-7.0, 7.0);
glColor3f(1.0, 0.0, 1.0);
glVertex2f(-11.0, 9.0);
glVertex2f(-8.0, 6.0);
glEnd();
/* draw one opened_line */
glBegin(GL_LINE_STRIP);
glColor3f(0.0, 1.0, 0.0);
glVertex2f(-3.0, 9.0);
glVertex2f(2.0, 6.0);
glVertex2f(3.0, 8.0);
glVertex2f(-2.5, 6.5);
glEnd();
/* draw one closed_line */
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();
/* draw one filled_polygon */
glBegin(GL_POLYGON);
glColor3f(0.5, 0.3, 0.7);
glVertex2f(-7.0, 2.0);
glVertex2f(-8.0, 3.0);
glVertex2f(-10.3, 0.5);
glVertex2f(-7.5, -2.0);
glVertex2f(-6.0, -1.0);
glEnd();
/* draw some filled_quandrangles */
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();
/* draw some filled_strip_quandrangles */
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();
/* draw some filled_triangles */
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();
/* draw some filled_strip_triangles */
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();
/* draw some filled_fan_triangles */
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 display()
{
// 清除之前帧数据
glClear(GL_COLOR_BUFFER_BIT);
DrawMyObjects();
// 执行绘图命令
glFlush();
}
// 窗口大小变化回调函数
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 0.1, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 25, 0, 0, -1, 0, 1, 0);
}
int main(int argc, char *argv[])
{
// 初始化显示模式
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// 初始化窗口
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
// 开始主循环绘制
glutMainLoop();
return 0;
}
编译、运行
$ gcc -o test5.out test5.c -lGL -lGLU -lglut
$ ./test5.out