OpenGl 顶点,图元以及颜色

标签: OpenGl opengl 2d graphic tutorial 发布于:2020-04-12 15:59:20 编辑于:2022-11-15 12:18:48 浏览量:32026

OpenGL 二维图形学教程系列

此系列翻译自:OpenGL Tutorial An Introduction on OpenGL with 2D Graphics

  1. OpenGl 环境搭建与介绍
  2. OpenGl 顶点,图元以及颜色
  3. OpenGL 裁剪区域与视口
  4. OpenGl 平移和旋转
  5. OpenGl 动画
  6. OpenGL 使用 GLUT 处理键盘输入
  7. OpenGL 使用 GLUT 处理鼠标输入

3. 顶点,图元以及颜色

3.1 例子 2:顶点,图元以及颜色(GL02Primitive.cpp)

尝试编译运行以下 OpenGL / C++ 程序:

/*
 * GL02Primitive.cpp: Vertex, Primitive and Color
 * Draw Simple 2D colored Shapes: quad, triangle and polygon.
 */
#include <windows.h>  // for MS Windows
#include <GL/glut.h>  // GLUT, include glu.h and gl.h
 
/* Initialize OpenGL Graphics */
void initGL() {
   // Set "clearing" or background color
   glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black and opaque
}
 
/* Handler for window-repaint event. Call back when the window first appears and
   whenever the window needs to be re-painted. */
void display() {
   glClear(GL_COLOR_BUFFER_BIT);   // Clear the color buffer with current clearing color
 
   // Define shapes enclosed within a pair of glBegin and glEnd
   glBegin(GL_QUADS);              // Each set of 4 vertices form a quad
      glColor3f(1.0f, 0.0f, 0.0f); // Red
      glVertex2f(-0.8f, 0.1f);     // Define vertices in counter-clockwise (CCW) order
      glVertex2f(-0.2f, 0.1f);     //  so that the normal (front-face) is facing you
      glVertex2f(-0.2f, 0.7f);
      glVertex2f(-0.8f, 0.7f);
 
      glColor3f(0.0f, 1.0f, 0.0f); // Green
      glVertex2f(-0.7f, -0.6f);
      glVertex2f(-0.1f, -0.6f);
      glVertex2f(-0.1f,  0.0f);
      glVertex2f(-0.7f,  0.0f);
 
      glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray
      glVertex2f(-0.9f, -0.7f);
      glColor3f(1.0f, 1.0f, 1.0f); // White
      glVertex2f(-0.5f, -0.7f);
      glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray
      glVertex2f(-0.5f, -0.3f);
      glColor3f(1.0f, 1.0f, 1.0f); // White
      glVertex2f(-0.9f, -0.3f);
   glEnd();
 
   glBegin(GL_TRIANGLES);          // Each set of 3 vertices form a triangle
      glColor3f(0.0f, 0.0f, 1.0f); // Blue
      glVertex2f(0.1f, -0.6f);
      glVertex2f(0.7f, -0.6f);
      glVertex2f(0.4f, -0.1f);
 
      glColor3f(1.0f, 0.0f, 0.0f); // Red
      glVertex2f(0.3f, -0.4f);
      glColor3f(0.0f, 1.0f, 0.0f); // Green
      glVertex2f(0.9f, -0.4f);
      glColor3f(0.0f, 0.0f, 1.0f); // Blue
      glVertex2f(0.6f, -0.9f);
   glEnd();
 
   glBegin(GL_POLYGON);            // These vertices form a closed polygon
      glColor3f(1.0f, 1.0f, 0.0f); // Yellow
      glVertex2f(0.4f, 0.2f);
      glVertex2f(0.6f, 0.2f);
      glVertex2f(0.7f, 0.4f);
      glVertex2f(0.6f, 0.6f);
      glVertex2f(0.4f, 0.6f);
      glVertex2f(0.3f, 0.4f);
   glEnd();
 
   glFlush();  // Render now
}
 
/* Main function: GLUT runs as a console application starting at main()  */
int main(int argc, char** argv) {
   glutInit(&argc, argv);          // Initialize GLUT
   glutCreateWindow("Vertex, Primitive & Color");  // Create window with the given title
   glutInitWindowSize(320, 320);   // Set the window's initial width & height
   glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
   glutDisplayFunc(display);       // Register callback handler for window re-paint event
   initGL();                       // Our own OpenGL initialization
   glutMainLoop();                 // Enter the event-processing loop
   return 0;
}

