Advertisement
Guest User

main.cpp

a guest
Jan 19th, 2020
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.80 KB | None | 0 0
  1. // OpenGL example application, that renders a bunch of trees via instancing.
  2.  
  3. #include "core.hpp"
  4. #include <simplex_noise.hpp>
  5.  
  6. #include "glm/glm.hpp"
  7. #include "glm/gtc/matrix_transform.hpp"
  8. #include "glm/gtc/type_ptr.hpp"
  9.  
  10. #include "lodepng/lodepng.h"
  11.  
  12. #include <array>
  13. #include <chrono>
  14. #include <iostream>
  15. #include <random>
  16. #include <thread>
  17.  
  18. /// Layout of the per-object data submitted to the graphics device.
  19. struct PerObject
  20. {
  21. glm::mat4 model; // object coords -> world coords
  22. };
  23.  
  24. /// Combination of a vertex array object and an index buffer object.
  25. struct RenderBatch {
  26. GLuint vao; // vertex array object
  27. GLuint ibo; // index buffer object
  28. int32_t index_count;
  29. PerObject per_object;
  30. };
  31.  
  32. /// Layout of the vertices, used to store them in vertex buffer objects.
  33. struct Vertex
  34. {
  35. glm::vec3 pos;
  36. glm::vec4 color;
  37. glm::vec3 normal;
  38. };
  39.  
  40. /// Layout of the per-frame data submitted to the graphics device.
  41. struct PerFrame
  42. {
  43. glm::mat4 view; // world coords -> clip coords
  44. glm::mat4 proj;
  45. glm::vec4 light_dir;
  46. };
  47.  
  48. RenderBatch CreateRenderBatch(const std::vector<Vertex>& vertices,
  49. const std::vector<uint32_t>& indices,
  50. const glm::mat4& model = glm::mat4{ 1 });
  51.  
  52. GLuint CreateSpriteTexture(std::string const& filename);
  53.  
  54. void InitRenderer();
  55. void InitScene();
  56. void UpdateShaders();
  57. int KeyAxisValue(GLFWwindow* window, int key1, int key2);
  58. void applyJoystickInput();
  59. bool NeedSceneUpdate();
  60. void UpdateScene();
  61. void RenderFrame();
  62. void RenderObject(const RenderBatch& batch);
  63. void FramebufferSizeCallback(GLFWwindow* window, int width, int height);
  64. void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
  65.  
  66. RenderBatch CreateGround(glm::vec4 color, bool flat = false, float height = 0.f);
  67. float GetGroundHeight(glm::ivec2 coords);
  68. glm::vec3 GetGroundNormal(glm::ivec2 coords);
  69.  
  70. GLFWwindow* g_window;
  71. int g_window_width = 960, g_window_height = 540;
  72.  
  73. GLuint g_shader_program_ground = 0; // shader program for rendering the ground
  74. GLuint g_shader_program_tree_imposter = 0; // shader program for rendering the tree imposters
  75.  
  76. RenderBatch g_render_batch_ground; // geometry of the ground
  77. RenderBatch g_render_batch_water; // geometry of the water
  78.  
  79. RenderBatch g_render_batch_tree_imposter; // geometry of a tree imposter
  80.  
  81. GLuint g_texture_name_tree_sprite; // texture for the tree imposters
  82.  
  83. GLuint g_ubo_per_frame; // uniform buffer containing per-frame data
  84. GLuint g_ubo_per_object;
  85. GLuint g_ubo_trees; // uniform buffer containing per-object data for all trees
  86. const int g_ground_extent = 512;
  87. const float g_ground_y_scale = 30.0f;
  88.  
  89. PerFrame g_per_frame; // local copy of the per-frame uniform buffer
  90.  
  91. glm::vec3 g_cam_pos{ -8, 5, 12 }; // camera position
  92. glm::vec3 g_cam_velocity{ 0, 0, 0 }; // change of g_cam_pos per tick
  93. float g_cam_yaw = -0.85f; // camera left-right orientation in [-pi, pi]
  94. float g_diff_cam_yaw = 0.f; // change of g_cam_yaw per tick
  95. float g_cam_pitch = -0.12f; // camera up down orientation in [-1.5, 1.5]
  96. float g_diff_cam_pitch = 0.f; // change of g_cam_pitch per tick
  97.  
  98. constexpr int numTrees = 1024; // number of trees to render
  99.  
  100. float g_light_yaw = 0.02f; // light horizontal orientation in [-pi, pi]
  101.  
  102. /// Entry point into the OpenGL example application.
  103. int main() {
  104. try {
  105. // initialize glfw
  106. GlfwInstance::init();
  107.  
  108. // initialize this application
  109. InitRenderer();
  110. InitScene();
  111.  
  112. // render until the window should close
  113. while (!glfwWindowShouldClose(g_window)) {
  114. glfwPollEvents(); // handle events
  115. while (NeedSceneUpdate())
  116. UpdateScene(); // per-tick updates
  117. RenderFrame(); // render image
  118. glfwSwapBuffers(g_window); // present image
  119. }
  120. }
  121. catch (const std::exception & e) {
  122. std::cerr << e.what() << "\nPress enter.\n";
  123. getchar();
  124. return -1;
  125. }
  126. }
  127.  
  128. /// Creates the window and sets persistent render settings and compiles shaders.
  129. /// @throw std::runtime_error If an error occurs during intialization.
  130. void InitRenderer() {
  131. // create window
  132. g_window = glfwCreateWindow(g_window_width, g_window_height, // initial resolution
  133. "Terrain", // window title
  134. nullptr, nullptr);
  135. if (!g_window)
  136. throw std::runtime_error("Failed to create window.");
  137.  
  138. // use the window that was just created
  139. glfwMakeContextCurrent(g_window);
  140.  
  141. // get window resolution
  142. glfwGetFramebufferSize(g_window, &g_window_width, &g_window_height);
  143.  
  144. // set callbacks for when the resolution changes or a key is pressed
  145. glfwSetFramebufferSizeCallback(g_window, &FramebufferSizeCallback);
  146. glfwSetKeyCallback(g_window, &KeyCallback);
  147.  
  148. // enable vsync
  149. glfwSwapInterval(1);
  150.  
  151. // load OpenGL (return value of 0 indicates error)
  152. if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
  153. throw std::runtime_error("Failed to load OpenGL context.");
  154. std::cout << "OpenGL " << glGetString(GL_VERSION) << '\n';
  155. std::cout << "GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION) << '\n';
  156.  
  157. // enable depth buffering
  158. glEnable(GL_DEPTH_TEST);
  159.  
  160. // enable simple blending
  161. glEnable(GL_BLEND);
  162. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  163.  
  164. // create shader programs
  165. UpdateShaders();
  166.  
  167. // create per-frame uniform buffer (will be filled later, once per frame)
  168. glGenBuffers(1, &g_ubo_per_frame);
  169. glBindBuffer(GL_UNIFORM_BUFFER, g_ubo_per_frame);
  170. glBufferData(GL_UNIFORM_BUFFER, sizeof(PerFrame), nullptr, GL_DYNAMIC_DRAW);
  171. glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_ubo_per_frame); // binding 0
  172. glBindBuffer(GL_UNIFORM_BUFFER, 0);
  173.  
  174. // create the per-object uniform buffer (will be filled later, once per rendering an object)
  175. glGenBuffers(1, &g_ubo_per_object);
  176. glBindBuffer(GL_UNIFORM_BUFFER, g_ubo_per_object);
  177. glBufferData(GL_UNIFORM_BUFFER, sizeof(PerObject), nullptr, GL_DYNAMIC_DRAW);
  178. glBindBufferBase(GL_UNIFORM_BUFFER, 1, g_ubo_per_object); // binding 1
  179. glBindBuffer(GL_UNIFORM_BUFFER, 0);
  180. }
  181.  
  182. /// Creates geometry and uniform buffers.
  183. void InitScene()
  184. {
  185. // create ground geometry: each vertex consists of a position and a color
  186. float height = 1.0f;
  187. g_render_batch_ground = CreateGround(glm::vec4{ 0.3f, 0.3f, 0.3f, 1.f });
  188. g_render_batch_water = CreateGround(glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, true, height);
  189.  
  190. g_per_frame.light_dir = glm::vec4(2.0f, 0.0f, 2.0f, 0.0f);
  191.  
  192. // create tree sprite geometry: a quad in the range [-1.5 , 1.5] x [0.0 3.0]
  193. // and with texture coordinates in the range [0,1] x [1,0]
  194. // use the color attribute of the vertices to store the texture coordinates (simply set the
  195. // third entry to 0)
  196. std::vector<Vertex> tree_sprite_vertices{ {{-1.5f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 1.f}},
  197. {{-1.5f, 3.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.f}},
  198. {{1.5f, 3.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.f}},
  199. {{1.5f, 0.0f, 0.0f}, {1.0f, 1.0f, 0.0f, 1.f}} };
  200. std::vector<uint32_t> tree_sprite_indices{ 0, 1, 2, 0, 2, 3 };
  201. g_render_batch_tree_imposter = CreateRenderBatch(tree_sprite_vertices, tree_sprite_indices);
  202.  
  203. // create tree sprite texture
  204. g_texture_name_tree_sprite = CreateSpriteTexture("../resources/pine_tree_sprite.png");
  205.  
  206.  
  207. /*
  208. * TODO: Aufgabe 3 Teilaufgabe 3: Berechnen Sie hier die positionen der Bäume und die
  209. * Model-Matrizen. Achten sie darauf das die Bäume nicht in Seen stehen und nutzen Sie
  210. * GetGroundHeight um die Höhe an der Position zu bestimmen.
  211. * Erstellen und füllen Sie dann den Uniform Buffer der das PerObject struct als
  212. * Datenformat verwendet
  213. */
  214. }
  215.  
  216. /// @return The ground's geometry wrapped in a RenderBatch object.
  217. RenderBatch CreateGround(glm::vec4 color, bool flat, float height)
  218. {
  219. std::vector<Vertex> vertices;
  220. std::vector<uint32_t> indices;
  221.  
  222. /*
  223. * TODO: Aufgabe 1 Teilaufgabe 2 Mesh-Generierung: Füllen sie den Vertex und
  224. * Index buffer mit dem generierten Mesh. Die Gitterpunkte entsprechen den
  225. * ganzzahligen Koordinaten, die Hohe und Normale eines Gitterpunktes (x; z)
  226. * werden in den Funktionen GetGroundHeight bzw. GetGroundNormal berechnet.
  227. * Jeder Vertex soll Information zu seiner Position, Farbe und Normalen
  228. * enthalten.
  229. *
  230. * Hinweis: Im Vektor indices stehen immer drei aufeinanderfolgende Integerwerte
  231. * für ein Dreieck. Diese Integers reprasentieren die drei Indices der Vertices
  232. * im Vektor vertices, aus denen das entsprechende Dreieck gebildet werden soll.
  233. */
  234.  
  235.  
  236. /*
  237. * TODO: Aufgabe 3 Teilaufgabe 1: Nutzen Sie die Parameter flat und height um
  238. * ein Mesh zu erstellen das keine Höhenwerte der Funktion GetGroundHeight
  239. * verwendet.
  240. */
  241.  
  242.  
  243. if (flat) {
  244.  
  245. vertices.push_back({ {0, height, 0}, color, GetGroundNormal(glm::ivec2(0,0)) });
  246. vertices.push_back({ {g_ground_extent - 1, height+1, 0}, color, GetGroundNormal(glm::ivec2(0,0)) });
  247. vertices.push_back({ {0, height, g_ground_extent - 1}, color, GetGroundNormal(glm::ivec2(0,0)) });
  248. vertices.push_back({ {g_ground_extent - 1, height, g_ground_extent - 1},color, GetGroundNormal(glm::ivec2(0,0)) });
  249. indices.push_back(0);
  250. indices.push_back(1);
  251. indices.push_back(2);
  252. indices.push_back(1);
  253. indices.push_back(2);
  254. indices.push_back(3);
  255. }
  256. else
  257. {
  258. for (int z = 0; z < g_ground_extent; z++) {
  259. for (int x = 0; x < g_ground_extent; x++) {
  260. vertices.push_back({ {x, GetGroundHeight(glm::ivec2(x,z)), z},
  261. color,
  262. GetGroundNormal(glm::ivec2(x,z)) });
  263.  
  264. if (x < g_ground_extent - 1 && z < g_ground_extent - 1) {
  265. indices.push_back((z * g_ground_extent) + x);
  266. indices.push_back((z * g_ground_extent) + (x + 1));
  267. indices.push_back(((z + 1) * g_ground_extent) + x);
  268. indices.push_back(((z + 1) * g_ground_extent) + x);
  269. indices.push_back((z * g_ground_extent) + (x + 1));
  270. indices.push_back(((z + 1) * g_ground_extent) + (x + 1));
  271. }
  272. }
  273. }
  274. }
  275.  
  276.  
  277.  
  278.  
  279. //if (flat) {
  280. //
  281. //
  282. //
  283. // vertices.push_back({ {0, height, 0}, color, GetGroundNormal(glm::ivec2(0,0)) });
  284. // vertices.push_back({ {g_ground_extent - 1, height, 0}, color, GetGroundNormal(glm::ivec2(0,0)) });
  285. // vertices.push_back({ {0, height, g_ground_extent - 1}, color, GetGroundNormal(glm::ivec2(0,0)) });
  286. // vertices.push_back({ {g_ground_extent - 1, height, g_ground_extent - 1},color, GetGroundNormal(glm::ivec2(0,0)) });
  287. // indices.push_back(0);
  288. // indices.push_back(1);
  289. // indices.push_back(2);
  290. // indices.push_back(1);
  291. // indices.push_back(2);
  292. // indices.push_back(3);
  293. //}
  294.  
  295.  
  296.  
  297. //std::cout << indices.size();
  298. //std::cout << indices.at(offset);
  299. //std::cout << vertices[512*512 +2].pos.x;
  300. //vertices.push_back({ {0, height, 0}, glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  301. //vertices.push_back({ {511, height, 0}, glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  302. //vertices.push_back({ {0, height, 511}, glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  303. //vertices.push_back({ {0, height, 511}, glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  304. //vertices.push_back({ {511, height, 0}, glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  305. //vertices.push_back({ {511, height, 511},glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f }, GetGroundNormal(glm::ivec2(0,0)) });
  306. //
  307. //
  308. //indices.push_back(512*512 + 1);
  309. //indices.push_back(512*512 + 2);
  310. //indices.push_back(512*512 + 3);
  311. //indices.push_back(512*512 + 4);
  312. //indices.push_back(512*512 + 5);
  313. //indices.push_back(512*512 + 6);
  314.  
  315.  
  316. //int sizevertices = vertices.size();
  317. //
  318. //height += 1;
  319. //
  320. //vertices.push_back({ {0, height, 0},glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f },GetGroundNormal(glm::ivec2(0,0)) });
  321. //vertices.push_back({ {511, height, 0},glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f },GetGroundNormal(glm::ivec2(0,0)) });
  322. //vertices.push_back({ {0, height, 511},glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f },GetGroundNormal(glm::ivec2(0,0)) });
  323. //vertices.push_back({ {511, height, 511},glm::vec4{ 0.53f, 0.81f, 0.98f, 0.3f },GetGroundNormal(glm::ivec2(0,0)) });
  324. //indices.push_back(sizevertices + 0);
  325. //indices.push_back(sizevertices + 1);
  326. //indices.push_back(sizevertices + 2);
  327. //indices.push_back(sizevertices + 1);
  328. //indices.push_back(sizevertices + 2);
  329. //indices.push_back(sizevertices + 3);
  330.  
  331.  
  332. //indices.push_back(0);
  333. //indices.push_back(511);
  334. //indices.push_back(511*511-511);
  335.  
  336. //indices.push_back(1000);
  337. //indices.push_back(511);
  338. //indices.push_back(511*511);
  339.  
  340.  
  341.  
  342. //std::cout << indices.at(offset+1.f);
  343. //std::cout << vertices[512*512 +3].pos.x;
  344. //std::cout << vertices[3].pos.y;
  345. //std::cout << vertices[3].pos.z;
  346. //std::vector<uint32_t> indices_water;
  347. //std::cout << vertices;
  348. //at(512 * 512 *4)
  349.  
  350. //uint32_t offset = vertices.size();
  351. //if (flat)
  352. //{
  353. // for (int z = 0; z < g_ground_extent; z++) {
  354. // for (int x = 0; x < g_ground_extent; x++) {
  355. //
  356. // vertices.push_back({ {x, height, z},
  357. // color,
  358. // GetGroundNormal(glm::ivec2(x,z)) });
  359. //
  360. // if (x < g_ground_extent - 1 && z < g_ground_extent - 1) {
  361. // indices.push_back(((z * g_ground_extent) + x) + offset);
  362. // indices.push_back(((z * g_ground_extent) + (x + 1)) + offset);
  363. // indices.push_back((((z + 1) * g_ground_extent) + x) + offset);
  364. // indices.push_back((((z + 1) * g_ground_extent) + x) + offset);
  365. // indices.push_back(((z * g_ground_extent) + (x + 1)) + offset);
  366. // indices.push_back((((z + 1) * g_ground_extent) + (x + 1)) + offset);
  367. //
  368. // }
  369. // }
  370. // }
  371. //}
  372. //else
  373. //{
  374. // for (int z = 0; z < g_ground_extent; z++) {
  375. // for (int x = 0; x < g_ground_extent; x++) {
  376. //
  377. // vertices.push_back({ {x, 0, z},
  378. // color,
  379. // GetGroundNormal(glm::ivec2(x,z)) });
  380. //
  381. // if (x < g_ground_extent - 1 && z < g_ground_extent - 1) {
  382. // indices.push_back(((z * g_ground_extent) + x) + offset);
  383. // indices.push_back(((z * g_ground_extent) + (x + 1)) + offset);
  384. // indices.push_back((((z + 1) * g_ground_extent) + x) + offset);
  385. // indices.push_back((((z + 1) * g_ground_extent) + x) + offset);
  386. // indices.push_back(((z * g_ground_extent) + (x + 1)) + offset);
  387. // indices.push_back((((z + 1) * g_ground_extent) + (x + 1)) + offset);
  388. //
  389. // }
  390. // }
  391. // }
  392. //}
  393.  
  394.  
  395. //std::cout << indices_water.size();
  396. //for (int i = 0; i < g_ground_extent*g_ground_extent; i++)
  397. //{
  398. // indices.push_back(indices_water.at(i));
  399. //}
  400.  
  401.  
  402.  
  403.  
  404. glm::vec3 translation{ -g_ground_extent / 2.f, 0.01f, -g_ground_extent / 2.f };
  405. glm::mat4 transform = glm::translate(glm::mat4{ 1 }, translation);
  406. return CreateRenderBatch(vertices, indices, transform);
  407. }
  408.  
  409. /// @param coord Coordinates on the ground's grid.
  410. /// @return The disired height of the ground at that coordinate.
  411. /// @throws std::runtime_error if coord contains a negative value or a value above g_ground_extent.
  412. float GetGroundHeight(glm::ivec2 coord)
  413. {
  414. static std::vector<std::array<float, g_ground_extent>> height_map;
  415.  
  416. if (glm::clamp(coord, 0, g_ground_extent - 1) != coord)
  417. throw std::runtime_error("Index out of bounds.");
  418. if (height_map.empty())
  419. {
  420. height_map.resize(g_ground_extent);
  421.  
  422. for (int x = 0; x < g_ground_extent; ++x)
  423. {
  424. for (int y = 0; y < g_ground_extent; ++y)
  425. {
  426. float noise = simplex::fractal2D(0.0158229f, // frequency
  427. 2.0f, // lacunarity
  428. 0.4f, // persistence
  429. 5, // number of octaves
  430. static_cast<float>(x),
  431. static_cast<float>(y)); // coodinates
  432. noise = noise * 0.5f + 0.5f;
  433. noise *= noise;
  434. float hilliness = simplex::noise2D(0.011887f * x, 0.011887f * y);
  435. hilliness *= hilliness;
  436. hilliness = 1.0f - hilliness;
  437. hilliness *= hilliness;
  438. hilliness = 0.4f + 0.6f * hilliness;
  439. int dx = g_ground_extent / 2 - x;
  440. int dy = g_ground_extent / 2 - y;
  441. float plain = static_cast<float>(dx * dx + dy * dy);
  442. plain = std::min(plain / 400.f, 1.0f);
  443. plain = 1.0f - plain;
  444. plain *= plain;
  445. plain = 1.0f - plain;
  446. height_map[x][y] = g_ground_y_scale * noise * hilliness * plain;
  447. }
  448. }
  449. }
  450. return height_map[coord.x][coord.y];
  451. }
  452.  
  453. /// @param coords Coordinates on the ground's grid.
  454. /// @return The disired normal vector of the ground at that coordinate.
  455. /// @throws std::runtime_error if coord contains a negative value or a value above g_ground_extent.
  456. glm::vec3 GetGroundNormal(glm::ivec2 coords)
  457. {
  458. static std::vector<std::array<glm::vec3, g_ground_extent>> normal_map;
  459.  
  460. if (glm::clamp(coords, 0, g_ground_extent - 1) != coords)
  461. throw std::runtime_error("Index out of bounds (GetGroundNormal).");
  462.  
  463. if (normal_map.empty())
  464. {
  465. normal_map.resize(g_ground_extent);
  466.  
  467. for (int x = 0; x < g_ground_extent; ++x)
  468. {
  469. for (int z = 0; z < g_ground_extent; ++z)
  470. {
  471. normal_map[x][z] = glm::vec3(0.f, 1.f, 0.f);
  472.  
  473. /*
  474. * TODO: Aufgabe 1 Teilaufgabe 3 Normalen: Berechnen Sie die normale für
  475. * die Position (x,y).
  476. *
  477. * Hinweise: - Achten Sie auf Grenzfälle.
  478. * - Sollten Sie das Kreuzproduktes in Ihrer Berechnung verwenden,
  479. * achten Sie auf eine korrekte Orientierung der Vektoren.
  480. * - Zum schnellen Debuggen der Normalen bietet es sich an, die
  481. * Normale als Terrainfarbe zu ubergeben
  482. */
  483.  
  484. if (x > 0 && x < g_ground_extent - 1 && z > 0 && z < g_ground_extent - 1) {
  485.  
  486. float sizefactor = 1.0f / (8.0f * 0.96f);
  487.  
  488. float hnw = GetGroundHeight(glm::ivec2(x - 1, z - 1));
  489. float hn = GetGroundHeight(glm::ivec2(x, z - 1));
  490. float hne = GetGroundHeight(glm::ivec2(x + 1, z - 1));
  491. float he = GetGroundHeight(glm::ivec2(x + 1, z));
  492. float hse = GetGroundHeight(glm::ivec2(x + 1, z + 1));
  493. float hs = GetGroundHeight(glm::ivec2(x, z + 1));
  494. float hsw = GetGroundHeight(glm::ivec2(x - 1, z + 1));
  495. float hw = GetGroundHeight(glm::ivec2(x - 1, z));
  496.  
  497. float dydx = ((hne + 2 * he + hse) - (hnw + 2 * hw + hsw)) * sizefactor;
  498. float dydz = ((hsw + 2 * hs + hse) - (hnw + 2 * hn + hne)) * sizefactor;
  499.  
  500. normal_map[x][z] = glm::normalize(glm::vec3(-dydx, 1.0f, -dydz));
  501. }
  502. }
  503. }
  504. }
  505.  
  506. return normal_map[coords.x][coords.y];
  507. }
  508.  
  509. /// @param vertices A vertex buffer.
  510. /// @param out_indices An index buffer.
  511. /// @return RenderBatch object created using the given buffers.
  512. RenderBatch CreateRenderBatch(const std::vector<Vertex>& vertices,
  513. const std::vector<uint32_t>& indices, const glm::mat4& model)
  514. {
  515. RenderBatch batch;
  516. batch.per_object.model = model;
  517. batch.index_count = static_cast<int32_t>(indices.size());
  518.  
  519. // create & fill index buffer object
  520. glGenBuffers(1, &batch.ibo);
  521. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.ibo);
  522. glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  523. sizeof(uint32_t) * indices.size(), // data size
  524. indices.data(), // data pointer
  525. GL_STATIC_DRAW); // usage
  526. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  527.  
  528. // create vertex array object
  529. glGenVertexArrays(1, &batch.vao);
  530. glBindVertexArray(batch.vao);
  531.  
  532. // create & fill vertex buffer object
  533. GLuint vbo;
  534. glGenBuffers(1, &vbo);
  535. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  536. glBufferData(GL_ARRAY_BUFFER,
  537. sizeof(Vertex) * vertices.size(), // data size
  538. vertices.data(), // data pointer
  539. GL_STATIC_DRAW); // usage
  540.  
  541. // specify & enable position attribute (the data is taken from the currently bound vbo)
  542. glEnableVertexAttribArray(0);
  543. glVertexAttribPointer(
  544. 0, // index of the attribute
  545. 3, GL_FLOAT, // a position consists of 3 floats
  546. GL_FALSE,
  547. sizeof(Vertex), // stride between consecutive vertices in the buffer
  548. reinterpret_cast<const void*>(offsetof(Vertex, pos))); // offset of this attribute
  549.  
  550. // specify & enable color attribute (the data is taken from the currently bound vbo)
  551. glEnableVertexAttribArray(1);
  552. glVertexAttribPointer(
  553. 1, // index of the attribute
  554. 4, GL_FLOAT, // a color consists of 4 floats
  555. GL_FALSE,
  556. sizeof(Vertex), // stride between consecutive colors in the buffer
  557. reinterpret_cast<const void*>(offsetof(Vertex, color))); // offset of this attribute
  558.  
  559. // specify & enable normal attribute (the data is taken from the currently bound vbo)
  560. glEnableVertexAttribArray(2);
  561. glVertexAttribPointer(
  562. 2, // index of the attribute
  563. 3, GL_FLOAT, // a normal consists of 3 floats
  564. GL_FALSE,
  565. sizeof(Vertex), // stride between consecutive normals in the buffer
  566. reinterpret_cast<const void*>(offsetof(Vertex, normal))); // offset of this attribute
  567.  
  568. // unbind bound objects
  569. glBindBuffer(GL_ARRAY_BUFFER, 0);
  570. glBindVertexArray(0);
  571.  
  572. return batch;
  573. }
  574.  
  575. /// Creates an OpenGL texture object using a texture from a file.
  576. /// @param filename Path to the file containing the texture.
  577. /// @return OpenGL handle of the created texture object.
  578. GLuint CreateSpriteTexture(std::string const& filename)
  579. {
  580. // Load file and decode image.
  581. unsigned int width, height;
  582. std::vector<unsigned char> image_data;
  583. unsigned int error = lodepng::decode(image_data, width, height, filename);
  584.  
  585. GLint level = 0;
  586. GLint internal_format = GL_RGBA8;
  587. GLenum format = GL_RGBA;
  588. GLenum type = GL_UNSIGNED_BYTE;
  589. GLint border = 0;
  590.  
  591. GLuint texture_name = 0;
  592.  
  593. // generate a new texture object using glGenTextures and store its name in texture_name
  594. glGenTextures(1, &texture_name);
  595.  
  596. // bind the created texture as a 2D texture
  597. glBindTexture(GL_TEXTURE_2D, texture_name);
  598.  
  599. // use glTexParameteri to set the texture wrap mode to GL_MIRRORED_REPEAT,
  600. // the minification filter to GL_LINEAR_MIPMAP_LINEAR and the maxification filter to GL_LINEAR
  601. // hint: you have to do four calls to the function
  602. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
  603. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
  604. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  605. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  606.  
  607. // use the (oldschool) function glTexImage2D to buffer the actual texture data using the
  608. // information and data supplied above
  609. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type,
  610. image_data.data());
  611.  
  612. // generate mipmaps for the texture
  613. glGenerateMipmap(GL_TEXTURE_2D);
  614.  
  615. glBindTexture(GL_TEXTURE_2D, 0);
  616.  
  617. return texture_name;
  618. }
  619.  
  620. /// Loads the shader programs or reloads them.
  621. void UpdateShaders()
  622. {
  623. glDeleteProgram(g_shader_program_ground);
  624.  
  625. try {
  626. // compile vertex & fragment shader
  627. GLuint vertex_shader_ground = glCreateShader(GL_VERTEX_SHADER);
  628. CompileShader(vertex_shader_ground, "../shaders/vert_ground.glsl");
  629. GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
  630. CompileShader(fragment_shader, "../shaders/frag.glsl");
  631.  
  632. GLuint vertex_shdr_tree_sprite = glCreateShader(GL_VERTEX_SHADER);
  633. CompileShader(vertex_shdr_tree_sprite, "../shaders/vert_tree_imposter.glsl");
  634. GLuint fragment_shdr_tree_sprite = glCreateShader(GL_FRAGMENT_SHADER);
  635. CompileShader(fragment_shdr_tree_sprite, "../shaders/frag_tree_imposter.glsl");
  636.  
  637. // link shaders
  638. g_shader_program_ground = glCreateProgram();
  639. LinkProgram(g_shader_program_ground, { vertex_shader_ground, fragment_shader });
  640. g_shader_program_tree_imposter = glCreateProgram();
  641. LinkProgram(g_shader_program_tree_imposter,
  642. { vertex_shdr_tree_sprite, fragment_shdr_tree_sprite });
  643.  
  644. // clean shaders up
  645. glDetachShader(g_shader_program_ground, fragment_shader);
  646. glDetachShader(g_shader_program_ground, vertex_shader_ground);
  647. glDetachShader(g_shader_program_tree_imposter, vertex_shdr_tree_sprite);
  648. glDetachShader(g_shader_program_tree_imposter, fragment_shdr_tree_sprite);
  649. glDeleteShader(fragment_shader);
  650. glDeleteShader(vertex_shader_ground);
  651. glDeleteShader(vertex_shdr_tree_sprite);
  652. glDeleteShader(fragment_shdr_tree_sprite);
  653. }
  654. catch (const std::runtime_error & e) {
  655. std::cerr << e.what() << "\nPress 'R' to reload the shaders.\n";
  656. }
  657. }
  658.  
  659. /// Helper function for controlling an axis with 2 keys.
  660. /// @param window The window where the keys should be pressed.
  661. /// @param key1 The first key.
  662. /// @param key2 The second key.
  663. /// @return -1 if only the first key is pressed, 1 if only the second key is pressed and 0 if none
  664. /// of the keys or both keys are pressed.
  665. int KeyAxisValue(GLFWwindow* window, int key1, int key2)
  666. {
  667. bool key1_pressed = glfwGetKey(g_window, key1) == GLFW_PRESS;
  668. bool key2_pressed = glfwGetKey(g_window, key2) == GLFW_PRESS;
  669. return key2_pressed - key1_pressed;
  670. }
  671.  
  672. double t0, t1 = 0.0;
  673.  
  674. void applyJoystickInput()
  675. {
  676. if (!glfwJoystickPresent(GLFW_JOYSTICK_1))
  677. return;
  678.  
  679. t0 = t1;
  680. t1 = glfwGetTime();
  681. double dt = t1 - t0;
  682.  
  683. int count;
  684. const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &count);
  685.  
  686. // update yaw and pitch
  687. float rot_dx = axes[2];
  688. float rot_dy = axes[3];
  689.  
  690. if (abs(rot_dx) < 0.025f)
  691. rot_dx = 0.0f;
  692.  
  693. if (abs(rot_dy) < 0.025f)
  694. rot_dy = 0.0f;
  695.  
  696. rot_dx = std::abs(rot_dx) * rot_dx * 1.5f;
  697. rot_dy = std::abs(rot_dy) * rot_dy * 1.5f;
  698.  
  699. g_cam_yaw += -rot_dx * static_cast<float>(dt);
  700. g_cam_yaw = std::remainder(g_cam_yaw, 2 * glm::pi<float>());
  701. g_cam_pitch += rot_dy * static_cast<float>(dt);
  702. g_cam_pitch = glm::clamp(g_cam_pitch, -1.5f, 1.5f);
  703.  
  704.  
  705. float trans_dx = axes[0];
  706. float trans_dy = axes[1];
  707.  
  708. if (abs(trans_dx) < 0.05f)
  709. trans_dx = 0.0f;
  710.  
  711. if (abs(trans_dy) < 0.05f)
  712. trans_dy = 0.0f;
  713.  
  714. glm::vec3 position = g_cam_pos;
  715.  
  716. // calculate camera direction
  717. glm::vec3 vfront{ 0, 0, -1 };
  718. vfront = glm::mat3(glm::rotate(glm::mat4(1), g_cam_pitch, glm::vec3(1, 0, 0))) * vfront;
  719. vfront = glm::mat3(glm::rotate(glm::mat4(1), g_cam_yaw, glm::vec3(0, 1, 0))) * vfront;
  720.  
  721. glm::vec3 vUp = glm::vec3(0.0f, 1.0f, 0.0f);
  722. glm::vec3 vRighthand = glm::normalize(glm::cross(vfront, vUp));
  723.  
  724. g_cam_pos = position + trans_dy * 20.0f * vfront * (float)dt + trans_dx * 20.0f * vRighthand * (float)dt;
  725. }
  726.  
  727. /// Synchronizes scene updates to a frequenzy of 100 Hz.
  728. /// This function assumes that the scene is updated each time it returns true.
  729. /// @return true iff the scene should be updated now.
  730. bool NeedSceneUpdate()
  731. {
  732. static auto nextUpdate = std::chrono::high_resolution_clock::now();
  733. auto now = std::chrono::high_resolution_clock::now();
  734. if (nextUpdate > now)
  735. return false;
  736. nextUpdate += std::chrono::milliseconds{ 10 };
  737. return true;
  738. }
  739.  
  740. /// Applies per-frame updates of the scene.
  741. void UpdateScene()
  742. {
  743. // update camera postion and orientation from gamepad input
  744. applyJoystickInput();
  745.  
  746. // update camera yaw and pitch
  747. int rot_horz_target = KeyAxisValue(g_window, GLFW_KEY_RIGHT, GLFW_KEY_LEFT);
  748. int rot_vert_target = KeyAxisValue(g_window, GLFW_KEY_DOWN, GLFW_KEY_UP);
  749. g_diff_cam_yaw = lerp(0.1f, g_diff_cam_yaw, static_cast<float>(rot_horz_target));
  750. g_diff_cam_pitch = lerp(0.1f, g_diff_cam_pitch, static_cast<float>(rot_vert_target));
  751. g_cam_yaw += 0.02f * g_diff_cam_yaw;
  752. g_cam_yaw = std::remainder(g_cam_yaw, 2 * glm::pi<float>());
  753. g_cam_pitch += 0.03f * g_diff_cam_pitch;
  754. g_cam_pitch = glm::clamp(g_cam_pitch, -1.5f, 1.5f);
  755.  
  756. // calculate camera direction
  757. glm::vec3 cam_dir{ 0, 0, -1 };
  758. cam_dir = glm::mat3(glm::rotate(glm::mat4(1), g_cam_pitch, glm::vec3(1, 0, 0))) * cam_dir;
  759. cam_dir = glm::mat3(glm::rotate(glm::mat4(1), g_cam_yaw, glm::vec3(0, 1, 0))) * cam_dir;
  760.  
  761. // calculate the rotation matrix used to orient the target velocity along the camera
  762. glm::vec2 cam_dir_2d{ cam_dir.x, cam_dir.z }; // only consider the xz-plane
  763. cam_dir_2d = glm::normalize(cam_dir_2d);
  764. glm::mat3 rot{ -cam_dir_2d.y, 0, cam_dir_2d.x, 0, 1, 0, -cam_dir_2d.x, 0, -cam_dir_2d.y };
  765.  
  766. // update camera velocity and position
  767. glm::vec3 target_velocity =
  768. rot * glm::vec3{ KeyAxisValue(g_window, GLFW_KEY_A, GLFW_KEY_D),
  769. KeyAxisValue(g_window, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_SPACE),
  770. KeyAxisValue(g_window, GLFW_KEY_W, GLFW_KEY_S) };
  771. g_cam_velocity = lerp(0.08f, g_cam_velocity, target_velocity);
  772. g_cam_pos += 0.05f * g_cam_velocity;
  773.  
  774. // calculate view matrix
  775. g_per_frame.view = glm::lookAt(g_cam_pos, // camera position
  776. g_cam_pos + cam_dir, // point to look towards (not a direction)
  777. glm::vec3{ 0, 1, 0 }); // up direction
  778.  
  779. // calculate projection matrix
  780. float aspect = static_cast<float>(g_window_width) / g_window_height;
  781. g_per_frame.proj = glm::perspective(0.25f * glm::pi<float>(), // fov in y-direction in radians
  782. aspect, // aspect ratio w/h
  783. 0.1f, // distance to near plane
  784. 500.f); // distance to far plane
  785.  
  786. /*
  787. * TODO: Aufgabe 2: Nutzen Sie die Parameter g_light_yaw sowie die Funktion KeyAxisValue
  788. * um eine Rotation der Lichtrichtung um die y-Achse zu implementieren. Die Taste 1
  789. * soll gegen den Uhrzeigersinn rotieren und die Taste 2 soll im Uhrzeigersinn rotieren.
  790. *
  791. * Hinweise: - Die Werte für Taste 1 und Taste 2 sind GLFW_KEY_1 und GLFW_KEY_2.
  792. * - Das Ergebnis der rotation muss in g_per_frame.light_dir gespeichert werden.
  793. */
  794.  
  795. int state = KeyAxisValue(g_window, GLFW_KEY_1, GLFW_KEY_2);
  796.  
  797. if (state == -1) {
  798.  
  799. g_per_frame.light_dir.x = g_per_frame.light_dir.x * cos(g_light_yaw) - g_per_frame.light_dir.y * sin(g_light_yaw);
  800. g_per_frame.light_dir.z = -g_per_frame.light_dir.x * sin(g_light_yaw) + g_per_frame.light_dir.z * cos(g_light_yaw);
  801. }
  802. else if (state == 1) {
  803. g_per_frame.light_dir.x = g_per_frame.light_dir.x * cos(-g_light_yaw) - g_per_frame.light_dir.y * sin(-g_light_yaw);
  804. g_per_frame.light_dir.z = -g_per_frame.light_dir.x * sin(-g_light_yaw) + g_per_frame.light_dir.z * cos(-g_light_yaw);
  805. }
  806.  
  807. }
  808.  
  809. /// Renders a RenderBatch.
  810. /// @param batch The RenderBatch to render.
  811. void RenderObject(const RenderBatch& batch)
  812. {
  813. // upload model matrix
  814. glUniformMatrix4fv(glGetUniformLocation(g_shader_program_ground, "model"),
  815. 1, false, glm::value_ptr(batch.per_object.model));
  816.  
  817. // render
  818. glBindVertexArray(batch.vao);
  819. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.ibo);
  820. glDrawElements(GL_TRIANGLES, batch.index_count, GL_UNSIGNED_INT, nullptr);
  821. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  822. glBindVertexArray(0);
  823. }
  824.  
  825. /// Renders a frame.
  826. void RenderFrame()
  827. {
  828. // update per-frame uniform buffer
  829. glBindBuffer(GL_UNIFORM_BUFFER, g_ubo_per_frame);
  830. void* data = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
  831. memcpy(data, &g_per_frame, sizeof(g_per_frame));
  832. glUnmapBuffer(GL_UNIFORM_BUFFER);
  833. glBindBuffer(GL_UNIFORM_BUFFER, 0);
  834.  
  835. // setup rendering
  836. glViewport(0, 0, g_window_width, g_window_height);
  837. glClearColor(0.53f, 0.81f, 0.98f, 1);
  838. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  839.  
  840. // render the ground
  841. glUseProgram(g_shader_program_ground);
  842. RenderObject(g_render_batch_ground);
  843.  
  844. /*
  845. * TODO: Aufgabe 3 Teilaufgabe 2: Aktivieren sie Blending und rendern sie das Wasser Mesh.
  846. */
  847.  
  848.  
  849.  
  850. //glEnable(GL_BLEND);
  851. //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  852. RenderObject(g_render_batch_water);
  853. //glEnable(GL_BLEND);
  854. //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  855.  
  856.  
  857. /*
  858. * TODO: Aufgabe 3 Teilaufgabe 3: Nutzen Sie das OpenGL program g_shader_program_tree_imposter
  859. * um die Bäume zu rendern.
  860. */
  861.  
  862. // unbind buffers
  863. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  864. glBindVertexArray(0);
  865. }
  866.  
  867. /// Updates the resolution. This is called by GLFW when the resolution changes.
  868. /// @param window The window that changed resolution.
  869. /// @param width New width.
  870. /// @param height New height.
  871. void FramebufferSizeCallback(GLFWwindow* window, int width, int height)
  872. {
  873. g_window_width = width;
  874. g_window_height = height;
  875. }
  876.  
  877. /// Reloads the shaders if 'R' is pressed. This is called by GLFW when a key is pressed.
  878. /// @param window The window in which a key was pressed.
  879. /// @param key GLFW key code of the pressed key.
  880. /// @param scancode platform-specific key code.
  881. /// @param action One of GLFW_PRESS, GLFW_REPEAT or GLFW_RELEASE
  882. /// @param mods Modifier bits.
  883. void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
  884. {
  885. if (key == GLFW_KEY_R && action == GLFW_PRESS)
  886. UpdateShaders();
  887. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement