-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathEclipseShadowReceiver.cpp
129 lines (94 loc) · 5.22 KB
/
EclipseShadowReceiver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
////////////////////////////////////////////////////////////////////////////////////////////////////
// This file is part of CosmoScout VR //
////////////////////////////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: German Aerospace Center (DLR) <[email protected]>
// SPDX-License-Identifier: MIT
#include "EclipseShadowReceiver.hpp"
#include "../cs-graphics/EclipseShadowMap.hpp"
#include "../cs-scene/CelestialObject.hpp"
#include "../cs-utils/filesystem.hpp"
#include "../cs-utils/utils.hpp"
#include "GraphicsEngine.hpp"
#include "SolarSystem.hpp"
#include <VistaOGLExt/VistaGLSLShader.h>
#include <glm/gtc/type_ptr.hpp>
#include <utility>
namespace cs::core {
////////////////////////////////////////////////////////////////////////////////////////////////////
EclipseShadowReceiver::EclipseShadowReceiver(std::shared_ptr<Settings> settings,
std::shared_ptr<SolarSystem> solarSystem, bool allowSelfShadowing)
: mSettings(std::move(settings))
, mSolarSystem(std::move(solarSystem))
, mAllowSelfShadowing(allowSelfShadowing) {
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool EclipseShadowReceiver::needsRecompilation() const {
return mLastEclipseShadowMode != mSettings->mGraphics.pEclipseShadowMode.get();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::string EclipseShadowReceiver::getShaderSnippet() const {
// Load the code only once.
static std::string code(
utils::filesystem::loadToString("../share/resources/shaders/eclipseShadows.glsl"));
// Inject the current eclipse mode into a copy of the string.
auto copy = code;
cs::utils::replaceString(copy, "ECLIPSE_MODE",
cs::utils::toString(static_cast<int>(mSettings->mGraphics.pEclipseShadowMode.get())));
// Store the last use mode. This is required for needsRecompilation().
mLastEclipseShadowMode = mSettings->mGraphics.pEclipseShadowMode.get();
return copy;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void EclipseShadowReceiver::init(VistaGLSLShader* shader, uint32_t textureOffset) {
mShader = shader;
mTextureOffset = textureOffset;
mUniforms.sun = glGetUniformLocation(shader->GetProgram(), "uEclipseSun");
mUniforms.numOccluders = glGetUniformLocation(shader->GetProgram(), "uEclipseNumOccluders");
mUniforms.occluders = glGetUniformLocation(shader->GetProgram(), "uEclipseOccluders");
mUniforms.shadowMaps = glGetUniformLocation(shader->GetProgram(), "uEclipseShadowMaps");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void EclipseShadowReceiver::update(scene::CelestialObject const& shadowReceiver) {
// No eclipse computation required if lighting is disabled.
if (!mSettings->mGraphics.pEnableLighting.get()) {
mShadowMaps.clear();
return;
}
// Acquire a list of all potentially relevant eclipse shadow maps.
mShadowMaps = mSolarSystem->getEclipseShadowMaps(shadowReceiver, mAllowSelfShadowing);
// For each shadow-casting body, we store the observer-relative position and the observer-relative
// radius. For now, all occluders are considered to be spheres.
for (size_t i(0); i < mShadowMaps.size() && i < MAX_BODIES; ++i) {
auto object = mSolarSystem->getObject(mShadowMaps[i]->mOccluder);
auto pos = object->getObserverRelativePosition();
mOccluders[i] = glm::vec4(
pos, object->getRadii()[0] * object->getScale() / mSolarSystem->getObserver().getScale());
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void EclipseShadowReceiver::preRender() const {
mShader->SetUniform(mUniforms.numOccluders, static_cast<int>(mShadowMaps.size()));
// Bind all eclipse shadow maps and upload the respective caster positions and radii.
if (!mShadowMaps.empty()) {
std::array<int, MAX_BODIES> shadowMapBindings{};
for (size_t i(0); i < mShadowMaps.size() && i < MAX_BODIES; ++i) {
shadowMapBindings[i] = static_cast<int>(i + mTextureOffset);
mShadowMaps[i]->mTexture->Bind(GL_TEXTURE0 + shadowMapBindings[i]);
}
glUniform4fv(mUniforms.occluders, MAX_BODIES, glm::value_ptr(mOccluders[0]));
glUniform1iv(mUniforms.shadowMaps, MAX_BODIES, shadowMapBindings.data());
// Also, the Sun's position and radius is required.
auto sunPos = mSolarSystem->pSunPosition.get();
auto sunRadius = mSolarSystem->getSun()->getRadii()[0] / mSolarSystem->getObserver().getScale();
mShader->SetUniform(mUniforms.sun, static_cast<float>(sunPos.x), static_cast<float>(sunPos.y),
static_cast<float>(sunPos.z), static_cast<float>(sunRadius));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void EclipseShadowReceiver::postRender() const {
for (size_t i = 0; i < mShadowMaps.size(); ++i) {
mShadowMaps[i]->mTexture->Unbind(GL_TEXTURE0 + static_cast<int>(i + mTextureOffset));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace cs::core