预期得到如下输出:

1579341347657.png

坐标关系图:

1579341385625.png

我将会在接下来的部分详细解释该程序。

3.2 OpenGL 与状态机

OpenGL 像一个状态机一样运作,并且其维护了一组状态变量(例如:前景色,背景色)。在一个状态机中,一旦设置了状态变量的值,该值将持续存在,直到给出新的值。

举个例子,我们在 initGL() 函数中将 clearing 颜色设置为黑色。我们将在 display() 函数中反复地使用此项设置,注意 display() 函数在窗口重新绘制时被调用。

// In initGL(), set the "clearing" or background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  // black and opaque
 
// In display(), clear the color buffer (i.e., set background) with the current "clearing" color
glClear(GL_COLOR_BUFFER_BIT);

另一个例子:如果我们使用 glColor 函数设置当前前景色为红色,之后红色将被用于后续所有顶点地着色,除非我们再次调用 glColor 函数改变前景色。

总之,在一个状态机中,任何值都将保持不变除非你显式地改变它。

3.3 OpenGL 命名约定

OpenGL 函数命名约定

  • 以小写的 gl(对于 OpenGL 核心函数库),glu(对于 OpenGL 实用程序库)或者 glut(对于 OpenGL 实用工具包)开头。
  • 紧跟该函数的功能,采用驼峰式命名法,例如 glColor 用于指定要绘制的颜色,glVertex 用于指定顶点的位置。
  • 紧跟参数描述,例如 glColor3f 函数要求三个浮点数作为参数,glVectex2i 函数要求两个整数作为参数。(为什么不直接使用函数重载?因为 C 语言不支持函数重载)。
  • 最后面是一个 v 代表参数需要是一个数组。

OpenGL 数据类型命名约定

typedef unsigned int    GLenum;
typedef unsigned char   GLboolean;
typedef unsigned int    GLbitfield;
typedef void            GLvoid;
typedef signed char     GLbyte;         /* 1-byte signed */
typedef short           GLshort;        /* 2-byte signed */
typedef int             GLint;          /* 4-byte signed */
typedef unsigned char   GLubyte;        /* 1-byte unsigned */
typedef unsigned short  GLushort;       /* 2-byte unsigned */
typedef unsigned int    GLuint;         /* 4-byte unsigned */
typedef int             GLsizei;        /* 4-byte signed */
typedef float           GLfloat;        /* single precision float */
typedef float           GLclampf;       /* single precision float in [0,1] */
typedef double          GLdouble;       /* double precision float */
typedef double          GLclampd;       /* double precision float in [0,1] */

OpenGL 常量命名约定

  • 以 GL,GLU 或者 GLUT 开头.
  • 下划线进行分割。
  • 全大写。

例如:GL_COLOR_BUFFER_BIT。

3.4 initGL()

initGL() 函数用于初始化那些只需要设置一次的任务,例如设置 clearing 颜色。initGL() 函数仅在 main() 函数中被调用一次。

3.5 display()

函数 display() 是一个事件处理回调函数。当一个事件发生时(例如按键被按下,鼠标点击,窗口绘制),相应的事件处理回调函数被调用。

当窗口第一次出现以及之后每次窗口重绘时调用 display() 函数。

注意该函数就是用户创建的一个普通的函数,名字可以任意,将此函数作为参数传递给 glutDisplayFunc(functionName) ,即所谓的向 OpenGL 注册绘制函数,这样 OpenGL 才知道当窗口绘制的时候应该调用哪一个函数。

3.6 设置 GLUT

GLUT 提供了一些较高层次封装的实用函数以简化 OpenGL 编程,尤其是当与操作系统交互时(例如创建窗口,处理键盘和鼠标输入)。在上述程序中用到了以下 GLUT 函数:

  • void glutInit(int *argc, char **argv):初始化 GLUT,需要在任何其它 GL/GLUT 函数前被调用,其参数与 main 函数一样。
  • int glutCreateWindow(char *title):创建一个窗口并设置窗口标题。
  • void glutInitWindowSize(int width, int height):指定窗口的宽度与高度,单位为像素。
  • void glutInitWindowPosition(int x, int y):指定窗口的位置,圆心为屏幕的左上角,x 轴正方向为向右,y 轴正方向则是向下。
  • void glutDisplayFunc(void (*func)(void)):注册处理窗口绘制事件的函数,传入的参数即函数名。
  • void glutMainLoop():进入事件处理循环,OpenGL 图形系统等待事件发生并调用相应的处理函数处理事件。

