💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
8.5 KiB

  1. /*
  2. * Copyright (C) 2017-2019 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "shadow-map-render-pass.hpp"
  20. #include "resources/resource-manager.hpp"
  21. ShadowMapRenderPass::ShadowMapRenderPass(ResourceManager* resourceManager):
  22. resourceManager(resourceManager),
  23. shader(nullptr),
  24. croppedShadowMapViewports(nullptr),
  25. viewCamera(nullptr),
  26. splitViewFrustum(nullptr),
  27. cropMatrices(nullptr),
  28. tileMatrices(nullptr)
  29. {}
  30. bool ShadowMapRenderPass::load(const RenderContext* renderContext)
  31. {
  32. // Set maximum number of bones for skinned meshes
  33. maxBoneCount = 64;
  34. // Create split view frustum
  35. splitViewFrustum = new SplitViewFrustum(4);
  36. splitViewFrustum->setSplitSchemeWeight(0.6f);
  37. // Determine resolution of shadow maps
  38. shadowMapResolution = 4096;
  39. croppedShadowMapResolution = shadowMapResolution >> 1;
  40. // Allocate viewports
  41. croppedShadowMapViewports = new Vector4[splitViewFrustum->getSubfrustumCount()];
  42. // Setup viewports
  43. for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
  44. {
  45. int x = i % 2;
  46. int y = i / 2;
  47. Vector4* viewport = &croppedShadowMapViewports[i];
  48. (*viewport)[0] = static_cast<float>(x * croppedShadowMapResolution);
  49. (*viewport)[1] = static_cast<float>(y * croppedShadowMapResolution);
  50. (*viewport)[2] = static_cast<float>(croppedShadowMapResolution);
  51. (*viewport)[3] = static_cast<float>(croppedShadowMapResolution);
  52. }
  53. // Allocate matrices
  54. cropMatrices = new Matrix4[splitViewFrustum->getSubfrustumCount()];
  55. tileMatrices = new Matrix4[splitViewFrustum->getSubfrustumCount()];
  56. // Setup tile matrices
  57. Matrix4 tileScale = glm::scale(Vector3(0.5f, 0.5f, 1.0f));
  58. for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
  59. {
  60. float x = static_cast<float>(i % 2) * 0.5f;
  61. float y = static_cast<float>(i / 2) * 0.5f;
  62. tileMatrices[i] = glm::translate(Vector3(x, y, 0.0f)) * tileScale;
  63. }
  64. // Setup permutation values
  65. unskinnedPermutation = 0;
  66. skinnedPermutation = 1;
  67. // Load shader
  68. shader = resourceManager->load<Shader>("depth-pass.glsl");
  69. // Generate unskinned and skinned permutations
  70. if (!shader->generatePermutation(unskinnedPermutation) || !shader->generatePermutation(skinnedPermutation))
  71. {
  72. std::cerr << std::string("ShadowMapRenderPass: failed to generate shader permutation.") << std::endl;
  73. return false;
  74. }
  75. // Allocate bone palette parameter
  76. matrixPaletteParam = new ShaderMatrix4(maxBoneCount);
  77. // Connect shader variables
  78. modelViewProjectionParam.connect(shader->getInput("modelViewProjectionMatrix"));
  79. matrixPaletteParam->connect(shader->getInput("matrixPalette"));
  80. if (!modelViewProjectionParam.isConnected() ||
  81. !matrixPaletteParam->isConnected())
  82. {
  83. std::cerr << std::string("ShadowMapRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
  84. return false;
  85. }
  86. return true;
  87. }
  88. void ShadowMapRenderPass::unload()
  89. {
  90. modelViewProjectionParam.disconnect();
  91. matrixPaletteParam->disconnect();
  92. delete matrixPaletteParam;
  93. shader->deleteAllPermutations();
  94. delete[] croppedShadowMapViewports;
  95. croppedShadowMapViewports = nullptr;
  96. delete splitViewFrustum;
  97. splitViewFrustum = nullptr;
  98. delete[] cropMatrices;
  99. cropMatrices = nullptr;
  100. delete[] tileMatrices;
  101. tileMatrices = nullptr;
  102. }
  103. void ShadowMapRenderPass::render(RenderContext* renderContext)
  104. {
  105. // Bind framebuffer and setup viewport
  106. glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer);
  107. glViewport(0, 0, renderTarget->width, renderTarget->height);
  108. // Enable depth testing
  109. glEnable(GL_DEPTH_TEST);
  110. glDepthMask(GL_TRUE);
  111. glDepthFunc(GL_LESS);
  112. // Clear the framebuffer depth
  113. glClear(GL_DEPTH_BUFFER_BIT);
  114. // Draw back faces only
  115. glDisable(GL_CULL_FACE);
  116. glCullFace(GL_FRONT);
  117. // Disable alpha blending
  118. glDisable(GL_BLEND);
  119. //const Camera& lightCamera = *(renderContext->camera);
  120. std::list<RenderOperation>* operations = renderContext->queue->getOperations();
  121. GLuint boundVAO = 0;
  122. const Matrix4& viewCameraView = viewCamera->getViewTween()->getSubstate();
  123. const Matrix4& viewCameraProjection = viewCamera->getProjectionTween()->getSubstate();
  124. const Matrix4& lightCameraViewProjection = lightCamera->getViewProjectionTween()->getSubstate();
  125. splitViewFrustum->setMatrices(viewCameraView, viewCameraProjection);
  126. // Sort operations
  127. operations->sort(RenderOpCompare());
  128. std::uint32_t permutation = 0xDEADBEEF;
  129. std::uint32_t noShadowCastingFlag = 4;
  130. // For each frustum split
  131. for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
  132. {
  133. // Calculate crop matrix
  134. {
  135. const ViewFrustum& subfrustum = splitViewFrustum->getSubfrustum(i);
  136. // Create AABB containing the subfrustum corners
  137. AABB subfrustumBounds(subfrustum.getCorner(0), subfrustum.getCorner(0));
  138. for (std::size_t j = 1; j < 8; ++j)
  139. {
  140. subfrustumBounds.add(subfrustum.getCorner(j));
  141. }
  142. // Transform subfrustum bounds into light's clip space
  143. AABB croppingBounds = subfrustumBounds.transformed(lightCameraViewProjection);
  144. Vector3 cropMax = croppingBounds.getMax();
  145. Vector3 cropMin = croppingBounds.getMin();
  146. // Calculate scale
  147. Vector3 scale;
  148. scale.x = 2.0f / (cropMax.x - cropMin.x);
  149. scale.y = 2.0f / (cropMax.y - cropMin.y);
  150. scale.z = 1.0f / (cropMax.z - cropMin.z);
  151. // Quantize scale
  152. float scaleQuantizer = 64.0f;
  153. scale.x = 1.0f / std::ceil(1.0f / scale.x * scaleQuantizer) * scaleQuantizer;
  154. scale.y = 1.0f / std::ceil(1.0f / scale.y * scaleQuantizer) * scaleQuantizer;
  155. // Calculate offset
  156. Vector3 offset;
  157. offset.x = (cropMax.x + cropMin.x) * scale.x * -0.5f;
  158. offset.y = (cropMax.y + cropMin.y) * scale.y * -0.5f;
  159. offset.z = -cropMin.z * scale.z;
  160. // Quantize offset
  161. float halfTextureSize = static_cast<float>(croppedShadowMapResolution) * 0.5f;
  162. offset.x = std::ceil(offset.x * halfTextureSize) / halfTextureSize;
  163. offset.y = std::ceil(offset.y * halfTextureSize) / halfTextureSize;
  164. cropMatrices[i] = glm::translate(offset) * glm::scale(scale);
  165. }
  166. Matrix4 croppedViewProjection = cropMatrices[i] * lightCameraViewProjection;
  167. // Activate viewport for corresponding cropped shadow map
  168. const Vector4& viewport = croppedShadowMapViewports[i];
  169. glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
  170. // Render operations
  171. for (const RenderOperation& operation: *operations)
  172. {
  173. // Skip operations with no materials and materials with no shadows
  174. if (operation.material == nullptr || (operation.material->getFlags() & noShadowCastingFlag))
  175. {
  176. continue;
  177. }
  178. // TODO: Perform culling for subfrustums
  179. // Select permutation
  180. std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation;
  181. if (permutation != targetPermutation)
  182. {
  183. permutation = targetPermutation;
  184. shader->activate(permutation);
  185. }
  186. // Pass matrix palette
  187. if (operation.pose != nullptr)
  188. {
  189. matrixPaletteParam->getConnectedInput()->upload(0, operation.pose->getMatrixPalette(), operation.pose->getSkeleton()->getBoneCount());
  190. }
  191. const Matrix4& modelMatrix = operation.transform;
  192. Matrix4 modelViewProjectionMatrix = croppedViewProjection * modelMatrix;
  193. modelViewProjectionParam.setValue(modelViewProjectionMatrix);
  194. modelViewProjectionParam.upload();
  195. if (boundVAO != operation.vao)
  196. {
  197. glBindVertexArray(operation.vao);
  198. boundVAO = operation.vao;
  199. }
  200. glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset);
  201. }
  202. }
  203. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  204. }
  205. bool ShadowMapRenderPass::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const
  206. {
  207. // If A is rigged
  208. if (opA.pose != nullptr)
  209. {
  210. // And B is rigged
  211. if (opB.pose != nullptr)
  212. {
  213. // Sort by VAO ID
  214. return (opA.vao <= opB.vao);
  215. }
  216. else
  217. {
  218. // Render A first
  219. return true;
  220. }
  221. }
  222. // Sort by VAO ID
  223. return (opA.vao <= opB.vao);
  224. }