Saya tidak mengerti penggunaan glOrtho
. Adakah yang bisa menjelaskan kegunaannya?
Apakah digunakan untuk mengatur kisaran batas koordinat xy dan z?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Artinya rentang x, y, dan z adalah dari -1 hingga 1?
Saya tidak mengerti penggunaan glOrtho
. Adakah yang bisa menjelaskan kegunaannya?
Apakah digunakan untuk mengatur kisaran batas koordinat xy dan z?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Artinya rentang x, y, dan z adalah dari -1 hingga 1?
Jawaban:
Lihat gambar ini: Proyeksi Grafis
The glOrtho
perintah menghasilkan "Oblique" proyeksi yang Anda lihat di baris bawah. Tidak peduli seberapa jauh titik sudut dalam arah z, mereka tidak akan mundur ke kejauhan.
Saya menggunakan glOrtho setiap kali saya perlu melakukan grafik 2D di OpenGL (seperti bilah kesehatan, menu, dll.) Menggunakan kode berikut setiap kali jendela diubah ukurannya:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);
Ini akan memetakan ulang koordinat OpenGL menjadi nilai piksel yang setara (X bergerak dari 0 ke windowWidth dan Y dari 0 ke windowHeight). Perhatikan bahwa saya telah membalik nilai Y karena koordinat OpenGL dimulai dari sudut kiri bawah jendela. Jadi dengan membalik, saya mendapatkan yang lebih konvensional (0,0) mulai dari sudut kiri atas jendela.
Perhatikan bahwa nilai Z dipotong dari 0 ke 1. Jadi berhati-hatilah saat Anda menentukan nilai Z untuk posisi puncak Anda, nilai itu akan dipotong jika berada di luar rentang itu. Jika tidak, jika berada di dalam kisaran itu, itu tidak akan berpengaruh pada posisi kecuali untuk pengujian Z.
z= -2
. Segitiga itu tak terlihat jika saya menggunakan glOrtho(.., 0.0f, -4.0f);
, ..-1.0f, -3.0f)
atau ..-3.0f, -1.0f)
. Agar terlihat, parameter jauh harus POSITIF 2 atau lebih besar; tampaknya tidak peduli apa parameter dekat itu. Semua ini bekerja: ..0.0f, 2.0f)
, ..-1.0f, 2.0f)
, ..-3.0f, 2.0f)
, atau ..0.0f, 1000.0f
.
Contoh minimal runnable
glOrtho
: Game 2D, objek dekat dan jauh tampak berukuran sama:
glFrustrum
: lebih nyata seperti 3D, objek identik yang jauh tampak lebih kecil:
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;
}
Menyusun:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
Jalankan dengan glOrtho
:
./main 1
Jalankan dengan glFrustrum
:
./main
Diuji di Ubuntu 18.10.
Skema
Ortho: kamera adalah bidang, volume terlihat persegi panjang:
Frustrum: kamera adalah sebuah titik, volume yang terlihat adalah sepotong piramida:
Parameter
Kami selalu melihat dari + z ke -z dengan + y ke atas:
glOrtho(left, right, bottom, top, near, far)
left
: minimal x
kita lihatright
: maksimal yang x
kami lihatbottom
: minimal y
kita lihattop
: maksimal yang y
kami lihat-near
: minimal z
kita lihat. Ya , ini -1
saatnya near
. Jadi masukan negatif berarti positif z
.-far
: maksimal yang z
kami lihat. Juga negatif.Skema:
Cara kerjanya di bawah tenda
Pada akhirnya, OpenGL selalu "menggunakan":
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Jika kita tidak menggunakan glOrtho
atau glFrustrum
, itulah yang kita dapatkan.
glOrtho
dan glFrustrum
hanya transformasi linier (perkalian matriks AKA) seperti itu:
glOrtho
: mengambil persegi 3D tertentu ke dalam kubus defaultglFrustrum
: mengambil bagian piramida tertentu ke dalam kubus defaultTransformasi ini kemudian diterapkan ke semua simpul. Inilah yang saya maksud dalam 2D:
Langkah terakhir setelah transformasi sederhana:
x
, y
dan z
berada di[-1, +1]
z
komponen tersebut dan ambil saja x
dan y
, yang sekarang dapat dimasukkan ke dalam layar 2DDengan glOrtho
, z
diabaikan, jadi sebaiknya Anda selalu menggunakan 0
.
Salah satu alasan Anda mungkin ingin menggunakan z != 0
adalah membuat sprite menyembunyikan latar belakang dengan buffer kedalaman.
Bantahan
glOrtho
tidak digunakan lagi sejak OpenGL 4.5 : profil kompatibilitas 12.1. "TRANSFORMASI VERTEX FUNGSI TETAP" berwarna merah.
Jadi jangan gunakan untuk produksi. Bagaimanapun, memahaminya adalah cara yang baik untuk mendapatkan beberapa wawasan OpenGL.
Program OpenGL 4 modern menghitung matriks transformasi (yang kecil) pada CPU, dan kemudian memberikan matriks dan semua titik untuk diubah menjadi OpenGL, yang dapat melakukan ribuan perkalian matriks untuk berbagai titik dengan sangat cepat secara paralel.
Vertex shader yang ditulis secara manual kemudian melakukan perkalian secara eksplisit, biasanya dengan tipe data vektor yang sesuai dari OpenGL Shading Language.
Karena Anda menulis shader secara eksplisit, ini memungkinkan Anda menyesuaikan algoritme dengan kebutuhan Anda. Fleksibilitas semacam itu adalah fitur utama dari GPU yang lebih modern, yang tidak seperti yang lama yang melakukan algoritme tetap dengan beberapa parameter input, sekarang dapat melakukan penghitungan sewenang-wenang. Lihat juga: https://stackoverflow.com/a/36211337/895245
Dengan eksplisit GLfloat transform[]
akan terlihat seperti ini:
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;
}
Kompilasi dan jalankan:
gcc -ggdb3 -O0 -o glfw_transform.out -std=c99 -Wall -Wextra -pedantic glfw_transform.c -lGL -lGLU -lglut -lGLEW -lglfw -lm
./glfw_transform.out
Keluaran:
Matriks untuk glOrtho
sangat sederhana, hanya terdiri dari penskalaan dan terjemahan:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
seperti yang disebutkan dalam dokumen OpenGL 2 .
The glFrustum
matriks tidak terlalu sulit untuk menghitung dengan tangan baik, tapi mulai mendapatkan menjengkelkan. Perhatikan bagaimana frustum tidak dapat dibuat hanya dengan penskalaan dan terjemahan seperti glOrtho
, info lebih lanjut di: https://gamedev.stackexchange.com/a/118848/25171
Pustaka matematika GLM OpenGL C ++ adalah pilihan populer untuk menghitung matriks semacam itu. http://glm.g-truc.net/0.9.2/api/a00245.html mendokumentasikan baik ortho
dan frustum
operasi.
common.h:19:23: error: ‘TIME_UTC’ undeclared (first use in this function) timespec_get(&ts, TIME_UTC);
glOrtho menjelaskan transformasi yang menghasilkan proyeksi paralel . Matriks saat ini (lihat glMatrixMode) dikalikan dengan matriks ini dan hasilnya menggantikan matriks saat ini, seolah-olah glMultMatrix dipanggil dengan matriks berikut sebagai argumennya:
Dokumentasi OpenGL (cetak tebal saya)
Angka-angka menentukan lokasi bidang kliping (kiri, kanan, bawah, atas, dekat dan jauh).
Proyeksi "normal" adalah proyeksi perspektif yang memberikan ilusi kedalaman. Wikipedia mendefinisikan proyeksi paralel sebagai:
Proyeksi paralel memiliki garis proyeksi yang sejajar baik dalam realita maupun dalam bidang proyeksi.
Proyeksi paralel berhubungan dengan proyeksi perspektif dengan sudut pandang hipotetis — misalnya, proyeksi di mana kamera berada dalam jarak tak terhingga dari objek dan memiliki panjang fokus tak terbatas, atau "zoom".