2010-04-03 40 views
65

Tôi không thể hiểu việc sử dụng glOrtho. Ai đó có thể giải thích những gì nó được sử dụng cho?Giải thích việc sử dụng glOrtho()?

Cập nhật

Được sử dụng để đặt phạm vi giới hạn tọa độ x y và z?

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

Điều đó có nghĩa là phạm vi x, y và z là từ -1 đến 1?

+0

[This] (https://www.youtube.com/watch?v=8ryJMO6rBT4) video đã giúp tôi rất nhiều. – ViniciusArruda

Trả lời

117

Hãy nhìn vào bức tranh này: Graphical Projections enter image description here

Lệnh glOrtho tạo ra một "xiên" chiếu mà bạn nhìn thấy ở hàng dưới cùng. Không có vấn đề làm thế nào xa các đỉnh theo hướng z, họ sẽ không rút vào khoảng cách.

tôi sử dụng glOrtho mỗi khi tôi cần phải làm đồ họa 2D trong OpenGL (như thanh sức khỏe, các menu vv) sử dụng đoạn mã sau mỗi khi cửa sổ được thay đổi kích cỡ:

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

này sẽ remap các OpenGL tọa độ thành các giá trị pixel tương đương (X đi từ 0 đến windowWidth và Y đi từ 0 đến windowHeight). Lưu ý rằng tôi đã lật các giá trị Y vì các tọa độ OpenGL bắt đầu từ góc dưới bên trái của cửa sổ. Vì vậy, bằng cách lật, tôi nhận được một thông thường (0,0) bắt đầu từ góc trên bên trái của cửa sổ thay vì.

+3

cảm ơn rất nhiều vì đã làm rõ vấn đề! :) – ufk

+74

ôi chúa ơi, tôi yêu bạn. Bạn có bất kỳ ý tưởng phải mất bao lâu để tìm/tìm ra dòng mã trực tuyến này? Cảm ơn bạn, tôi sẽ đặt tên đứa con đầu lòng của tôi sau khi bạn cho số này – karpathy

+1

Lưu ý: (trên Android) ngay cả khi mô hình chỉ có giá trị z âm, có vẻ như cần phải có giá trị dương cho tham số cuối cùng (xa). Tôi đã làm một thử nghiệm tam giác đơn giản (với culling disabled), với các đỉnh tại 'z = -2'. Tam giác vô hình nếu tôi sử dụng 'glOrtho (.., 0,0f, -4.0f);', '..- 1.0f, -3.0f)', hoặc '..- 3.0f, -1.0f)'. Để hiển thị, tham số xa phải là TÍCH CỰC 2 hoặc cao hơn; dường như không có vấn đề gì với thông số gần. Bất kỳ tác vụ nào trong số này hoạt động: '..0.0f, 2.0f)', '..- 1.0f, 2.0f)', '..- 3.0f, 2.0f)', hoặc '..0.0f, 1000.0f' . – ToolmakerSteve

3

glOrtho mô tả phép biến đổi tạo ra một phép chiếu song song. Ma trận hiện tại (xem glMatrixMode) được nhân với ma trận này và kết quả thay thế ma trận hiện tại, như thể glMultMatrix được gọi với ma trận sau đây như là đối số của nó:

OpenGL documentation (đậm của tôi)

Các con số xác định vị trí của các mặt cắt (trái, phải, đáy, đỉnh, gần và xa).

Phép chiếu "bình thường" là phép chiếu phối cảnh cung cấp ảo ảnh về chiều sâu. Wikipedia xác định phép chiếu song song là:

Dự đoán song song có các đường chiếu song song cả trên thực tế và mặt phẳng chiếu.

Phép chiếu song song tương ứng với phép chiếu phối cảnh với quan điểm giả thiết — ví dụ: một máy ảnh nằm cách khoảng cách vô hạn đối tượng và có độ dài tiêu cự vô hạn hoặc "thu phóng".

+0

hi cảm ơn thông tin. tôi hoàn toàn không thể hiểu được sự khác biệt giữa phép chiếu song song và phối cảnh. tôi googled một chút và tìm thấy câu trả lời trong http://wiki.answers.com/Q/What_is_the_difference_between_orthogonal_and_perspective_projection – ufk

+6

Thật không may là thông tin bạn nhận được từ answers.com là khá vô giá trị. Ví dụ, một khung nhìn isometric là rất 3-D, nhưng nó là một phép chiếu song song không có phối cảnh. Xem ở đây, và cũng có các liên kết đến nhiều ví dụ khác về phép chiếu: http://en.wikipedia.org/wiki/Isometric_projection –

32

glOrtho: trò chơi 2D, các đối tượng gần gũi và xuất hiện xa cùng kích thước:

