如何在OpenGL中使用glOrtho() ?

时间:2022-01-01 05:14:28

I can't understand the usage of glOrtho. Can someone explain what it is used for?

我不明白glOrtho的用法。有人能解释一下它的用途吗?

Is it used to set the range of x y and z coordinates limit?

它是用来设置x y和z坐标的范围吗?

glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

It means that the x, y and z range is from -1 to 1?

它意味着x y z的范围是从-1到1?

3 个解决方案

#1


120  

Have a look at this picture: Graphical Projections 如何在OpenGL中使用glOrtho() ?

看看这幅图:图形投影?

The glOrtho command produces an "Oblique" projection that you see in the bottom row. No matter how far away vertexes are in the z direction, they will not recede into the distance.

glOrtho命令产生一个“倾斜”投影,你可以在下面一行看到。无论顶点在z方向上有多远,它们都不会退到远处去。

I use glOrtho every time I need to do 2D graphics in OpenGL (such as health bars, menus etc) using the following code every time the window is resized:

每次需要在OpenGL(比如健康栏、菜单等)中进行二维图形处理时,我都会使用glOrtho,每次调整窗口大小时都使用以下代码:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);

This will remap the OpenGL coordinates into the equivalent pixel values (X going from 0 to windowWidth and Y going from 0 to windowHeight). Note that I've flipped the Y values because OpenGL coordinates start from the bottom left corner of the window. So by flipping, I get a more conventional (0,0) starting at the top left corner of the window rather.

这将把OpenGL坐标重新映射到等效像素值(X从0到windowWidth, Y从0到windowh8)。注意,我翻转了Y值,因为OpenGL坐标从窗口的左下角开始。通过翻转,我得到一个更常规的(0,0)从窗口的左上角开始。

#2


35  

glOrtho: 2D games, objects close and far appear the same size:

glOrtho: 2D游戏,接近和远的物体呈现相同的尺寸:

如何在OpenGL中使用glOrtho() ?

glFrustrum: more real-life like 3D, identical objects further away appear smaller:

更真实的物体,比如3D,离得更远的物体看起来更小:

如何在OpenGL中使用glOrtho() ?

Code

代码

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

static int ortho = 0;

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    if (ortho) {
    } else {
        /* This only rotates and translates the world around to look like the camera moved. */
        gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    }
    glColor3f(1.0f, 1.0f, 1.0f);
    glutWireCube(2);
    glFlush();
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (ortho) {
        glOrtho(-2.0, 2.0, -2.0, 2.0, -1.5, 1.5);
    } else {
        glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    }
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    if (argc > 1) {
        ortho = 1;
    }
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Schema

模式

Ortho: camera is a plane, visible volume a rectangle:

正形:相机为平面,可见体积为矩形:

如何在OpenGL中使用glOrtho() ?

Frustrum: camera is a point,visible volume a slice of a pyramid:

挫折:相机是一个点,可见体积是金字塔的一部分:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

Parameters

参数

We are always looking from +z to -z with +y upwards:

我们总是从+z到-z +y向上看:

glOrtho(left, right, bottom, top, near, far)
  • left: minimum x we see
  • 左:最小x
  • right: maximum x we see
  • 右:我们看到的最大x。
  • bottom: minimum y we see
  • 底部:我们看到的最小的y。
  • top: maximum y we see
  • 我们看到的最大y值
  • -near: minimum z we see. Yes, this is -1 times near. So a negative input means positive z.
  • 我们看到的最小z。是的,这是-1倍。所以负输入表示正z。
  • -far: maximum z we see. Also negative.
  • -远:我们看到的最大z。也消极。

Schema:

模式:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

How it works under the hood

它是如何在引擎盖下工作的

In the end, OpenGL always "uses":

最后,OpenGL总是“使用”:

glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

If we use neither glOrtho nor glFrustrum, that is what we get.

如果我们既不使用glOrtho也不使用glum,那就是我们得到的结果。

glOrtho and glFrustrum are just linear transformations (AKA matrix multiplication) such that:

glOrtho和glum只是线性变换(又称矩阵乘法),使得:

  • glOrtho: takes a given 3D rectangle into the default cube
  • glOrtho:将给定的3D矩形放入默认的立方体中
  • glFrustrum: takes a given pyramid section into the default cube
  • glum:将给定的金字塔部分放入默认的多维数据集。

