OpenGL에서 glOrtho ()를 사용하는 방법은 무엇입니까?


87

의 사용법을 이해할 수 없습니다 glOrtho. 누군가 그것이 무엇을 위해 사용되는지 설명 할 수 있습니까?

xy 및 z 좌표 제한 범위를 설정하는 데 사용됩니까?

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

x, y 및 z 범위가 -1에서 1까지임을 의미합니까?


1
비디오는 저에게 많은 도움 되었습니다.
ViniciusArruda

답변:


153

이 그림을보십시오 : 그래픽 프로젝션 여기에 이미지 설명 입력

glOrtho명령은 맨 아래 행에 표시되는 "Oblique"투영을 생성합니다. 정점이 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 테스트를 제외하고 위치에 영향을 미치지 않는 것처럼 보입니다.


90
오 마이 갓 사랑해. 온라인에서이 한 줄의 코드를 찾고 파악하는 데 얼마나 걸리는지 아십니까? 감사합니다. 나는 이것을 위해 당신의 이름을 따서 첫 번째 태어난 아이를
지을

2
참고 : (Android에서) 모델에 음의 z 값만 있더라도 최종 (원거리) 매개 변수에 양수 값을 가져야하는 것 같습니다. 저는 컬링이 비활성화 된 간단한 삼각형 테스트를했습니다 z= -2. 내가 사용하는 경우 삼각형은 눈에 보이지 않는이었다 glOrtho(.., 0.0f, -4.0f);, ..-1.0f, -3.0f)또는 ..-3.0f, -1.0f). 표시하려면 far 매개 변수가 POSITIVE 2 이상이어야합니다. near 매개 변수가 무엇인지는 중요하지 않은 것 같습니다. 이들 중 어떤 일 : ..0.0f, 2.0f), ..-1.0f, 2.0f), ..-3.0f, 2.0f), 또는 ..0.0f, 1000.0f.
ToolmakerSteve 2014 년

9
OpenGl에 대한 나쁜 튜토리얼의 양은 우스꽝 스럽습니다.
basickarl 2014

1
@Kari,이 링크가 도움이되기를 바랍니다. > learnopengl.com/#!In-Practice/2D-Game/Rendering-Sprites
huahsin68

1
@mgouin z 범위는 Z-near 평면과 Z-far 평면의 위치를 ​​지정합니다. 지오메트리를 그릴 때 Z 값 두 Z 평면 내부에 있어야합니다 . Z 평면을 벗어나면 형상이 렌더링되지 않습니다. 또한 렌더러에는 깊이에 대한 특정 해상도 만 있습니다. 먼 평면을 1000 단위로 설정하고 작은 얼굴이 서로 0.1 단위 떨어진 작은 모델을 그리려고하면 OpenGL은 필요한 깊이 해상도를 제공 할 수 없으며 Z- 파이팅 (깜박임)이 발생합니다. 얼굴 사이.
Mikepote 2017 년

54

최소 실행 가능 예

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

GitHub 업스트림 .

엮다:

gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut

다음으로 실행 glOrtho:

./main 1

다음으로 실행 glFrustrum:

./main

Ubuntu 18.10에서 테스트되었습니다.

개요

직교 : 카메라는 평면이고 가시적 볼륨은 직사각형입니다.

여기에 이미지 설명 입력

Frustrum : 카메라는 포인트, 가시적 볼륨, 피라미드 조각 :

여기에 이미지 설명 입력

이미지 소스 .

매개 변수

우리는 항상 + 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, yz[-1, +1]
  • 무시 z구성 요소 만 가지고 xy지금은 2 차원 화면에 넣을 수있는,

glOrtho, z무시, 그래서 당신은뿐만 아니라 항상 사용할 수 있습니다 0.

사용하고 싶은 한 가지 이유 z != 0는 스프라이트가 깊이 버퍼로 배경을 숨기도록 만드는 것입니다.

천칭

