ฉันไม่เข้าใจการใช้งานของglOrtho
. ใครช่วยอธิบายว่ามันใช้ทำอะไร?
ใช้กำหนดช่วงพิกัด xy และ z หรือไม่?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
หมายความว่าช่วง x, y และ z อยู่ระหว่าง -1 ถึง 1?
ฉันไม่เข้าใจการใช้งานของglOrtho
. ใครช่วยอธิบายว่ามันใช้ทำอะไร?
ใช้กำหนดช่วงพิกัด xy และ z หรือไม่?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
หมายความว่าช่วง x, y และ z อยู่ระหว่าง -1 ถึง 1?
คำตอบ:
ดูภาพนี้: การฉายภาพ
glOrtho
คำสั่งผลิต "เอียง" ฉายที่คุณเห็นในแถวด้านล่าง ไม่ว่าจุดยอดจะอยู่ห่างออกไปในทิศทาง z แค่ไหนก็จะไม่ถอยกลับไปในระยะทาง
ฉันใช้ glOrtho ทุกครั้งที่ต้องทำกราฟิก 2 มิติใน OpenGL (เช่นแถบสุขภาพเมนู ฯลฯ ) โดยใช้รหัสต่อไปนี้ทุกครั้งที่ปรับขนาดหน้าต่าง:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);
สิ่งนี้จะทำการแมปพิกัด OpenGL ให้เป็นค่าพิกเซลที่เท่ากัน (X จาก 0 เป็น windowWidth และ Y จาก 0 เป็น windowHeight) โปรดทราบว่าฉันได้พลิกค่า Y เนื่องจากพิกัด OpenGL เริ่มจากมุมล่างซ้ายของหน้าต่าง ดังนั้นโดยการพลิกฉันจะได้รับแบบธรรมดามากขึ้น (0,0) โดยเริ่มที่มุมซ้ายบนของหน้าต่าง
โปรดทราบว่าค่า Z ถูกตัดจาก 0 ถึง 1 ดังนั้นโปรดใช้ความระมัดระวังเมื่อคุณระบุค่า Z สำหรับตำแหน่งจุดยอดของคุณค่านั้นจะถูกตัดออกหากอยู่นอกช่วงนั้น มิฉะนั้นหากอยู่ในช่วงดังกล่าวดูเหมือนว่าจะไม่มีผลกับตำแหน่งยกเว้นการทดสอบ Z
z= -2
กับจุดที่ สามเหลี่ยมมองไม่เห็นถ้าผมใช้glOrtho(.., 0.0f, -4.0f);
, หรือ..-1.0f, -3.0f)
..-3.0f, -1.0f)
เพื่อให้มองเห็นได้พารามิเตอร์ far จะต้องเป็น POSITIVE 2 ขึ้นไป ดูเหมือนจะไม่สำคัญว่าพารามิเตอร์ใกล้คืออะไร ใด ๆ เหล่านี้ทำงาน: ..0.0f, 2.0f)
, ..-1.0f, 2.0f)
, หรือ..-3.0f, 2.0f)
..0.0f, 1000.0f
ตัวอย่างที่รันได้น้อยที่สุด
glOrtho
: เกม 2 มิติวัตถุที่อยู่ใกล้และไกลมีขนาดเท่ากัน:
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
ทดสอบบน Ubuntu 18.10
สคีมา
Ortho: กล้องเป็นระนาบปริมาตรที่มองเห็นได้เป็นรูปสี่เหลี่ยมผืนผ้า:
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
เราเห็น ลบด้วยSchema:
วิธีการทำงานภายใต้ประทุน
ในท้ายที่สุด OpenGL จะ "ใช้" เสมอ:
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
ถ้าเราใช้ค่าglOrtho
มิได้glFrustrum
ว่าเป็นสิ่งที่เราได้รับ
glOrtho
และglFrustrum
เป็นเพียงการแปลงเชิงเส้น (การคูณเมทริกซ์ AKA) เช่นนั้น:
glOrtho
: นำสี่เหลี่ยมผืนผ้า 3 มิติที่กำหนดมาไว้ในคิวบ์เริ่มต้นglFrustrum
: นำส่วนปิรามิดที่กำหนดมาไว้ในคิวบ์เริ่มต้นจากนั้นการเปลี่ยนแปลงนี้จะถูกนำไปใช้กับจุดยอดทั้งหมด นี่คือสิ่งที่ฉันหมายถึงใน 2D:
ขั้นตอนสุดท้ายหลังการเปลี่ยนแปลงนั้นง่ายมาก:
x
, y
และz
อยู่ใน[-1, +1]
z
ส่วนประกอบและรับเฉพาะx
และy
ซึ่งตอนนี้สามารถใส่ลงในหน้าจอ 2D ได้ด้วยglOrtho
, จะถูกละเว้นดังนั้นคุณอาจรวมทั้งการใช้งานเสมอz
0
เหตุผลหนึ่งที่คุณอาจต้องการใช้z != 0
คือทำให้สไปรต์ซ่อนพื้นหลังด้วยบัฟเฟอร์ความลึก
การเลิกใช้งาน
glOrtho
เลิกใช้แล้วเมื่อOpenGL 4.5 : โปรไฟล์ความเข้ากันได้ 12.1 "FIXED-FUNCTION VERTEX TRANSFORMATIONS" เป็นสีแดง
ดังนั้นอย่าใช้เพื่อการผลิต ไม่ว่าในกรณีใดการทำความเข้าใจเป็นวิธีที่ดีในการรับข้อมูลเชิงลึกของ OpenGL
โปรแกรม OpenGL 4 สมัยใหม่จะคำนวณเมทริกซ์การแปลง (ซึ่งมีขนาดเล็ก) บน CPU จากนั้นให้เมทริกซ์และจุดทั้งหมดที่จะเปลี่ยนเป็น OpenGL ซึ่งสามารถทำการคูณเมทริกซ์หลายพันรายการสำหรับจุดต่างๆได้อย่างรวดเร็วแบบขนาน
เฉดสีจุดยอดที่เขียนด้วยตนเองจากนั้นทำการคูณอย่างชัดเจนโดยปกติจะใช้ชนิดข้อมูลเวกเตอร์ที่สะดวกของ OpenGL Shading Language
เนื่องจากคุณเขียน shader อย่างชัดเจนจึงช่วยให้คุณปรับแต่งอัลกอริทึมตามความต้องการของคุณได้ ความยืดหยุ่นดังกล่าวเป็นคุณสมบัติหลักของ 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
ตามที่กล่าวไว้ในOpenGL 2 เอกสาร
glFrustum
เมทริกซ์ไม่ยากเกินไปที่จะคำนวณด้วยมือทั้ง แต่เริ่มจะน่ารำคาญ โปรดทราบว่าไม่สามารถสร้างความผิดหวังด้วยการปรับขนาดและการแปลเท่านั้นเช่นglOrtho
ข้อมูลเพิ่มเติมได้ที่: https://gamedev.stackexchange.com/a/118848/25171
ไลบรารีคณิตศาสตร์ GLM OpenGL C ++ เป็นตัวเลือกยอดนิยมสำหรับการคำนวณเมทริกซ์ดังกล่าว http://glm.g-truc.net/0.9.2/api/a00245.htmlเอกสารทั้ง an ortho
และfrustum
operation
common.h:19:23: error: ‘TIME_UTC’ undeclared (first use in this function) timespec_get(&ts, TIME_UTC);
glOrtho อธิบายการเปลี่ยนแปลงที่ก่อให้เกิดการฉายภาพคู่ขนาน เมทริกซ์ปัจจุบัน (ดู glMatrixMode) คูณด้วยเมทริกซ์นี้และผลลัพธ์จะแทนที่เมทริกซ์ปัจจุบันราวกับว่า glMultMatrix ถูกเรียกด้วยเมทริกซ์ต่อไปนี้เป็นอาร์กิวเมนต์:
เอกสาร OpenGL (ตัวหนาของฉัน)
ตัวเลขกำหนดตำแหน่งของระนาบการตัด (ซ้ายขวาล่างบนสุดใกล้และไกล)
การฉายภาพ "ปกติ" คือการฉายภาพมุมมองที่ให้ภาพลวงตาของความลึก Wikipediaให้คำจำกัดความของการฉายภาพคู่ขนานว่า:
เส้นโครงร่างขนานมีเส้นฉายที่ขนานกันทั้งในความเป็นจริงและในระนาบการฉาย
การฉายภาพคู่ขนานสอดคล้องกับการฉายภาพมุมมองที่มีมุมมองสมมุติเช่นจุดที่กล้องอยู่ห่างจากวัตถุเป็นระยะทางไม่สิ้นสุดและมีทางยาวโฟกัสไม่สิ้นสุดหรือ "ซูม"