This transformation is then applied to all vertexes. This is what I mean in 2D:

然后将这个转换应用到所有的顶点。这就是我所说的2D:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

The final step after transformation is simple:

转换后的最后一步很简单:

  • remove any points outside of the cube (culling): just ensure that x, y and z are in [-1, +1]
  • 删除立方体外的任何点(剔除):只需确保x、y和z在[-1,+1]中
  • ignore the z component and take only x and y, which now can be put into a 2D screen
  • 忽略z分量,只取x和y,现在可以放到2D屏幕上

With glOrtho, z is ignored, so you might as well always use 0.

对于glOrtho, z被忽略,所以你最好总是用0。

One reason you might want to use z != 0 is to make sprites hide the background with the depth buffer.

您可能希望使用z != 0的一个原因是使精灵使用深度缓冲区隐藏背景。

Deprecation

弃用

glOrtho is deprecated as of OpenGL 4.5: the compatibility profile 12.1. "FIXED-FUNCTION VERTEX TRANSFORMATIONS" is in red.

在OpenGL 4.5:兼容性配置文件12.1中,不赞成使用glOrtho。“固定函数顶点变换”是红色的。

So don't use it for production. In any case, understanding it is a good way to get some OpenGL insight.

所以不要用它来生产。无论如何,理解它是获得一些OpenGL洞察力的好方法。

Modern OpenGL 4 programs calculate the transformation matrix (which is small) on the CPU, and then give the matrix and all points to be transformed to OpenGL, which can do the thousands of matrix multiplications for different points really fast in parallel.

现代的OpenGL 4程序在CPU上计算变换矩阵(它很小),然后给出矩阵和所有要转换成OpenGL的点,OpenGL可以并行地对不同的点进行成千上万的矩阵乘法。

Manually written vertex shaders then do the multiplication explicitly, usually with the convenient vector data types of the OpenGL Shading Language.

手工编写顶点着色器然后显式地做乘法,通常使用方便的矢量数据类型的OpenGL着色语言。

Since you write the shader explicitly, this allows you to tweak the algorithm to your needs. Such flexibility is a major feature of more modern GPUs, which unlike the old ones that did a fixed algorithm with some input parameters, can now do arbitrary computations. See also: https://*.com/a/36211337/895245

由于您显式地编写着色器,这允许您根据需要调整算法。这种灵活性是更现代的gpu的一个主要特性,它不像以前使用一些输入参数的固定算法,现在可以进行任意计算。参见:https://*.com/a/36211337/895245

With an explicit GLfloat transform[] it would look something like this:

使用一个显式的GLfloat变换[],它看起来会是这样的:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include "common.h"

static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
/* ourColor is passed on to the fragment shader. */
static const GLchar* vertex_shader_source =
    "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\n"
    "uniform mat4 transform;\n"
    "void main() {\n"
    "    gl_Position = transform * vec4(position, 1.0f);\n"
    "    ourColor = color;\n"
    "}\n";
static const GLchar* fragment_shader_source =
    "#version 330 core\n"
    "in vec3 ourColor;\n"
    "out vec4 color;\n"
    "void main() {\n"
    "    color = vec4(ourColor, 1.0f);\n"
    "}\n";
static GLfloat vertices[] = {
/*   Positions          Colors */
     0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};

int main(void) {
    GLint shader_program;
    GLint transform_location;
    GLuint vbo;
    GLuint vao;
    GLFWwindow* window;
    double time;

    glfwInit();
    window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glViewport(0, 0, WIDTH, HEIGHT);

    shader_program = common_get_shader_program(vertex_shader_source, fragment_shader_source);

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    /* Position attribute */
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    /* Color attribute */
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader_program);
        transform_location = glGetUniformLocation(shader_program, "transform");
        /* THIS is just a dummy transform. */
        GLfloat transform[] = {
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f,
        };
        time = glfwGetTime();
        transform[0] = 2.0f * sin(time);
        transform[5] = 2.0f * cos(time);
        glUniformMatrix4fv(transform_location, 1, GL_FALSE, transform);

        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glfwTerminate();
    return EXIT_SUCCESS;
}

Generated output: http://imgur.com/QVW14Gu

生成的输出:http://imgur.com/QVW14Gu

The matrix for glOrtho is really simple, composed only of scaling and translation:

