/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2024 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include #include #include #include #include #include namespace { constexpr std::string_view _loggerCat = "DirectionalLightsource"; struct [[codegen::Dictionary(DirectionalLightsource)]] Parameters { }; #include "DirectionalLightsource_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DirectionalLightSource::Documentation() { return codegen::doc("base_renderable_cartesianaxes"); } DirectionalLightSource::DirectionalLightSource(const ghoul::Dictionary& dictionary) : Renderable(dictionary) { setRenderBin(Renderable::RenderBin::Background); } bool DirectionalLightSource::isReady() const { return true; } void DirectionalLightSource::initialize() { _depthMapResolution = global::renderEngine->renderingResolution() * 4; } void DirectionalLightSource::initializeGL() { _depthMapProgram = BaseModule::ProgramObjectManager.request( "ModelDepthMapProgram", [&]() -> std::unique_ptr { std::filesystem::path vs = absPath("${MODULE_BASE}/shaders/model_depth_vs.glsl"); std::filesystem::path fs = absPath("${MODULE_BASE}/shaders/model_depth_fs.glsl"); std::unique_ptr prog = global::renderEngine->buildRenderProgram( "ModelDepthMapProgram", vs, fs ); prog->setIgnoreAttributeLocationError( ghoul::opengl::ProgramObject::IgnoreError::Yes ); prog->setIgnoreUniformLocationError( ghoul::opengl::ProgramObject::IgnoreError::Yes ); return prog; } ); } void DirectionalLightSource::deinitializeGL() { for (const auto& [key, tex] : _depthMaps) { glDeleteTextures(1, &tex); } for (const auto& [key, fbo] : _FBOs) { glDeleteFramebuffers(1, &fbo); } } void DirectionalLightSource::render(const RenderData& data, RendererTasks&){ for (const auto& [key, casters] : _shadowGroups) { if (!_depthMaps.contains(key)) { GLint prevFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _depthMapResolution.x, _depthMapResolution.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(glm::vec4(1.f, 1.f, 1.f, 1.f))); glBindTexture(GL_TEXTURE_2D, 0); _depthMaps[key] = tex; GLuint fbo; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex, 0); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, 0); _FBOs[key] = fbo; glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); } glm::dvec3 vmin(std::numeric_limits::max()), vmax(-std::numeric_limits::max()); std::vector torender; for (const std::string& identifier : casters) { SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(identifier); if (node != nullptr) { RenderableModel* model = dynamic_cast(node->renderable()); if (model != nullptr && model->isEnabled() && model->isCastingShadow() && model->isReady()) { const double fsz = model->shadowFrustumSize(); glm::dvec3 center = model->center(); vmin = glm::min(vmin, center - fsz / 2); vmax = glm::max(vmax, center + fsz / 2); torender.push_back(model); } } } double sz = glm::length(vmax - vmin); double d = sz * 500.; glm::dvec3 center = vmin + (vmax - vmin) * 0.5; glm::dvec3 light = parent()->modelTransform() * glm::dvec4(0.0, 0.0, 0.0, 1.0); glm::dvec3 light_dir = glm::normalize(center - light); glm::dvec3 right = glm::normalize(glm::cross(glm::dvec3(0, 1, 0), light_dir)); glm::dvec3 eye = center - light_dir * d; glm::dvec3 up = glm::cross(right, light_dir); glm::dmat4 view = glm::lookAt(eye, center, up); glm::dmat4 projection = glm::ortho( -sz, sz, -sz, sz, d - sz, d + sz ); glm::dmat4 vp = projection * view; GLint prevProg; glGetIntegerv(GL_CURRENT_PROGRAM, &prevProg); GLint prevFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); GLint prevVp[4]; glGetIntegerv(GL_VIEWPORT, prevVp); glBindFramebuffer(GL_FRAMEBUFFER, _FBOs[key]); glViewport(0, 0, _depthMapResolution.x, _depthMapResolution.y); glClear(GL_DEPTH_BUFFER_BIT); for (const RenderableModel* model : torender) { model->renderForDepthMap(vp); } glBindFramebuffer(GL_FRAMEBUFFER, 0); _vps[key] = vp; glUseProgram(prevProg); glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); glViewport(prevVp[0], prevVp[1], prevVp[2], prevVp[3]); } } void DirectionalLightSource::registerShadowCaster(const std::string& shadowgroup, const std::string& identifier) { _shadowGroups[shadowgroup].push_back(identifier); } const GLuint& DirectionalLightSource::depthMap(const std::string& shadowgroup) const { return _depthMaps.at(shadowgroup); } glm::dmat4 DirectionalLightSource::viewProjectionMatrix(const std::string& shadowgroup) const { return _vps.at(shadowgroup); } } // namespace openspace