3.7 颜色

我们使用 glColor 设置前景色,使用 glClearColor 函数设置背景色,即所谓的 clearing 颜色。

void glColor3f(GLfloat red, GLfloat green, GLfloat blue)
void glColor3fv(GLfloat *colorRGB)
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
void glColor4fv(GLfloat *colorRGBA)
 
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
   // GLclampf in the range of 0.0f to 1.0f

注意:

  • 颜色通常是浮点数且范围在 0.0f 与 1.0f 之间。
  • 颜色可以使用 RGB 或者 RGBA 模式指定。A (alpha)代表透明度,值为 1 时完全不透明,值为 0 时完全透明。

在上述例子中,我们通过 initGL() 中的 glClearColor 设置背景色。

// In initGL(), set the "clearing" or background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  // Black and opague

在 display() 函数中,我们通过 glColor3f() 函数设置后续的顶点的颜色。

// In display(), set the foreground color of the pixel
glColor3f(1.0f, 0.0f, 0.0f);  // Red

3.8 几何图元

在 OpenGL 中,物体是由诸如三角形,四边形,线段,点之类的几何图元构成的,而图元又由一个或者多个点构成。OpenGL 支持以下图元:

1579341408109.png

几何图元可以通过 glVertex 函数指定其顶点,并由一对 glBegin 和 glEnd 包裹来定义。

void glBegin(GLenum shape)
   void glVertex[234][sifd] (type x, type y, type z, ...)
   void glVertex[234][sifd]v (type *coords)
void glEnd()

glBegin 指定几何体的类型,例如 GL_POINTS,GL_LINES,GL_QUADS,GL_TRIANGLES 以及 GL_POLYGON。对于以 S 结尾的类型,你可以在每一组 glBegin / glEnd 定义多个相同类型的几何体。例如对于 GL_TRIANGLES,每三个顶点定义一个三角形。

顶点通常以单精度浮点数指定。这是因为整型不合适三角运算,而单精度浮点数的精度足够用于中间运算并最后将图形以像素为单位渲染到屏幕上,并且通常没有必要使用双精度浮点数。

在上述例子中:

glBegin(GL_QUADS);
   .... 4 quads with 12x glVertex() ....
glEnd();

我们使用了 12 个 glVertex() 函数定义了 3 个具有颜色的四边形。

glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(-0.8f, 0.1f);
glVertex2f(-0.2f, 0.1f);
glVertex2f(-0.2f, 0.7f);
glVertex2f(-0.8f, 0.7f);

我们将颜色设置为红色(R=1,G=0,B=0)。所有后续定义的顶点都会是红色。请注意在 OpenGL 中,颜色与许多其它的属性应用于顶点而非图元。图元的颜色由其顶点的颜色插值得来。

第二个四边形定义为为绿色。

对于第三个多边形,其顶点的颜色各不相同。四边形平面的颜色由其顶点的颜色插值而来,如程序的输出所示,结果是白色到深灰色的阴影。

glColor3f(0.2f, 0.2f, 0.2f);  // Dark Gray
glVertex2f(-0.9f, -0.7f);
glColor3f(1.0f, 1.0f, 1.0f);  // White
glVertex2f(-0.5f, -0.7f);
glColor3f(0.2f, 0.2f, 0.2f);  // Dark Gray
glVertex2f(-0.5f, -0.3f);
glColor3f(1.0f, 1.0f, 1.0f);  // White
glVertex2f(-0.9f, -0.3f);

3.9 二维坐标系以及默认视图

下面的图展示了 OpenGL 的二维坐标系统,其与圆心在左下角的直角坐标系相同。

1579341424161.png

默认的 OpenGL 2D 裁剪区域(即相机捕获的区域)是 x 和 y 分别在-1.0 到 1.0 范围内的正交视图,即以原点为中心的 2x2 正方形。该裁剪区域被映射到屏幕上的视口(viewport)。视口以像素为单位。

研究以上示例,以使自己确信你所创建的 2D 图形在屏幕上被正确定位。

未经允许,禁止转载,本文源站链接:https://iamazing.cn/