glOrtho的矩阵真的很简单,只由缩放和平移组成:

scalex, 0,      0,      translatex,
0,      scaley, 0,      translatey,
0,      0,      scalez, translatez,
0,      0,      0,      1

as mentioned in the OpenGL 2 docs.

如OpenGL 2文档中提到的。

The glFrustum matrix is not too hard to calculate by hand either, but starts getting annoying. Note how frustum cannot be made up with only scaling and translations like glOrtho, more info at: https://gamedev.stackexchange.com/a/118848/25171

glFrustum矩阵也不是很难手工计算,但开始变得令人讨厌。请注意,frustum不能仅通过缩放和翻译(如glOrtho)来弥补,更多信息见:https://gamedev.stackexchange.com/a/118848/25171

The GLM OpenGL C++ math library is a popular choice for calculating such matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documents both an ortho and frustum operations.

GLM OpenGL c++数学库是计算此类矩阵的常用选择。http://glm.g-truc.net/0.9.2/api/a00245.html文档都包含了ortho和frustum操作。

#3


4  

glOrtho describes a transformation that produces a parallel projection. The current matrix (see glMatrixMode) is multiplied by this matrix and the result replaces the current matrix, as if glMultMatrix were called with the following matrix as its argument:

glOrtho描述了一个产生平行投影的变换。将当前矩阵(参见glMatrixMode)乘以这个矩阵,结果替换了当前矩阵,就好像glMultMatrix是以以下矩阵作为参数调用的:

OpenGL documentation (my bold)

OpenGL文档(我大胆)

The numbers define the locations of the clipping planes (left, right, bottom, top, near and far).

这些数字定义了剪切面的位置(左、右、下、顶、近和远)。

The "normal" projection is a perspective projection that provides the illusion of depth. Wikipedia defines a parallel projection as:

“正常”投影是提供深度错觉的透视投影。*将平行投影定义为:

Parallel projections have lines of projection that are parallel both in reality and in the projection plane.

平行投影在现实和投影平面都有平行的投影。

Parallel projection corresponds to a perspective projection with a hypothetical viewpoint—e.g., one where the camera lies an infinite distance away from the object and has an infinite focal length, or "zoom".

平行投影相当于一个假想视点的透视投影。其中,摄像机距离物体有无限远的距离,有无限焦距,或“变焦”。

#1


120  

Have a look at this picture: Graphical Projections 如何在OpenGL中使用glOrtho() ?

看看这幅图:图形投影?

The glOrtho command produces an "Oblique" projection that you see in the bottom row. No matter how far away vertexes are in the z direction, they will not recede into the distance.

glOrtho命令产生一个“倾斜”投影,你可以在下面一行看到。无论顶点在z方向上有多远,它们都不会退到远处去。

I use glOrtho every time I need to do 2D graphics in OpenGL (such as health bars, menus etc) using the following code every time the window is resized:

每次需要在OpenGL(比如健康栏、菜单等)中进行二维图形处理时,我都会使用glOrtho,每次调整窗口大小时都使用以下代码:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);

This will remap the OpenGL coordinates into the equivalent pixel values (X going from 0 to windowWidth and Y going from 0 to windowHeight). Note that I've flipped the Y values because OpenGL coordinates start from the bottom left corner of the window. So by flipping, I get a more conventional (0,0) starting at the top left corner of the window rather.

这将把OpenGL坐标重新映射到等效像素值(X从0到windowWidth, Y从0到windowh8)。注意,我翻转了Y值,因为OpenGL坐标从窗口的左下角开始。通过翻转,我得到一个更常规的(0,0)从窗口的左上角开始。

#2


35  

glOrtho: 2D games, objects close and far appear the same size:

glOrtho: 2D游戏,接近和远的物体呈现相同的尺寸:

如何在OpenGL中使用glOrtho() ?

glFrustrum: more real-life like 3D, identical objects further away appear smaller:

更真实的物体,比如3D,离得更远的物体看起来更小:

如何在OpenGL中使用glOrtho() ?

Code

代码

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

static int ortho = 0;

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    if (ortho) {
    } else {
        /* This only rotates and translates the world around to look like the camera moved. */
        gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    }
    glColor3f(1.0f, 1.0f, 1.0f);
    glutWireCube(2);
    glFlush();
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (ortho) {
        glOrtho(-2.0, 2.0, -2.0, 2.0, -1.5, 1.5);
    } else {
        glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    }
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    if (argc > 1) {
        ortho = 1;
    }
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Schema