glOrthoOpenGL 4.5 : 호환성 프로파일 12.1부터 더 이상 사용되지 않습니다 . "FIXED-FUNCTION VERTEX TRANSFORMATIONS"는 빨간색입니다.

따라서 생산에 사용하지 마십시오. 어쨌든 그것을 이해하는 것은 OpenGL에 대한 통찰력을 얻는 좋은 방법입니다.

최신 OpenGL 4 프로그램은 CPU에서 변환 행렬 (작은)을 계산 한 다음 행렬과 변환 할 모든 점을 OpenGL로 제공하여 여러 점에 대해 수천 개의 행렬 곱셈을 병렬로 매우 빠르게 수행 할 수 있습니다.

수동으로 작성된 버텍스 쉐이더 는 일반적으로 OpenGL 쉐이딩 언어의 편리한 벡터 데이터 유형을 사용하여 명시 적으로 곱셈을 수행합니다.

셰이더를 명시 적으로 작성하기 때문에 필요에 따라 알고리즘을 조정할 수 있습니다. 이러한 유연성은 일부 입력 매개 변수를 사용하여 고정 알고리즘을 수행 한 이전 GPU와 달리 이제 임의의 계산을 수행 할 수있는 최신 GPU의 주요 기능입니다. 참조 : https://stackoverflow.com/a/36211337/895245

명시 적으로 GLfloat transform[]다음과 같이 보일 것입니다.

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

GitHub 업스트림 .

산출:

여기에 이미지 설명 입력

매트릭스 glOrtho는 정말 간단하며 크기 조정과 변환으로 만 구성됩니다.

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

OpenGL 2 문서 에서 언급했듯이 .

glFrustum매트릭스는 두 손으로 계산에 너무 열심히하지,하지만 성가신 받고 시작합니다. 절두체는 확장 및 번역만으로 구성 할 수 없습니다 glOrtho. 자세한 내용은 https://gamedev.stackexchange.com/a/118848/25171

GLM OpenGL C ++ 수학 라이브러리는 이러한 행렬을 계산하는 데 널리 사용됩니다. http://glm.g-truc.net/0.9.2/api/a00245.htmlorthofrustum작업을 모두 설명합니다 .


1
"대신 무엇을 사용해야합니까?" -자신 만의 행렬을 구성하고 직접 할당합니다.
Kromster

4

glOrtho는 평행 투영 을 생성하는 변환을 설명합니다 . 현재 행렬 (glMatrixMode 참조)에이 행렬을 곱하고 결과는 glMultMatrix가 다음 행렬을 인수로 사용하여 호출 된 것처럼 현재 행렬을 대체합니다.

OpenGL 문서 (내 굵은 글씨)

숫자는 클리핑 평면의 위치를 ​​정의합니다 (왼쪽, 오른쪽, 아래쪽, 위쪽, 근거리 및 원거리).

"일반"투영은 깊이의 환상을 제공하는 원근 투영입니다. Wikipedia 는 병렬 투영을 다음과 같이 정의합니다.

평행 투영에는 실제와 투영 평면 모두에서 평행 한 투영 선이 있습니다.

평행 투영은 가상의 관점을 갖는 투시 투영에 해당합니다. 예를 들어, 카메라가 물체로부터 무한 거리에 있고 무한 초점 거리 또는 "줌"을 갖는 관점이 있습니다.


안녕하세요 정보 감사합니다. 평행 투영과 투시 투영의 차이점을 잘 이해할 수 없었습니다. 나는 조금 googled하고 wiki.answers.com/Q/
ufk

6
유감스럽게도 answers.com에서 얻은 정보는 꽤 쓸모가 없습니다. 예를 들어 등각 투영 뷰는 매우 3 차원이지만 원근이없는 평행 투영입니다. 여기를 참조하고 다른 많은 투영 예에 대한 링크도 있습니다. en.wikipedia.org/wiki/Isometric_projection
Ben Voigt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.