Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

SkyRenderer.cpp 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include "graphics/SkyRenderer.h"
  19. #include "graphics/SkyModel.h"
  20. #include "graphics/util.h"
  21. #include "Camera.h"
  22. #include "Core.h"
  23. #include "graphics/shaders/SkyVertexShader.h"
  24. #include "graphics/shaders/SkyFragmentShader.h"
  25. static const int kCubeSize = 256;
  26. SkyRenderer::SkyRenderer()
  27. {
  28. initProgram();
  29. initGeometry();
  30. initTexture();
  31. glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
  32. }
  33. SkyRenderer::~SkyRenderer()
  34. {
  35. program_.destroy();
  36. glDeleteVertexArrays(1, &vertexArray_);
  37. glDeleteBuffers(1, &vertexBuffer_);
  38. glDeleteTextures(1, &texture_);
  39. }
  40. void SkyRenderer::render()
  41. {
  42. program_.use();
  43. glm::mat4 rotationMat = glm::mat4_cast(glm::conjugate(Core::get().camera().rotationQuat()));
  44. loadMat4ToUniform(rotationMat, program_.getUniform("rotationMat"));
  45. glBindVertexArray(vertexArray_);
  46. glActiveTexture(GL_TEXTURE0);
  47. glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
  48. glDisable(GL_DEPTH_TEST);
  49. glDrawArrays(GL_TRIANGLES, 0, vertexCount_);
  50. glEnable(GL_DEPTH_TEST);
  51. }
  52. void SkyRenderer::initProgram()
  53. {
  54. program_.create();
  55. program_.attach(GL_VERTEX_SHADER, SkyVertexShader);
  56. program_.attach(GL_FRAGMENT_SHADER, SkyFragmentShader);
  57. program_.link();
  58. }
  59. void SkyRenderer::initGeometry()
  60. {
  61. static float VERTEX_DATA[]
  62. {
  63. -1.0, -1.0,
  64. 1.0, -1.0,
  65. -1.0, 1.0,
  66. 1.0, 1.0,
  67. -1.0, 1.0,
  68. 1.0, -1.0
  69. };
  70. static const int kComponentsPerVertex = 2;
  71. vertexCount_ = sizeof(VERTEX_DATA) / sizeof(VERTEX_DATA[0]) / kComponentsPerVertex;
  72. glGenVertexArrays(1, &vertexArray_);
  73. glBindVertexArray(vertexArray_);
  74. glGenBuffers(1, &vertexBuffer_);
  75. glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
  76. glBufferData(GL_ARRAY_BUFFER, sizeof(VERTEX_DATA), VERTEX_DATA, GL_STATIC_DRAW);
  77. glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * kComponentsPerVertex, nullptr);
  78. glEnableVertexAttribArray(0);
  79. }
  80. void SkyRenderer::initTexture()
  81. {
  82. static const GLenum kFaces[]
  83. {
  84. GL_TEXTURE_CUBE_MAP_POSITIVE_X,
  85. GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  86. GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  87. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
  88. GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  89. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
  90. };
  91. static const int kNumkFaces = sizeof(kFaces) / sizeof(kFaces[0]);
  92. glGenTextures(1, &texture_);
  93. glBindTexture(GL_TEXTURE_CUBE_MAP, texture_);
  94. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  95. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  96. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  97. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  98. glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  99. SkyModel model;
  100. SkyModel::Params params;
  101. params.dt = fp_t(180.0);
  102. params.tm = fp_t(0.7);
  103. params.lng = fp_t(0.0);
  104. params.lat = fp_t(0.0);
  105. params.tu = fp_t(5.0);
  106. model.prepare(params);
  107. vector<uint8_t> data(kCubeSize * kCubeSize * 3);
  108. for(int face = 0; face < kNumkFaces; face++)
  109. {
  110. for(int j = 0; j < kCubeSize; j++)
  111. {
  112. for(int i = 0; i < kCubeSize; i++)
  113. {
  114. // scale to cube face
  115. fp_t fi = fp_t(i) / fp_t(kCubeSize - 1) * fp_t(2.0) - fp_t(1.0);
  116. fp_t fj = fp_t(j) / fp_t(kCubeSize - 1) * fp_t(2.0) - fp_t(1.0);
  117. // find point on the cube we're mapping
  118. glm::vec3 cp;
  119. switch(face)
  120. {
  121. case 0: cp = glm::vec3{ 1.0, -fj, -fi}; break; // +X
  122. case 1: cp = glm::vec3{-1.0, -fj, fi}; break; // -X
  123. case 2: cp = glm::vec3{ fi, 1.0, fj}; break; // +Y
  124. case 3: cp = glm::vec3{ fi, -1.0, -fj}; break; // -Y
  125. case 4: cp = glm::vec3{ fi, -fj, 1.0}; break; // +Z
  126. case 5: cp = glm::vec3{ -fi, -fj, -1.0}; break; // -Z
  127. }
  128. // map cube to sphere
  129. // http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
  130. glm::vec3 sp;
  131. sp.x = cp.x * glm::sqrt(fp_t(1.0) - cp.y * cp.y / fp_t(2.0) - cp.z * cp.z / fp_t(2.0) + cp.y * cp.y * cp.z * cp.z / fp_t(3.0));
  132. sp.y = cp.y * glm::sqrt(fp_t(1.0) - cp.z * cp.z / fp_t(2.0) - cp.x * cp.x / fp_t(2.0) + cp.z * cp.z * cp.x * cp.x / fp_t(3.0));
  133. sp.z = cp.z * glm::sqrt(fp_t(1.0) - cp.x * cp.x / fp_t(2.0) - cp.y * cp.y / fp_t(2.0) + cp.x * cp.x * cp.y * cp.y / fp_t(3.0));
  134. // convert cartesian to spherical
  135. // http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
  136. // phi is ccw from -y, not ccw from +x
  137. fp_t theta = acos(sp.z / sqrt(sp.x * sp.x + sp.y * sp.y + sp.z * sp.z));
  138. fp_t phi = atan2(sp.x, -sp.y);
  139. // pull sky edge below land edge
  140. theta *= fp_t(0.9);
  141. // compute and store color
  142. glm::vec3 color = model.getColor(theta, phi);
  143. data[(i + j * kCubeSize) * 3] = static_cast<uint8_t>(color.x * 0xFF);
  144. data[(i + j * kCubeSize) * 3 + 1] = static_cast<uint8_t>(color.y * 0xFF);
  145. data[(i + j * kCubeSize) * 3 + 2] = static_cast<uint8_t>(color.z * 0xFF);
  146. }
  147. }
  148. glTexImage2D(kFaces[face], 0, GL_RGB8, kCubeSize, kCubeSize, 0, GL_RGB, GL_UNSIGNED_BYTE, data.data());
  149. }
  150. sunVector_.x = sin(model.thetaSun()) * sin(model.phiSun());
  151. sunVector_.y = -sin(model.thetaSun()) * cos(model.phiSun());
  152. sunVector_.z = cos(model.thetaSun());
  153. }
  154. const glm::vec3& SkyRenderer::sunVector() const
  155. {
  156. return sunVector_;
  157. }