模式

Ortho: camera is a plane, visible volume a rectangle:

正形:相机为平面,可见体积为矩形:

如何在OpenGL中使用glOrtho() ?

Frustrum: camera is a point,visible volume a slice of a pyramid:

挫折:相机是一个点,可见体积是金字塔的一部分:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

Parameters

参数

We are always looking from +z to -z with +y upwards:

我们总是从+z到-z +y向上看:

glOrtho(left, right, bottom, top, near, far)
  • left: minimum x we see
  • 左:最小x
  • right: maximum x we see
  • 右:我们看到的最大x。
  • bottom: minimum y we see
  • 底部:我们看到的最小的y。
  • top: maximum y we see
  • 我们看到的最大y值
  • -near: minimum z we see. Yes, this is -1 times near. So a negative input means positive z.
  • 我们看到的最小z。是的,这是-1倍。所以负输入表示正z。
  • -far: maximum z we see. Also negative.
  • -远:我们看到的最大z。也消极。

Schema:

模式:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

How it works under the hood

它是如何在引擎盖下工作的

In the end, OpenGL always "uses":

最后,OpenGL总是“使用”:

glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

If we use neither glOrtho nor glFrustrum, that is what we get.

如果我们既不使用glOrtho也不使用glum,那就是我们得到的结果。

glOrtho and glFrustrum are just linear transformations (AKA matrix multiplication) such that:

glOrtho和glum只是线性变换(又称矩阵乘法),使得:

  • glOrtho: takes a given 3D rectangle into the default cube
  • glOrtho:将给定的3D矩形放入默认的立方体中
  • glFrustrum: takes a given pyramid section into the default cube
  • glum:将给定的金字塔部分放入默认的多维数据集。

This transformation is then applied to all vertexes. This is what I mean in 2D:

然后将这个转换应用到所有的顶点。这就是我所说的2D:

如何在OpenGL中使用glOrtho() ?

Image source.

图像源。

The final step after transformation is simple:

转换后的最后一步很简单:

  • remove any points outside of the cube (culling): just ensure that x, y and z are in [-1, +1]
  • 删除立方体外的任何点(剔除):只需确保x、y和z在[-1,+1]中
  • ignore the z component and take only x and y, which now can be put into a 2D screen
  • 忽略z分量,只取x和y,现在可以放到2D屏幕上

With glOrtho, z is ignored, so you might as well always use 0.

对于glOrtho, z被忽略,所以你最好总是用0。

One reason you might want to use z != 0 is to make sprites hide the background with the depth buffer.

您可能希望使用z != 0的一个原因是使精灵使用深度缓冲区隐藏背景。

Deprecation

弃用

glOrtho is deprecated as of OpenGL 4.5: the compatibility profile 12.1. "FIXED-FUNCTION VERTEX TRANSFORMATIONS" is in red.

在OpenGL 4.5:兼容性配置文件12.1中,不赞成使用glOrtho。“固定函数顶点变换”是红色的。

So don't use it for production. In any case, understanding it is a good way to get some OpenGL insight.

所以不要用它来生产。无论如何,理解它是获得一些OpenGL洞察力的好方法。

Modern OpenGL 4 programs calculate the transformation matrix (which is small) on the CPU, and then give the matrix and all points to be transformed to OpenGL, which can do the thousands of matrix multiplications for different points really fast in parallel.

现代的OpenGL 4程序在CPU上计算变换矩阵(它很小),然后给出矩阵和所有要转换成OpenGL的点,OpenGL可以并行地对不同的点进行成千上万的矩阵乘法。

Manually written vertex shaders then do the multiplication explicitly, usually with the convenient vector data types of the OpenGL Shading Language.

手工编写顶点着色器然后显式地做乘法,通常使用方便的矢量数据类型的OpenGL着色语言。

Since you write the shader explicitly, this allows you to tweak the algorithm to your needs. Such flexibility is a major feature of more modern GPUs, which unlike the old ones that did a fixed algorithm with some input parameters, can now do arbitrary computations. See also: https://*.com/a/36211337/895245

