の使い方がわかりませんglOrtho
。誰かがそれが何のために使われるのか説明できますか?
xy座標とz座標の範囲の制限を設定するために使用されますか?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
これは、x、y、zの範囲が-1から1であることを意味しますか?
回答:
この写真を見てください:グラフィカルな投影
このglOrtho
コマンドは、下の行に表示される「斜投影」投影を生成します。頂点がz方向にどれだけ離れていても、その距離に後退することはありません。
ウィンドウのサイズが変更されるたびに次のコードを使用して、OpenGLで2Dグラフィックス(ヘルスバー、メニューなど)を実行する必要があるたびにglOrthoを使用します。
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);
これにより、OpenGL座標が同等のピクセル値に再マップされます(Xは0からwindowWidthに、Yは0からwindowHeightになります)。OpenGL座標はウィンドウの左下隅から始まるため、Y値を反転したことに注意してください。したがって、反転することで、ウィンドウの左上隅から開始する、より従来型の(0,0)を取得します。
Z値は0から1にクリップされることに注意してください。したがって、頂点の位置にZ値を指定するときは、その範囲外になるとクリップされることに注意してください。それ以外の場合、その範囲内であれば、Z検定を除いて位置に影響を与えないように見えます。
z= -2
。私が使用している場合、三角形が見えなかったglOrtho(.., 0.0f, -4.0f);
、..-1.0f, -3.0f)
または..-3.0f, -1.0f)
。表示するには、farパラメーターがPOSITIVE2以上である必要がありました。ニアパラメータが何であるかは問題ではないようでした。これらのいずれかが働いた: ..0.0f, 2.0f)
、..-1.0f, 2.0f)
、..-3.0f, 2.0f)
、または..0.0f, 1000.0f
。
実行可能な最小限の例
glOrtho
:2Dゲーム、オブジェクトの近くと遠くは同じサイズで表示されます:
glFrustrum
:3Dのようなより現実的な、遠くにある同一のオブジェクトは小さく見えます:
main.c
#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;
}
コンパイル:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
で実行glOrtho
:
./main 1
で実行glFrustrum
:
./main
Ubuntu18.10でテスト済み。
スキーマ
オルソ:カメラは平面であり、可視ボリュームは長方形です:
錐台:カメラは点であり、目に見えるボリュームはピラミッドのスライスです:
パラメーター
私たちは常に+ zから-zまで+ yを上向きに見ています:
glOrtho(left, right, bottom, top, near, far)
left
:最小x
我々が見ますright
:x
私たちが見る最大bottom
:最小y
我々が見ますtop
:y
私たちが見る最大-near
:最小値z
が表示されます。はい、これは-1
時間near
です。したがって、負の入力は正を意味しz
ます。-far
:z
私たちが見る最大。また、否定的です。スキーマ:
内部でどのように機能するか
結局、OpenGLは常に以下を「使用」します。
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
私たちはどちらも使用している場合glOrtho
もをglFrustrum
、それは我々が得るものです。
glOrtho
そしてglFrustrum
、次のような線形変換(別名行列乗算)です。
glOrtho
:指定された3D長方形をデフォルトの立方体に取り込みますglFrustrum
:指定されたピラミッドセクションをデフォルトのキューブに取り込みますこの変換は、すべての頂点に適用されます。これは私が2Dで意味することです:
変換後の最後のステップは簡単です。
x
、y
そしてz
内にあります[-1, +1]
z
コンポーネントをのみ取るx
とy
、今の2D画面に入れることができましたではglOrtho
、z
あなたにも、常に使用することがありますので、無視されます0
。
使用する理由の1つz != 0
は、スプライトに深度バッファーで背景を非表示にすることです。
非推奨
glOrtho
OpenGL 4.5で非推奨になりました:互換性プロファイル12.1。「FIXED-FUNCTIONVERTEXTRANSFORMATIONS」は赤で表示されます。
したがって、本番環境には使用しないでください。いずれにせよ、それを理解することは、OpenGLの洞察を得るための良い方法です。
最新のOpenGL4プログラムは、CPU上で変換行列(小さい)を計算し、行列とすべての点をOpenGLに変換します。これにより、さまざまな点に対して数千の行列乗算を非常に高速に並行して実行できます。
次に、手動で記述された頂点シェーダーは、通常はOpenGLシェーディング言語の便利なベクターデータ型を使用して、明示的に乗算を実行します。
シェーダーを明示的に記述しているため、これにより、アルゴリズムをニーズに合わせて微調整できます。このような柔軟性は、最近のGPUの主要な機能であり、一部の入力パラメーターを使用して固定アルゴリズムを実行していた古いGPUとは異なり、任意の計算を実行できるようになりました。参照:https://stackoverflow.com/a/36211337/895245
明示的GLfloat transform[]
に使用すると、次のようになります。
glfw_transform.c
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.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
};
/* Build and compile shader program, return its ID. */
GLuint common_get_shader_program(
const char *vertex_shader_source,
const char *fragment_shader_source
) {
GLchar *log = NULL;
GLint log_length, success;
GLuint fragment_shader, program, vertex_shader;
/* Vertex shader */
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
if (log_length > 0) {
glGetShaderInfoLog(vertex_shader, log_length, NULL, log);
printf("vertex shader log:\n\n%s\n", log);
}
if (!success) {
printf("vertex shader compile error\n");
exit(EXIT_FAILURE);
}
/* Fragment shader */
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
log = realloc(log, log_length);
glGetShaderInfoLog(fragment_shader, log_length, NULL, log);
printf("fragment shader log:\n\n%s\n", log);
}
if (!success) {
printf("fragment shader compile error\n");
exit(EXIT_FAILURE);
}
/* Link shaders */
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
log = realloc(log, log_length);
glGetProgramInfoLog(program, log_length, NULL, log);
printf("shader link log:\n\n%s\n", log);
}
if (!success) {
printf("shader link error");
exit(EXIT_FAILURE);
}
/* Cleanup. */
free(log);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
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;
}
コンパイルして実行します。
gcc -ggdb3 -O0 -o glfw_transform.out -std=c99 -Wall -Wextra -pedantic glfw_transform.c -lGL -lGLU -lglut -lGLEW -lglfw -lm
./glfw_transform.out
出力:
のマトリックスglOrtho
は非常に単純で、スケーリングと変換のみで構成されています。
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
OpenGL2のドキュメントに記載されているように。
glFrustum
行列は、どちらかの手で計算するにはあまりにもハードではありませんが、迷惑な取得を開始します。錐台のみのスケーリングなどの翻訳をアップにすることはできませんどのように注glOrtho
:で、より多くの情報、https://gamedev.stackexchange.com/a/118848/25171
GLM OpenGL C ++数学ライブラリは、このような行列を計算するための一般的な選択肢です。http://glm.g-truc.net/0.9.2/api/a00245.htmlには、ortho
とfrustum
操作の両方が記載されています。
common.h:19:23: error: ‘TIME_UTC’ undeclared (first use in this function) timespec_get(&ts, TIME_UTC);
glOrthoは、平行投影を生成する変換について説明します。現在の行列(glMatrixModeを参照)にこの行列が乗算され、結果は、glMultMatrixが引数として次の行列で呼び出されたかのように、現在の行列を置き換えます。
OpenGLドキュメント(私の太字)
数字は、クリッピングプレーンの位置(左、右、下、上、近く、遠く)を定義します。
「通常の」投影は、奥行きの錯覚を提供する透視投影です。ウィキペディアでは、平行投影を次のように定義しています。
平行投影には、実際と投影面の両方で平行な投影線があります。
平行投影は、仮想的な視点を使用した透視投影に対応します。たとえば、カメラがオブジェクトから無限の距離にあり、無限の焦点距離、つまり「ズーム」を持っている投影です。