Minimum çalıştırılabilir örnek
glOrtho
: 2D oyunlar, yakın ve uzak nesneler aynı boyutta görünür:
glFrustrum
: 3D gibi daha fazla gerçek hayat, aynı nesneler daha uzakta daha küçük görünür:
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 {
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;
}
GitHub yukarı akış .
Derleyin:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
Şununla çalıştırın glOrtho
:
./main 1
Şununla çalıştırın glFrustrum
:
./main
Ubuntu 18.10'da test edilmiştir.
Şema
Ortho: kamera bir düzlem, görünür hacim bir dikdörtgendir:
Frustrum: kamera bir nokta, görünür hacim bir piramidin bir dilimi:
Görüntü kaynağı .
Parametreler
Her zaman + z'den -z'ye + y'den yukarı bakıyoruz:
glOrtho(left, right, bottom, top, near, far)
left
: asgari x
görüyoruz
right
: x
gördüğümüz maksimum
bottom
: asgari y
görüyoruz
top
: y
gördüğümüz maksimum
-near
: asgari z
görüyoruz. Evet , bu -1
zamanlar near
. Yani negatif girdi, pozitif anlamına gelir z
.
-far
: maksimum z
görüyoruz. Ayrıca olumsuz.
Şema:
Görüntü kaynağı .
Kaputun altında nasıl çalışır
Sonunda, OpenGL her zaman "kullanır":
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Ne kullanırsak ne glOrtho
de kullanırsak glFrustrum
, elde ettiğimiz budur.
glOrtho
ve glFrustrum
sadece doğrusal dönüşümlerdir (AKA matris çarpımı) öyle ki:
glOrtho
: belirli bir 3B dikdörtgeni varsayılan küpün içine alır
glFrustrum
: belirli bir piramit bölümünü varsayılan küpün içine alır
Bu dönüşüm daha sonra tüm tepe noktalarına uygulanır. 2D'de kastettiğim bu:
Görüntü kaynağı .
Dönüşümden sonraki son adım basittir:
- (itlaf) küpün herhangi noktaları dışında kaldırın: sadece sağlamak
x
, y
ve z
vardır[-1, +1]
z
bileşeni görmezden gelin ve yalnızca x
ve y
şimdi 2D ekrana yerleştirilebilen al
With glOrtho
, z
göz ardı edilir, bu yüzden her zaman kullanabilirsiniz 0
.
Kullanmak isteyebileceğiniz bir neden z != 0
, sprite'ların arka planı derinlik tamponuyla gizlemesini sağlamaktır.
Kullanımdan kaldırma
glOrtho
OpenGL 4.5 itibariyle kullanımdan kaldırılmıştır : uyumluluk profili 12.1. "SABİT FONKSİYONLU KÖŞE DÖNÜŞÜMLERİ" kırmızı renkte.
Bu yüzden onu üretim için kullanmayın. Her durumda, bunu anlamak OpenGL içgörüsü elde etmenin iyi bir yoludur.
Modern OpenGL 4 programları, CPU üzerindeki dönüşüm matrisini (küçük olan) hesaplar ve ardından matrisi ve dönüştürülecek tüm noktaları, farklı noktalar için binlerce matris çarpımını paralel olarak gerçekten hızlı yapabilen OpenGL'ye verir.
Manuel olarak yazılan köşe gölgelendiricileri daha sonra çarpımı açıkça, genellikle OpenGL Gölgelendirme Dilinin uygun vektör veri türleriyle yapar.
Gölgelendiriciyi açıkça yazdığınız için bu, algoritmayı ihtiyaçlarınıza göre ayarlamanıza olanak tanır. Bu tür bir esneklik, bazı giriş parametreleriyle sabit bir algoritma yapan eski GPU'ların aksine, artık rastgele hesaplamalar yapabilen daha modern GPU'ların önemli bir özelliğidir. Ayrıca bkz .: https://stackoverflow.com/a/36211337/895245
Açıkça ifade GLfloat transform[]
etmek gerekirse şuna benzer:
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;
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[] = {
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
};
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 = 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 = 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);
}
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);
}
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
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");
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;
}
GitHub yukarı akış .
Derleyin ve çalıştırın:
gcc -ggdb3 -O0 -o glfw_transform.out -std=c99 -Wall -Wextra -pedantic glfw_transform.c -lGL -lGLU -lglut -lGLEW -lglfw -lm
./glfw_transform.out
Çıktı:
Matrisi glOrtho
gerçekten basittir, yalnızca ölçeklendirme ve çeviriden oluşur:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
OpenGL 2 belgelerinde belirtildiği gibi .
glFrustum
Matris ya elle olarak hesaplanması çok zor değil, ama can sıkıcı oluyor başlar. Sadece ölçeklendirme ve çevirilerle nasıl hayal kırıklığı yaratılamayacağına dikkat edinglOrtho
, daha fazla bilgi için: https://gamedev.stackexchange.com/a/118848/25171
GLM OpenGL C ++ matematik kitaplığı, bu tür matrisleri hesaplamak için popüler bir seçimdir. http://glm.g-truc.net/0.9.2/api/a00245.html belgeler ikisi de bir ortho
ve frustum
operasyonları.