mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-01 17:20:09 -06:00
223 lines
8.7 KiB
C++
223 lines
8.7 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* 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 <modules/base/basemodule.h>
|
|
#include <modules/base/rendering/directionallightsource.h>
|
|
#include <modules/base/rendering/renderablemodel.h>
|
|
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/scene/scene.h>
|
|
#include <openspace/scene/scenegraphnode.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/opengl/programobjectmanager.h>
|
|
|
|
#include <limits>
|
|
|
|
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<Parameters>("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<ghoul::opengl::ProgramObject> {
|
|
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<ghoul::opengl::ProgramObject> 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<double>::max()), vmax(-std::numeric_limits<double>::max());
|
|
|
|
std::vector<RenderableModel*> torender;
|
|
for (const std::string& identifier : casters) {
|
|
SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(identifier);
|
|
if (node != nullptr) {
|
|
RenderableModel* model = dynamic_cast<RenderableModel*>(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
|