link : http://www.opengl-tutorial.org/kr/beginners-tutorials/tutorial-6-keyboard-and-mouse/
벌써 6번째 튜토리얼! 이번에는 마우스와 키보드를 사용해서 카메라를 움직이는 방법을 배운다고 한다.
The Interface
이 코드는 튜토리얼 전체에서 다시 사용되므로 common/controls.cpp 라는 별도의 파일에 코드를 추가하고,
controls.hpp를 선언해 사용하라고 한다. (사실 이전에 쓰던 shader와 texture도 따로 선언해야하는데 안 했었다)
나는 튜토리얼만 할 것임으로 한 코드에 넣을 것이다. (이렇게 해야지 초보자 분들도 따라하기 쉬울거 같아서)
do{
// ...
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// ...
}
이 코드는 3가지 새로운 기능이 필요하다
1) computerMatricesFromInputs()는 키보드와 마우스를 읽고 Projection과 View 매트릭스들을 계산한다.
2) getProjectionMatrix()는 계산된 Projection행렬을 반환한다.
3) getViewMatrix()는 계산된 View행렬을 반환한다.
이 것은 여러가지 방법 중 하나일 뿐이므로 마음에 들지 않으면 변경해도 된다고 한다.
The actual code
우리는 몇 가지 변수가 필요하다.
// position
glm::vec3 position = glm::vec3( 0, 0, 5 );
// horizontal angle : toward -Z
float horizontalAngle = 3.14f;
// vertical angle : 0, look at the horizon
float verticalAngle = 0.0f;
// Initial Field of View
float initialFoV = 45.0f;
float speed = 3.0f; // 3 units / second
float mouseSpeed = 0.005f;
FoV는 확대/축소 수준을 뜻한다. (80° = 매우 넓은 각도, 거대한 변형,, 60°~45° : 표준,, 20° : 큰 확대)
입력에 따라 position, horizontalAngle, verticalAngle 및 FoV를 다시 계산 한 다음 position, horizontalAngle, verticalAngle 및
FoV에서 View 및 Projection 행렬을 계산한다.
Orientation
마우스 위치 읽기는 쉽다.
// Get mouse position
int xpos, ypos;
glfwGetMousePos(&xpos, &ypos);
커서를 화면의 중앙으로 되돌려 놓아야한다. 그렇지 않으면 곧 창 밖으로 나가서 더 이상 움직일 수 없게 된다.
// Reset mouse position for next frame
glfwSetMousePos(1024/2, 768/2);
이 코드는 윈도우가 1024*768이라고 가정한다.
// Compute new orientation
horizontalAngle += mouseSpeed * deltaTime * float(1024/2 - xpos );
verticalAngle += mouseSpeed * deltaTime * float( 768/2 - ypos );
이제 우리의 시야각을 계산할 수 있다.
// Compute new orientation
horizontalAngle += mouseSpeed * deltaTime * float(1024/2 - xpos );
verticalAngle += mouseSpeed * deltaTime * float( 768/2 - ypos );
1) 1024/2 - xpos는 마우스 중앙에서 마우스까지의 거리를 의미한다. 이 값이 클스록 더 많이 돌린다는 것이다.
2) float(...)은 곱셈이 잘 되도록 부동 소수점 수로 변환한다.
3) mouseSpeed는 회전 속도를 높이거나 낮추기 위한 것이다.
이 기능을 원하는대로 미세 조정하거나 사용자가 선택할 수 있도록해라.
4) += : 마우스를 움직이지 않으면 1024/2-xpos는 0이 되고 horizontalAngle += 0은 horizontalAngle을 변경하지 않는다.
대신 "="기호를 사용하면 각 프레임의 원래 방향으로 되돌아 가게 된다. (이는 좋지 않다)
이제 World Space에서 우리가 보고 있는 방향을 나타내는 벡터를 계산할 수 있다.
// Direction : Spherical coordinates to Cartesian coordinates conversion
glm::vec3 direction(
cos(verticalAngle) * sin(horizontalAngle),
sin(verticalAngle),
cos(verticalAngle) * cos(horizontalAngle)
);
이것은 표준 계산이지만 cosine과 sinus에 대해 잘 모르는 경우 간단한 설명을 하겠다.
이제 "up" vector에 대해 안정적인 계산을 하려고 한다. 그 전에 "up" vector가 항상 +Y 방향으로 향하는 것이 아님을 알아야한다.
만약 너가 아래쪽을 본다면, "up" vector는 수평이 될 것이다. 다음 사진을 참조해라.
우리의 경우에는 유일한 constant는 카메라의 오른쪽으로가는 벡터가 항상 수평이라는 것이다.
팔을 수평으로 놓고 어떤 방향으로든 아래를 올려다 보면서 이것을 확인할 수 있다.
"right" vector를 정의해보자. Y 좌표는 수평이므로 0이고, X 및 Z 좌표는 위의 그림과 같지만 각도는 90° 또는 Pi/2 라디안으로 회전한다.
// Right vector
glm::vec3 right = glm::vec3(
sin(horizontalAngle - 3.14f/2.0f),
0,
cos(horizontalAngle - 3.14f/2.0f)
);
"right"vector와 "direction", 또는 "front" vector를 가지고 있다. "up" vector는 이 둘에 수직인 벡터이다.
유용한 수학 도구를 사용하면 이 작업을 매우 간단하게 처리할 수 있다.
// Up vector : perpendicular to both direction and right
glm::vec3 up = glm::cross( right, direction );
Position
// Move forward
if (glfwGetKey( GLFW_KEY_UP ) == GLFW_PRESS){
position += direction * deltaTime * speed;
}
// Move backward
if (glfwGetKey( GLFW_KEY_DOWN ) == GLFW_PRESS){
position -= direction * deltaTime * speed;
}
// Strafe right
if (glfwGetKey( GLFW_KEY_RIGHT ) == GLFW_PRESS){
position += right * deltaTime * speed;
}
// Strafe left
if (glfwGetKey( GLFW_KEY_LEFT ) == GLFW_PRESS){
position -= right * deltaTime * speed;
}
여기서 잘 봐야할 것은 deltaTime이다. 컴퓨터 속도에 따라 달라지지 않도록 하기 위해 deltaTime을 곱해준다.
double currentTime = glfwGetTime();
float deltaTime = float(currentTime - lastTime);
Field Of View
마우스 휠을 Field of View에 바인딩해 확대/축소할 수 있다.
float FoV = initialFoV - 5 * glfwGetMouseWheel();
Computing the matrices
// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
ProjectionMatrix = glm::perspective(glm::radians(FoV), 4.0f / 3.0f, 0.1f, 100.0f);
// Camera matrix
ViewMatrix = glm::lookAt(
position, // Camera is here
position+direction, // and looks here : at the same position, plus "direction"
up // Head is up (set to 0,-1,0 to look upside-down)
);
마우스와 키보드로 움직이는거 뿐인데도 많은 과정이 필요했다. 어렵지는 않았으니 나중에 프로젝트를 진행할 때 한 번 더 보도록 하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | #include <stdio.h> #include <stdlib.h> #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <GL/glew.h> #include <glfw3.h> GLFWwindow* window; #include <glm/glm.hpp> #include <glm/gtx/transform.hpp> using namespace glm; #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII GLuint LoadShaders(const char *, const char *); GLuint loadBMP_custom(const char *); GLuint loadDDS(const char *); //mouse-keyboard input void computeMatricesFromInputs(); glm::mat4 getViewMatrix(); glm::mat4 getProjectionMatrix(); glm::mat4 ViewMatrix; glm::mat4 ProjectionMatrix; glm::mat4 getViewMatrix() { return ViewMatrix; } glm::mat4 getProjectionMatrix() { return ProjectionMatrix; } //포지션 초기화 glm::vec3 position = glm::vec3(0, 0, 5); float horizontalAngle = 3.14f; float verticalAngle = 0.0f; float initialFoV = 45.0f; float speed = 3.0f; float mouseSpeed = 0.005f; int main() { // Initialise GLFW if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW\n"); getchar(); return -1; } glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Open a window and create its OpenGL context window = glfwCreateWindow(1024, 768, "QBOT_opengl", NULL, NULL); if (window == NULL) { fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n"); getchar(); glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // Initialize GLEW glewExperimental = true; if (glewInit() != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW\n"); getchar(); glfwTerminate(); return -1; } // Ensure we can capture the escape key being pressed below glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set the mouse at the center of the screen glfwPollEvents(); glfwSetCursorPos(window, 1024 / 2, 768 / 2); // Dark blue background glClearColor(0.0f, 0.0f, 0.4f, 0.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); //Shader를 불러온다. GLuint programID = LoadShaders("TransformVertexShader.vertexshader", "TextureFragmentShader.fragmentshader"); //매트릭스ID 추가 GLuint MatrixID = glGetUniformLocation(programID, "MVP"); //어떠한 두 가지의 함수를 사용해서 텍스처를 불러온다 //GLuint Texture = loadBMP_custom("uvtemplate.bmp"); GLuint Texture = loadDDS("uvtemplate.DDS"); GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler"); //vertex 데이터 static const GLfloat g_vertex_buffer_data[] = { -1.0f,-1.0f,-1.0f, -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f,-1.0f, 1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, 1.0f,-1.0f, 1.0f, -1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f, 1.0f, -1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f }; // color 데이터 static const GLfloat g_uv_buffer_data[] = { 0.000059f, 0.000004f, 0.000103f, 0.336048f, 0.335973f, 0.335903f, 1.000023f, 0.000013f, 0.667979f, 0.335851f, 0.999958f, 0.336064f, 0.667979f, 0.335851f, 0.336024f, 0.671877f, 0.667969f, 0.671889f, 1.000023f, 0.000013f, 0.668104f, 0.000013f, 0.667979f, 0.335851f, 0.000059f, 0.000004f, 0.335973f, 0.335903f, 0.336098f, 0.000071f, 0.667979f, 0.335851f, 0.335973f, 0.335903f, 0.336024f, 0.671877f, 1.000004f, 0.671847f, 0.999958f, 0.336064f, 0.667979f, 0.335851f, 0.668104f, 0.000013f, 0.335973f, 0.335903f, 0.667979f, 0.335851f, 0.335973f, 0.335903f, 0.668104f, 0.000013f, 0.336098f, 0.000071f, 0.000103f, 0.336048f, 0.000004f, 0.671870f, 0.336024f, 0.671877f, 0.000103f, 0.336048f, 0.336024f, 0.671877f, 0.335973f, 0.335903f, 0.667969f, 0.671889f, 1.000004f, 0.671847f, 0.667979f, 0.335851f }; GLuint vertexbuffer; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); GLuint uvbuffer; glGenBuffers(1, &uvbuffer); glBindBuffer(GL_ARRAY_BUFFER, uvbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_uv_buffer_data), g_uv_buffer_data, GL_STATIC_DRAW); do { // Clear the screen. It's not mentioned before Tutorial 02, but it can cause flickering, so it's there nonetheless. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(programID); //키보드와 마우스 인풋으로부터의 MVP 매트릭스를 계산한다 computeMatricesFromInputs(); glm::mat4 ProjectionMatrix = getProjectionMatrix(); glm::mat4 ViewMatrix = getViewMatrix(); glm::mat4 ModelMatrix = glm::mat4(1.0); glm::mat4 MVP = ProjectionMatrix*ViewMatrix*ModelMatrix; //transformation을 현재 쉐이더에 보냄 glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); //텍스처 유닛0에 있는 텍스처를 바인딩한다. glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, Texture); //"myTextureSampler" 셈플러를 유저 텍스처 유닛 0에 세팅한다. glUniform1i(TextureID, 0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, //0번째 속성. 0이 될 특별한 이유는 없지만 쉐이더의 레이아웃과 반드시 맞춰야함 3, //크기(size) GL_FLOAT, //타입(type) GL_FALSE, //정규화(normalized)? 0, //다음 요소까지의 간격(stride) (void*)0 //배열 버퍼의 오프셋(offset) ); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, uvbuffer); glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 ); glDrawArrays(GL_TRIANGLES, 0, 12 * 3); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); // Swap buffers glfwSwapBuffers(window); glfwPollEvents(); } // Check if the ESC key was pressed or the window was closed while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0); // Cleanup VBO glDeleteBuffers(1, &vertexbuffer); glDeleteBuffers(1, &uvbuffer); glDeleteProgram(programID); glDeleteTextures(1, &TextureID); glDeleteVertexArrays(1, &VertexArrayID); // Close OpenGL window and terminate GLFW glfwTerminate(); return 0; } GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path) { //쉐이더 생성 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); //버텍스 쉐이더 코드를 파일에서 읽기 std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } else { printf("파일 %s를 읽을 수 없음. 정확한 디렉토리를 사용 중입니까?\n", vertex_file_path); getchar(); return 0; } //프래그먼트 쉐이더 코드를 파일에서 읽기 std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } GLint Result = GL_FALSE; int InfoLogLength; //버텍스 쉐이더를 컴파일 printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //버텍스 쉐이더를 검사 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (InfoLogLength > 0) { std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); printf("%s\n", &VertexShaderErrorMessage[0]); } //프래그먼트 쉐이더를 컴파일 printf("Compiling shader : %s", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); //프래그먼트 쉐이더를 검사 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (InfoLogLength > 0) { std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); printf("%s\n", &FragmentShaderErrorMessage[0]); } //프로그램에 링크 printf("Linking program\n"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); //프로그램 검사 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (InfoLogLength > 0) { std::vector<char> ProgramErrorMessage(InfoLogLength + 1); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); printf("%s\n", &ProgramErrorMessage[0]); } glDetachShader(ProgramID, VertexShaderID); glDetachShader(ProgramID, FragmentShaderID); glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); return ProgramID; } GLuint loadBMP_custom(const char * imagepath) { printf("Reading image %s\n", imagepath); //BMP파일의 헤더에서 데이터를 읽는다 unsigned char header[54]; unsigned int dataPos; unsigned int imageSize; unsigned int width, height; //실제 RGB 데이터 unsigned char * data; //파일을 연다 FILE * file = fopen(imagepath, "rb"); if (!file) { printf("%s는 열수 없다. 경로가 맞는지 확인해라.\n", imagepath); getchar(); return 0; } //헤더를 읽는다, i.e. the 54 first bytes //만약 54 bytes보다 적게 읽혔으면 문제 발생 if (fread(header, 1, 54, file) != 54) { printf("BMP 파일이 아니다\n"); return 0; } //A BMP 파일은 항상 "BM"으로 시작한다. if (header[0] != 'B' || header[1] != 'M') { printf("BMP 파일이 아니다\n"); return 0; } //24pp file임을 확인한다. if (*(int*)&(header[0x1e]) != 0 || *(int*)&(header[0x1C]) != 24) { printf("BMP 파일이 아니다\n"); return 0; } //이미지에 대한 정보를 읽는다. dataPos = *(int*)&(header[0x0A]); imageSize = *(int*)&(header[0x22]); width = *(int*)&(header[0x12]); height = *(int*)&(header[0x16]); //몇몇 BMP 파일들은 포맷이 놓쳐졌다, 놓쳐진 정보를 추측해라 if (imageSize == 0) imageSize = width*height * 3; // 3 : one byte for each Red-Green-Blue component if (dataPos == 0) dataPos = 54; //BMP 헤더는 항상 이 형식 //버퍼를 생성한다 data = new unsigned char[imageSize]; //파일의 버퍼에 있는 실제 데이터를 읽는다 fread(data, 1, imageSize, file); //모든 것은 현재 메모리에 있다, 파일을 닫는다 fclose(file); //openGL 텍스처를 만든다 GLuint textureID; glGenTextures(1, &textureID); //새로이 만들어진 텍스처를 바인딩한다. glBindTexture(GL_TEXTURE_2D, textureID); //이미지를 OpenGL에게 넘긴다 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); delete[] data; // trilinear(삼선형) 필터링 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glGenerateMipmap(GL_TEXTURE_2D); return textureID; } GLuint loadDDS(const char * imagepath) { unsigned char header[124]; FILE *fp; //파일을 연다 fp = fopen(imagepath, "rb"); if (fp == NULL) { printf("%s는 열 수 없다. 경로를 확인해라\n", imagepath); getchar(); return 0; } //파일의 타입을 확인한다 char filecode[4]; fread(filecode, 1, 4, fp); if (strncmp(filecode, "DDS ", 4) != 0) { fclose(fp); return 0; } //surface desc를 얻는다 fread(&header, 124, 1, fp); unsigned int height = *(unsigned int*)&(header[8]); unsigned int width = *(unsigned int*)&(header[12]); unsigned int linearSize = *(unsigned int*)&(header[16]); unsigned int mipMapCount = *(unsigned int*)&(header[24]); unsigned int fourCC = *(unsigned int*)&(header[80]); unsigned char * buffer; unsigned int bufsize; bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize; buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); fread(buffer, 1, bufsize, fp); fclose(fp); unsigned int components = (fourCC == FOURCC_DXT1) ? 3 : 4; unsigned int format; switch (fourCC) { case FOURCC_DXT1: format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case FOURCC_DXT3: format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: free(buffer); return 0; } //하나의 OpenGL 텍스처를 생성한다 GLuint textureID; glGenTextures(1, &textureID); //새로이 만들어진 텍스처를 바인딩한다 glBindTexture(GL_TEXTURE_2D, textureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; unsigned int offset = 0; //밉맵을 불러온다 for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) { unsigned int size = ((width + 3) / 4)*((height + 3) / 4)*blockSize; glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, buffer + offset); offset += size; width /= 2; height /= 2; //Non-Power-Of-Two 텍스처를 사용합니다. //이 코드는 혼란을 줄이기 위해 웹 페이지에는 포함되어 있지 않습니다. if (width < 1)width = 1; if (height < 1) height = 1; } free(buffer); return textureID; } void computeMatricesFromInputs() { //glfwGetTime은 한번만 호출된다. static double lastTime = glfwGetTime(); //현재와 마지막 프레임의 시간 차를 계산한다. double currentTime = glfwGetTime(); float deltaTime = float(currentTime - lastTime); //마우스의 위치를 얻는다. double xpos, ypos; glfwGetCursorPos(window, &xpos, &ypos); //다음 프레임의 마우스 위치를 리셋한다. glfwSetCursorPos(window, 1024 / 2, 768 / 2); horizontalAngle += mouseSpeed * float(1024 / 2 - xpos); verticalAngle += mouseSpeed * float(768 / 2 - ypos); //Direction : Spherical 좌표 to Cartesian 좌표 변환 glm::vec3 direction( cos(verticalAngle)*sin(horizontalAngle), sin(verticalAngle), cos(verticalAngle)*cos(horizontalAngle) ); //Right vector glm::vec3 right = glm::vec3( sin(horizontalAngle - 3.14f / 2.0f), 0, cos(horizontalAngle - 3.14f / 2.0f) ); //Up vector glm::vec3 up = glm::cross(right, direction); //앞으로 이동 if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { position += direction*deltaTime*speed; } //뒤로 이동 if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { position -= direction*deltaTime*speed; } //오른쪽로 Strafe if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { position += right*deltaTime*speed; } //왼쪽으로 Strafe if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { position -= right*deltaTime*speed; } float FoV = initialFoV; ProjectionMatrix = glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 100.0f); ViewMatrix = glm::lookAt( position, //camera here position + direction, //and looks here up // Head is up ); //다음 프레임을 위해 lastTime = currentTime; } | cs |
'Game > Graphics' 카테고리의 다른 글
OpenGL-Tutorial 8 : Basic shading (0) | 2018.06.26 |
---|---|
OpenGL-Tutorial 7 : Model loading (0) | 2018.06.22 |
OpenGL-Tutorial 5 : A Textured Cube (0) | 2018.06.20 |
OpenGL-Tutorial 4 : 색깔이 입혀진 육면체 (0) | 2018.06.20 |
OpenGL-Tutorial 3 : 행렬(매트릭스) (0) | 2018.06.20 |