由于您显式地编写着色器,这允许您根据需要调整算法。这种灵活性是更现代的gpu的一个主要特性,它不像以前使用一些输入参数的固定算法,现在可以进行任意计算。参见:https://*.com/a/36211337/895245

With an explicit GLfloat transform[] it would look something like this:

使用一个显式的GLfloat变换[],它看起来会是这样的:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include "common.h"

static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
/* ourColor is passed on to the fragment shader. */
static const GLchar* vertex_shader_source =
    "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\n"
    "uniform mat4 transform;\n"
    "void main() {\n"
    "    gl_Position = transform * vec4(position, 1.0f);\n"
    "    ourColor = color;\n"
    "}\n";
static const GLchar* fragment_shader_source =
    "#version 330 core\n"
    "in vec3 ourColor;\n"
    "out vec4 color;\n"
    "void main() {\n"
    "    color = vec4(ourColor, 1.0f);\n"
    "}\n";
static GLfloat vertices[] = {
/*   Positions          Colors */
     0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};

int main(void) {
    GLint shader_program;
    GLint transform_location;
    GLuint vbo;
    GLuint vao;
    GLFWwindow* window;
    double time;

    glfwInit();
    window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glViewport(0, 0, WIDTH, HEIGHT);

    shader_program = common_get_shader_program(vertex_shader_source, fragment_shader_source);

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    /* Position attribute */
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    /* Color attribute */
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader_program);
        transform_location = glGetUniformLocation(shader_program, "transform");
        /* THIS is just a dummy transform. */
        GLfloat transform[] = {
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f,
        };
        time = glfwGetTime();
        transform[0] = 2.0f * sin(time);
        transform[5] = 2.0f * cos(time);
        glUniformMatrix4fv(transform_location, 1, GL_FALSE, transform);

        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glfwTerminate();
    return EXIT_SUCCESS;
}

Generated output: http://imgur.com/QVW14Gu

生成的输出:http://imgur.com/QVW14Gu

The matrix for glOrtho is really simple, composed only of scaling and translation:

glOrtho的矩阵真的很简单,只由缩放和平移组成:

scalex, 0,      0,      translatex,
0,      scaley, 0,      translatey,
0,      0,      scalez, translatez,
0,      0,      0,      1

as mentioned in the OpenGL 2 docs.

如OpenGL 2文档中提到的。

The glFrustum matrix is not too hard to calculate by hand either, but starts getting annoying. Note how frustum cannot be made up with only scaling and translations like glOrtho, more info at: https://gamedev.stackexchange.com/a/118848/25171

glFrustum矩阵也不是很难手工计算,但开始变得令人讨厌。请注意,frustum不能仅通过缩放和翻译(如glOrtho)来弥补,更多信息见:https://gamedev.stackexchange.com/a/118848/25171

The GLM OpenGL C++ math library is a popular choice for calculating such matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documents both an ortho and frustum operations.

GLM OpenGL c++数学库是计算此类矩阵的常用选择。http://glm.g-truc.net/0.9.2/api/a00245.html文档都包含了ortho和frustum操作。

#3


4  

glOrtho describes a transformation that produces a parallel projection. The current matrix (see glMatrixMode) is multiplied by this matrix and the result replaces the current matrix, as if glMultMatrix were called with the following matrix as its argument:

glOrtho描述了一个产生平行投影的变换。将当前矩阵(参见glMatrixMode)乘以这个矩阵,结果替换了当前矩阵,就好像glMultMatrix是以以下矩阵作为参数调用的:

OpenGL documentation (my bold)

OpenGL文档(我大胆)

The numbers define the locations of the clipping planes (left, right, bottom, top, near and far).

这些数字定义了剪切面的位置(左、右、下、顶、近和远)。

The "normal" projection is a perspective projection that provides the illusion of depth. Wikipedia defines a parallel projection as:

“正常”投影是提供深度错觉的透视投影。*将平行投影定义为:

Parallel projections have lines of projection that are parallel both in reality and in the projection plane.

平行投影在现实和投影平面都有平行的投影。

Parallel projection corresponds to a perspective projection with a hypothetical viewpoint—e.g., one where the camera lies an infinite distance away from the object and has an infinite focal length, or "zoom".

平行投影相当于一个假想视点的透视投影。其中,摄像机距离物体有无限远的距离,有无限焦距,或“变焦”。