glFrustrum: hơn thực tế cuộc sống như 3D, các đối tượng giống hệt nhau xa xuất hiện nhỏ hơn:

#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: máy ảnh là một chiếc máy bay, khối lượng có thể nhìn thấy một hình chữ nhật:

enter image description here

Frustrum: máy ảnh là một điểm, khối lượng có thể nhìn thấy một lát một kim tự tháp:

enter image description here

Image source.

thông số

Chúng tôi luôn tìm kiếm từ + z để -Z với + y trở lên:

glOrtho(left, right, bottom, top, near, far) 
  • left: tối thiểu x
  • right chúng ta thấy: tối đa x chúng ta thấy
  • bottom: giảm thiểu um y chúng ta thấy
  • top: tối đa y chúng ta thấy
  • -near: tối thiểu z chúng ta thấy. , đây là -1 lần near. Vì vậy, một đầu vào tiêu cực có nghĩa là tích cực z.
  • -far: tối đa z chúng tôi thấy. Cũng tiêu cực.

Schema:

Image source.

Cách thức hoạt động dưới mui xe

Cuối cùng, OpenGL luôn "sử dụng":

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

Nếu chúng ta sử dụng không glOrtho cũng không glFrustrum, đó là những gì chúng tôi nhận được.

glOrthoglFrustrum là biến đổi chỉ tuyến tính (AKA nhân ma trận) sao cho:

  • glOrtho: mất một hình chữ nhật 3D cho vào khối mặc định
  • glFrustrum: mất một phần kim tự tháp được vào khối mặc định

Chuyển đổi này sau đó được áp dụng cho tất cả các đỉnh. Đây là những gì tôi muốn nói trong 2D:

Image source.

Bước cuối cùng sau khi chuyển đổi rất đơn giản:

  • loại bỏ bất kỳ điểm bên ngoài của khối lập phương (tiêu huỷ): chỉ cần đảm bảo rằng x, yz là trong [-1, +1]
  • bỏ qua các thành phần z và chăm chỉ xy, hiện có thể được đưa vào màn hình 2D

Với glOrtho, z bị bỏ qua, vì vậy bạn cũng có thể sử dụng 0.

Một lý do bạn có thể muốn sử dụng z != 0 là làm cho hình ảnh ẩn ẩn nền với bộ đệm độ sâu.

Deprecation

glOrtho bị phản đối như của OpenGL 4.5: hồ sơ cá nhân tương thích 12.1. "FIXED-FUNCTION VERTEX TRANSFORMATIONS" có màu đỏ.

Vì vậy, không sử dụng nó để sản xuất. Trong bất kỳ trường hợp nào, việc hiểu nó là một cách hay để có được một số thông tin chi tiết về OpenGL.

Chương trình OpenGL 4 hiện đại tính ma trận chuyển đổi (nhỏ) trên CPU, sau đó cung cấp ma trận và tất cả các điểm được chuyển thành OpenGL, có thể thực hiện hàng nghìn phép nhân cho các điểm khác nhau. .

Viết thủ công vertex shaders sau đó thực hiện phép nhân một cách rõ ràng, thường với các loại dữ liệu vectơ thuận tiện của Ngôn ngữ đổ bóng OpenGL.

Vì bạn viết bóng đổ một cách rõ ràng, điều này cho phép bạn tinh chỉnh thuật toán theo nhu cầu của mình. Tính linh hoạt như vậy là một tính năng chính của các GPU hiện đại hơn, không giống như các GPU cũ đã thực hiện một thuật toán cố định với một số tham số đầu vào, giờ đây có thể thực hiện các phép tính tùy ý.Xem thêm: https://stackoverflow.com/a/36211337/895245

Với một rõ ràng GLfloat transform[] nó sẽ giống như thế này:

#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; 
} 

tạo đầu ra: http://imgur.com/QVW14Gu

Ma trận cho glOrtho là thực sự đơn giản, chỉ gồm các mở rộng quy mô và bản dịch:

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

như đã đề cập trong OpenGL 2 docs.

glFrustum matrix cũng không quá khó để tính bằng tay, nhưng bắt đầu trở nên khó chịu. Lưu ý mức độ thất vọng không thể được thực hiện chỉ với quy mô lớn và các bản dịch như glOrtho, thông tin khác tại: https://gamedev.stackexchange.com/a/118848/25171

Thư viện toán GLM OpenGL C++ là một lựa chọn phổ biến để tính toán các ma trận đó. http://glm.g-truc.net/0.9.2/api/a00245.html tài liệu cả hoạt động orthofrustum.

+1

"những gì nên được sử dụng thay thế?" - xây dựng ma trận của riêng bạn và chỉ định chúng trực tiếp. – Kromster

Các vấn đề liên quan