mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-03 01:59:35 -06:00
713 lines
25 KiB
C++
713 lines
25 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2023 *
|
|
* *
|
|
* 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 <openspace/rendering/screenspacerenderable.h>
|
|
|
|
#include <openspace/camera/camera.h>
|
|
#include <openspace/documentation/documentation.h>
|
|
#include <openspace/documentation/verifier.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/engine/windowdelegate.h>
|
|
#include <openspace/rendering/helper.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/scripting/scriptengine.h>
|
|
#include <openspace/scene/scene.h>
|
|
#include <openspace/util/factorymanager.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/misc/profiling.h>
|
|
#include <ghoul/opengl/ghoul_gl.h>
|
|
#include <ghoul/opengl/programobject.h>
|
|
#include <ghoul/opengl/textureunit.h>
|
|
#include <optional>
|
|
#include <variant>
|
|
|
|
namespace {
|
|
constexpr std::array<const char*, 6> UniformNames = {
|
|
"color", "opacity", "mvpMatrix", "tex", "backgroundColor", "gamma"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo EnabledInfo = {
|
|
"Enabled",
|
|
"Is Enabled",
|
|
"This setting determines whether this sceen space plane will be visible or not"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo
|
|
UseRadiusAzimuthElevationInfo =
|
|
{
|
|
"UseRadiusAzimuthElevation",
|
|
"Use Radius Azimuth and Elevation",
|
|
"This value determines whether the location of this screen space plane will be "
|
|
"specified using radius, azimuth and elevation (if this is set to 'true') or "
|
|
"using cartesian coordinates. By switching this value, the correct property will "
|
|
"be shown or hidden. The Cartesian coordinate system is useful if a regular "
|
|
"rendering is applied, whereas the radius azimuth elevation are most useful in a "
|
|
"planetarium environment"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo UsePerspectiveProjectionInfo =
|
|
{
|
|
"UsePerspectiveProjection",
|
|
"Use Perspective Projection",
|
|
"Determines whetether the z/radius values affects the size of the plane or not"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo CartesianPositionInfo = {
|
|
"CartesianPosition",
|
|
"Cartesian Coordinates",
|
|
"This value determines the position of this screen space plane in Cartesian "
|
|
"three-dimensional coordinates (meters)"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo RadiusAzimuthElevationInfo = {
|
|
"RadiusAzimuthElevation",
|
|
"Radius Azimuth Elevation",
|
|
"This value determines the position of this screen space plane in a "
|
|
"coordinate system based on radius (meters), azimuth (radians) and elevation "
|
|
"(radians)"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo ScaleInfo = {
|
|
"Scale",
|
|
"Scale Value",
|
|
"This value determines a scale factor for the plane. The default size of a plane "
|
|
"is determined by the concrete instance and reflects, for example, the size of "
|
|
"the image being displayed"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo LocalRotationInfo = {
|
|
"Rotation",
|
|
"Local Rotation",
|
|
"An euler rotation (x, y, z) to apply to the plane"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo MultiplyColorInfo = {
|
|
"MultiplyColor",
|
|
"Multiply Color",
|
|
"If set, the plane's texture is multiplied with this color. Useful for applying "
|
|
"a color grayscale images"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo BackgroundColorInfo = {
|
|
"BackgroundColor",
|
|
"Background Color",
|
|
"The fixed color that is combined with the screen space renderable to create the "
|
|
"final color. The actual color of the screen space renderable is alpha-blended "
|
|
"with the background color to produce the final result"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo OpacityInfo = {
|
|
"Opacity",
|
|
"Opacity",
|
|
"This value determines the opacity of the screen space plane. If this value "
|
|
"is 1, the plane is completely opaque, if this value is 0, the plane is "
|
|
"completely transparent"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo FadeInfo = {
|
|
"Fade",
|
|
"Fade",
|
|
"This value is used by the system to be able to fade out renderables "
|
|
"independently from the Opacity value selected by the user. This value should "
|
|
"not be directly manipulated through a user interface, but instead used by other "
|
|
"components of the system programmatically",
|
|
// The Developer mode should be used once the properties in the UI listen to this
|
|
// openspace::properties::Property::Visibility::Developer
|
|
openspace::properties::Property::Visibility::Hidden
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo DeleteInfo = {
|
|
"Delete",
|
|
"Delete",
|
|
"If this property is triggered, this screen space plane is removed from the "
|
|
"scene"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo FaceCameraInfo = {
|
|
"FaceCamera",
|
|
"Face Camera",
|
|
"If enabled, the local rotation is applied after the plane is rotated to face "
|
|
"the camera"
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo GammaInfo = {
|
|
"Gamma",
|
|
"Gamma Correction",
|
|
"Sets the gamma correction of the texture"
|
|
};
|
|
|
|
float wrap(float value, float min, float max) {
|
|
return glm::mod(value - min, max - min) + min;
|
|
}
|
|
|
|
|
|
struct [[codegen::Dictionary(ScreenSpaceRenderable)]] Parameters {
|
|
// The type of the Screenspace renderable that is to be created. The available
|
|
// types of Screenspace renderable depend on the configuration of the application
|
|
// and can be written to disk on application startup into the FactoryDocumentation
|
|
std::string type
|
|
[[codegen::annotation("Must name a valid Screenspace renderable")]];
|
|
|
|
// Specifies the name of this screenspace renderable. This does not have to be
|
|
// unique to the scene, but it is recommended to be
|
|
std::optional<std::string> name;
|
|
|
|
// This is the unique identifier for this screenspace renderable. It has to be
|
|
// unique amongst all existing screenspace nodes that already have been added to
|
|
// the scene.
|
|
std::optional<std::string> identifier [[codegen::identifier()]];
|
|
|
|
// [[codegen::verbatim(EnabledInfo.description)]]
|
|
std::optional<bool> enabled;
|
|
|
|
// [[codegen::verbatim(UseRadiusAzimuthElevationInfo.description)]]
|
|
std::optional<bool> useRadiusAzimuthElevation;
|
|
|
|
// [[codegen::verbatim(FaceCameraInfo.description)]]
|
|
std::optional<bool> faceCamera;
|
|
|
|
// [[codegen::verbatim(CartesianPositionInfo.description)]]
|
|
std::optional<glm::vec3> cartesianPosition;
|
|
|
|
// [[codegen::verbatim(GammaInfo.description)]]
|
|
std::optional<glm::vec3> radiusAzimuthElevation;
|
|
|
|
// [[codegen::verbatim(ScaleInfo.description)]]
|
|
std::optional<float> scale;
|
|
|
|
// [[codegen::verbatim(UseRadiusAzimuthElevationInfo.description)]]
|
|
std::optional<float> gamma;
|
|
|
|
// [[codegen::verbatim(UsePerspectiveProjectionInfo.description)]]
|
|
std::optional<bool> usePerspectiveProjection;
|
|
|
|
// [[codegen::verbatim(MultiplyColorInfo.description)]]
|
|
std::optional<glm::vec3> multiplyColor [[codegen::color()]];
|
|
|
|
// [[codegen::verbatim(BackgroundColorInfo.description)]]
|
|
std::optional<glm::vec4> backgroundColor [[codegen::color()]];
|
|
|
|
// [codegen::verbatim(OpacityInfo.description)]]
|
|
std::optional<float> opacity [[codegen::inrange(0.f, 1.f)]];
|
|
|
|
// Defines either a single or multiple tags that apply to this
|
|
// ScreenSpaceRenderable, thus making it possible to address multiple, separate
|
|
// Renderables with a single property change
|
|
std::optional<std::variant<std::string, std::vector<std::string>>> tag;
|
|
};
|
|
#include "screenspacerenderable_codegen.cpp"
|
|
} // namespace
|
|
|
|
namespace openspace {
|
|
|
|
documentation::Documentation ScreenSpaceRenderable::Documentation() {
|
|
return codegen::doc<Parameters>("core_screenspacerenderable");
|
|
}
|
|
|
|
std::unique_ptr<ScreenSpaceRenderable> ScreenSpaceRenderable::createFromDictionary(
|
|
const ghoul::Dictionary& dictionary)
|
|
{
|
|
const Parameters p = codegen::bake<Parameters>(dictionary);
|
|
|
|
ScreenSpaceRenderable* ssr =
|
|
FactoryManager::ref().factory<ScreenSpaceRenderable>()->create(
|
|
p.type,
|
|
dictionary
|
|
);
|
|
return std::unique_ptr<ScreenSpaceRenderable>(ssr);
|
|
}
|
|
|
|
std::string ScreenSpaceRenderable::makeUniqueIdentifier(std::string name) {
|
|
std::vector<ScreenSpaceRenderable*> rs =
|
|
global::renderEngine->screenSpaceRenderables();
|
|
|
|
auto nameTaken = [&rs](const std::string& n) {
|
|
const bool taken = std::any_of(
|
|
rs.cbegin(),
|
|
rs.cend(),
|
|
[&n](ScreenSpaceRenderable* r) { return r->identifier() == n; }
|
|
);
|
|
return taken;
|
|
};
|
|
|
|
std::string baseName = name;
|
|
int i = 1;
|
|
while (nameTaken(name)) {
|
|
name = baseName + std::to_string(i);
|
|
i++;
|
|
}
|
|
return name;
|
|
}
|
|
|
|
ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary)
|
|
: properties::PropertyOwner({ "" })
|
|
, _enabled(EnabledInfo, true)
|
|
, _usePerspectiveProjection(UsePerspectiveProjectionInfo, false)
|
|
, _useRadiusAzimuthElevation(UseRadiusAzimuthElevationInfo, false)
|
|
, _faceCamera(FaceCameraInfo, true)
|
|
, _cartesianPosition(
|
|
CartesianPositionInfo,
|
|
glm::vec3(0.f, 0.f, -2.f),
|
|
glm::vec3(-4.f, -4.f, -10.f),
|
|
glm::vec3(4.f, 4.f, 0.f)
|
|
)
|
|
, _raePosition(
|
|
RadiusAzimuthElevationInfo,
|
|
glm::vec3(2.f, 0.f, 0.f),
|
|
glm::vec3(0.f, -glm::pi<float>(), -glm::half_pi<float>()),
|
|
glm::vec3(10.f, glm::pi<float>(), glm::half_pi<float>())
|
|
)
|
|
, _localRotation(
|
|
LocalRotationInfo,
|
|
glm::vec3(0.f),
|
|
glm::vec3(-glm::pi<float>()),
|
|
glm::vec3(glm::pi<float>())
|
|
)
|
|
, _scale(ScaleInfo, 0.25f, 0.f, 2.f)
|
|
, _gamma(GammaInfo, 1.f, 0.000001f, 10.f)
|
|
, _multiplyColor(MultiplyColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
|
, _backgroundColor(
|
|
BackgroundColorInfo,
|
|
glm::vec4(0.f),
|
|
glm::vec4(0.f),
|
|
glm::vec4(1.f)
|
|
)
|
|
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
|
|
, _fade(FadeInfo, 1.f, 0.f, 1.f)
|
|
, _delete(DeleteInfo)
|
|
{
|
|
const Parameters p = codegen::bake<Parameters>(dictionary);
|
|
|
|
if (p.identifier.has_value()) {
|
|
setIdentifier(*p.identifier);
|
|
}
|
|
|
|
if (p.name.has_value()) {
|
|
setGuiName(*p.name);
|
|
}
|
|
|
|
addProperty(_enabled);
|
|
addProperty(_useRadiusAzimuthElevation);
|
|
addProperty(_usePerspectiveProjection);
|
|
addProperty(_faceCamera);
|
|
addProperty(_cartesianPosition);
|
|
addProperty(_raePosition);
|
|
addProperty(_gamma);
|
|
|
|
// Setting spherical/euclidean onchange handler
|
|
_useRadiusAzimuthElevation.onChange([this]() {
|
|
if (_useRadiusAzimuthElevation) {
|
|
_raePosition = sphericalToRae(cartesianToSpherical(_cartesianPosition));
|
|
}
|
|
else {
|
|
_cartesianPosition = sphericalToCartesian(raeToSpherical(_raePosition));
|
|
}
|
|
});
|
|
|
|
addProperty(_scale);
|
|
addProperty(_multiplyColor);
|
|
addProperty(_backgroundColor);
|
|
addProperty(_opacity);
|
|
addProperty(_fade);
|
|
addProperty(_localRotation);
|
|
|
|
|
|
_multiplyColor = p.multiplyColor.value_or(_multiplyColor);
|
|
_multiplyColor.setViewOption(properties::Property::ViewOptions::Color);
|
|
|
|
_backgroundColor = p.backgroundColor.value_or(_backgroundColor);
|
|
_backgroundColor.setViewOption(properties::Property::ViewOptions::Color);
|
|
|
|
_enabled = p.enabled.value_or(_enabled);
|
|
_gamma = p.gamma.value_or(_gamma);
|
|
|
|
_useRadiusAzimuthElevation =
|
|
p.useRadiusAzimuthElevation.value_or(_useRadiusAzimuthElevation);
|
|
|
|
if (_useRadiusAzimuthElevation) {
|
|
_raePosition = p.radiusAzimuthElevation.value_or(_raePosition);
|
|
}
|
|
else {
|
|
_cartesianPosition = p.cartesianPosition.value_or(_cartesianPosition);
|
|
}
|
|
|
|
_scale = p.scale.value_or(_scale);
|
|
_opacity = p.opacity.value_or(_opacity);
|
|
_usePerspectiveProjection =
|
|
p.usePerspectiveProjection.value_or(_usePerspectiveProjection);
|
|
|
|
_faceCamera = p.faceCamera.value_or(_faceCamera);
|
|
|
|
if (p.tag.has_value()) {
|
|
if (std::holds_alternative<std::string>(*p.tag)) {
|
|
addTag(std::get<std::string>(*p.tag));
|
|
}
|
|
else if (std::holds_alternative<std::vector<std::string>>(*p.tag)) {
|
|
for (const std::string& t : std::get<std::vector<std::string>>(*p.tag)) {
|
|
if (!t.empty()) {
|
|
addTag(t);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
throw ghoul::MissingCaseException();
|
|
}
|
|
}
|
|
|
|
_delete.onChange([this](){
|
|
std::string script =
|
|
"openspace.removeScreenSpaceRenderable('" + identifier() + "');";
|
|
global::scriptEngine->queueScript(
|
|
script,
|
|
scripting::ScriptEngine::RemoteScripting::No
|
|
);
|
|
});
|
|
addProperty(_delete);
|
|
}
|
|
|
|
ScreenSpaceRenderable::~ScreenSpaceRenderable() {}
|
|
|
|
bool ScreenSpaceRenderable::initialize() {
|
|
return true;
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::initializeGL() {
|
|
createShaders();
|
|
return isReady();
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::deinitialize() {
|
|
return true;
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::deinitializeGL() {
|
|
if (_shader) {
|
|
global::renderEngine->removeRenderProgram(_shader.get());
|
|
_shader = nullptr;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::render() {
|
|
ZoneScoped;
|
|
|
|
draw(
|
|
globalRotationMatrix() *
|
|
translationMatrix() *
|
|
localRotationMatrix() *
|
|
scaleMatrix()
|
|
);
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::isReady() const {
|
|
return _shader != nullptr;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::update() {}
|
|
|
|
bool ScreenSpaceRenderable::isEnabled() const {
|
|
return _enabled;
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::isUsingRaeCoords() const {
|
|
return _useRadiusAzimuthElevation;
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::isFacingCamera() const {
|
|
return _faceCamera;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::setEnabled(bool isEnabled) {
|
|
_enabled = isEnabled;
|
|
}
|
|
|
|
float ScreenSpaceRenderable::depth() {
|
|
return _useRadiusAzimuthElevation ?
|
|
_raePosition.value().x :
|
|
cartesianToSpherical(_cartesianPosition).x;
|
|
}
|
|
|
|
float ScreenSpaceRenderable::scale() const {
|
|
return _scale;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::createShaders() {
|
|
ghoul::Dictionary dict = ghoul::Dictionary();
|
|
|
|
auto res = global::windowDelegate->currentDrawBufferResolution();
|
|
ghoul::Dictionary rendererData;
|
|
rendererData.setValue(
|
|
"fragmentRendererPath",
|
|
std::string("${SHADERS}/framebuffer/renderframebuffer.frag")
|
|
);
|
|
rendererData.setValue("windowWidth", res.x);
|
|
rendererData.setValue("windowHeight", res.y);
|
|
rendererData.setValue(
|
|
"hdrExposure",
|
|
static_cast<double>(global::renderEngine->hdrExposure())
|
|
);
|
|
rendererData.setValue("disableHDR", global::renderEngine->isHdrDisabled());
|
|
|
|
dict.setValue("rendererData", rendererData);
|
|
dict.setValue(
|
|
"fragmentPath",
|
|
std::string("${MODULE_BASE}/shaders/screenspace_fs.glsl")
|
|
);
|
|
_shader = ghoul::opengl::ProgramObject::Build(
|
|
"ScreenSpaceProgram",
|
|
absPath("${MODULE_BASE}/shaders/screenspace_vs.glsl"),
|
|
absPath("${SHADERS}/render.frag"),
|
|
dict
|
|
);
|
|
|
|
ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
|
|
}
|
|
|
|
glm::mat4 ScreenSpaceRenderable::scaleMatrix() {
|
|
// to scale the plane
|
|
float textureRatio =
|
|
static_cast<float>(_objectSize.y) / static_cast<float>(_objectSize.x);
|
|
|
|
glm::mat4 scale = glm::scale(
|
|
glm::mat4(1.f),
|
|
glm::vec3(_scale, textureRatio*_scale, 1.f)
|
|
);
|
|
|
|
return scale;
|
|
}
|
|
|
|
glm::vec2 ScreenSpaceRenderable::screenSpacePosition() {
|
|
return glm::vec2(_cartesianPosition.value());
|
|
}
|
|
|
|
glm::vec2 ScreenSpaceRenderable::screenSpaceDimensions() {
|
|
float ratio = static_cast<float>(_objectSize.x) / static_cast<float>(_objectSize.y);
|
|
return glm::vec2(2.f * _scale * ratio, 2.f * _scale);
|
|
}
|
|
|
|
glm::vec2 ScreenSpaceRenderable::upperRightCornerScreenSpace() {
|
|
return screenSpacePosition() + (screenSpaceDimensions() / 2.0f);
|
|
}
|
|
|
|
glm::vec2 ScreenSpaceRenderable::lowerLeftCornerScreenSpace() {
|
|
return screenSpacePosition() - (screenSpaceDimensions() / 2.0f);
|
|
}
|
|
|
|
bool ScreenSpaceRenderable::isIntersecting(glm::vec2 coord) {
|
|
bool isUnderTopBorder = coord.x < upperRightCornerScreenSpace().x;
|
|
bool isLeftToRightBorder = coord.y < upperRightCornerScreenSpace().y;
|
|
bool isRightToLeftBorder = coord.x > lowerLeftCornerScreenSpace().x;
|
|
bool isOverBottomBorder = coord.y > lowerLeftCornerScreenSpace().y;
|
|
|
|
return isUnderTopBorder && isLeftToRightBorder &&
|
|
isRightToLeftBorder && isOverBottomBorder;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::translate(glm::vec2 translation, glm::vec2 position) {
|
|
glm::mat4 translationMatrix = glm::translate(
|
|
glm::mat4(1.f),
|
|
glm::vec3(translation, 0.0f)
|
|
);
|
|
glm::vec4 origin = glm::vec4(position, _cartesianPosition.value().z, 1.0f);
|
|
_cartesianPosition = translationMatrix * origin;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::setCartesianPosition(const glm::vec3& position) {
|
|
_cartesianPosition = position;
|
|
}
|
|
|
|
void ScreenSpaceRenderable::setRaeFromCartesianPosition(const glm::vec3& position) {
|
|
_raePosition = cartesianToRae(position);
|
|
}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::raePosition() const {
|
|
return _raePosition;
|
|
}
|
|
|
|
glm::mat4 ScreenSpaceRenderable::globalRotationMatrix() {
|
|
// We do not want the screen space planes to be affected by
|
|
// 1) The global rotation of the view applied in the render engine
|
|
// 2) sgct's scene matrix (also called model matrix by sgct)
|
|
|
|
glm::mat4 inverseRotation = glm::inverse(
|
|
global::renderEngine->globalRotation() *
|
|
global::windowDelegate->modelMatrix()
|
|
);
|
|
|
|
// The rotation of all screen space renderables is adjustable in the render engine:
|
|
return global::renderEngine->screenSpaceRotation() * inverseRotation;
|
|
}
|
|
|
|
glm::mat4 ScreenSpaceRenderable::localRotationMatrix() {
|
|
glm::mat4 rotation = glm::mat4(1.f);
|
|
if (_faceCamera) {
|
|
glm::vec3 translation = _useRadiusAzimuthElevation ?
|
|
sphericalToCartesian(raeToSpherical(_raePosition)) :
|
|
_cartesianPosition;
|
|
|
|
rotation = glm::inverse(glm::lookAt(
|
|
glm::vec3(0.f),
|
|
glm::normalize(translation),
|
|
glm::vec3(0.f, 1.f, 0.f)
|
|
));
|
|
}
|
|
|
|
float roll = _localRotation.value().x;
|
|
float pitch = _localRotation.value().y;
|
|
float yaw = _localRotation.value().z;
|
|
return rotation * glm::mat4(glm::quat(glm::vec3(pitch, yaw, roll)));
|
|
}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::raeToCartesian(const glm::vec3& rae) const {
|
|
return sphericalToCartesian(raeToSpherical(rae));
|
|
}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::cartesianToRae(const glm::vec3& cartesian) const {
|
|
return sphericalToRae(cartesianToSpherical(cartesian));
|
|
}
|
|
|
|
glm::mat4 ScreenSpaceRenderable::translationMatrix() {
|
|
glm::vec3 translation = _useRadiusAzimuthElevation ?
|
|
sphericalToCartesian(raeToSpherical(_raePosition)) :
|
|
_cartesianPosition;
|
|
|
|
return glm::translate(glm::mat4(1.f), translation);
|
|
}
|
|
|
|
void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) {
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
_shader->activate();
|
|
|
|
_shader->setUniform(_uniformCache.color, _multiplyColor);
|
|
_shader->setUniform(_uniformCache.opacity, opacity());
|
|
_shader->setUniform(_uniformCache.backgroundColor, _backgroundColor);
|
|
_shader->setUniform(_uniformCache.gamma, _gamma);
|
|
_shader->setUniform(
|
|
_uniformCache.mvp,
|
|
global::renderEngine->scene()->camera()->viewProjectionMatrix() * modelTransform
|
|
);
|
|
|
|
ghoul::opengl::TextureUnit unit;
|
|
unit.activate();
|
|
bindTexture();
|
|
_shader->setUniform(_uniformCache.texture, unit);
|
|
|
|
glBindVertexArray(rendering::helper::vertexObjects.square.vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
_shader->deactivate();
|
|
unbindTexture();
|
|
}
|
|
|
|
void ScreenSpaceRenderable::unbindTexture() {}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::sanitizeSphericalCoordinates(glm::vec3 spherical) const {
|
|
const float r = spherical.x;
|
|
float phi = spherical.z;
|
|
|
|
// Sanitize coordinates.
|
|
float theta = wrap(spherical.y, 0.f, glm::two_pi<float>());
|
|
if (theta > glm::pi<float>()) {
|
|
theta = glm::two_pi<float>() - theta;
|
|
phi += glm::pi<float>();
|
|
}
|
|
|
|
return glm::vec3(r, theta, phi);
|
|
}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::sphericalToCartesian(glm::vec3 spherical) const {
|
|
// First convert to ISO convention spherical coordinates according to
|
|
// https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
|
// (radius, theta, phi), where theta is the polar angle from the z axis,
|
|
// and phi is the azimuth.
|
|
|
|
const glm::vec3 sanitized = sanitizeSphericalCoordinates(std::move(spherical));
|
|
const float x = sanitized[0] * sin(sanitized[1]) * cos(sanitized[2]);
|
|
const float y = sanitized[0] * sin(sanitized[1]) * sin(sanitized[2]);
|
|
const float z = sanitized[0] * cos(sanitized[1]);
|
|
|
|
// Now, convert rotate the coordinate system, so that z maps to y,
|
|
// and y maps to -z. We want the pole to be in y instead of z.
|
|
return glm::vec3(x, -z, y);
|
|
}
|
|
|
|
glm::vec3 ScreenSpaceRenderable::cartesianToSpherical(const glm::vec3& cartesian) const {
|
|
// Rotate cartesian coordinates.
|
|
glm::vec3 rotated = glm::vec3(cartesian.x, cartesian.z, -cartesian.y);
|
|
|
|
const float r = sqrt(
|
|
pow(rotated.x, 2.f) + pow(rotated.y, 2.f) + pow(rotated.z, 2.f)
|
|
);
|
|
const float theta = acos(rotated.z / r);
|
|
const float phi = atan2(rotated.y, rotated.x);
|
|
return sanitizeSphericalCoordinates(glm::vec3(r, theta, phi));
|
|
}
|
|
|
|
// Radius, azimiuth, elevation to spherical coordinates.
|
|
glm::vec3 ScreenSpaceRenderable::raeToSpherical(glm::vec3 rae) const {
|
|
//return rae;
|
|
const float r = rae.x;
|
|
|
|
// Polar angle, theta, is elevation + pi/2.
|
|
const float theta = rae.z + glm::half_pi<float>();
|
|
|
|
// Azimuth in ISO spherical coordiantes (phi) is angle from x,
|
|
// as opposed to from negative y on screen.
|
|
const float phi = rae.y - glm::half_pi<float>();
|
|
|
|
return glm::vec3(r, theta, phi);
|
|
}
|
|
|
|
// Spherical coordinates to radius, azimuth and elevation.
|
|
glm::vec3 ScreenSpaceRenderable::sphericalToRae(glm::vec3 spherical) const {
|
|
//return spherical;
|
|
const float r = spherical.x;
|
|
|
|
// Azimuth on screen is angle from negative y, as opposed to from x.
|
|
float azimuth = spherical.z + glm::half_pi<float>();
|
|
|
|
// Elevation is polar angle - pi/2
|
|
float elevation = wrap(
|
|
spherical.y - glm::half_pi<float>(),
|
|
-glm::pi<float>(),
|
|
glm::pi<float>()
|
|
);
|
|
|
|
return glm::vec3(
|
|
r,
|
|
wrap(azimuth, -glm::pi<float>(), glm::pi<float>()),
|
|
wrap(elevation, -glm::pi<float>(), glm::pi<float>())
|
|
);
|
|
}
|
|
|
|
|
|
float ScreenSpaceRenderable::opacity() const {
|
|
return _opacity * _fade;
|
|
}
|
|
} // namespace openspace
|