diff --git a/modules/exoplanets/CMakeLists.txt b/modules/exoplanets/CMakeLists.txt index 86d4e5588f..33edec6fd2 100644 --- a/modules/exoplanets/CMakeLists.txt +++ b/modules/exoplanets/CMakeLists.txt @@ -27,18 +27,26 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetsmodule.h ${CMAKE_CURRENT_SOURCE_DIR}/tasks/exoplanetscsvtobintask.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitdisc.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetsmodule.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tasks/exoplanetscsvtobintask.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitdisc.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) +set(SHADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/orbitdisc_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/orbitdisc_vs.glsl +) +source_group("Shader Files" FILES ${SHADER_FILES}) + create_new_module( "Exoplanets" exoplanets_module STATIC - ${HEADER_FILES} ${SOURCE_FILES} + ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) diff --git a/modules/exoplanets/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp new file mode 100644 index 0000000000..fdadad8feb --- /dev/null +++ b/modules/exoplanets/rendering/renderableorbitdisc.cpp @@ -0,0 +1,348 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 +#include +#include + +namespace { + static const openspace::properties::Property::PropertyInfo TextureInfo = { + "Texture", + "Texture", + "This value is the path to a texture on disk that contains a one-dimensional " + "texture which is used for these rings." + }; + + static const openspace::properties::Property::PropertyInfo SizeInfo = { + "Size", + "Size", + "This value specifies the semi-major axis of teh orbit in meter." + }; + + static const openspace::properties::Property::PropertyInfo EccentricityInfo = { + "Eccentricity", + "Eccentricity", + "This value determines the eccentricity, that is the deviation from a perfect sphere, for this orbit." + }; + + static const openspace::properties::Property::PropertyInfo OffsetInfo = { + "Offset", + "Offset", + "This value is used to limit the width of the rings. Each of the two values is " + "the lower and the upper uncertainties of the semi-major axis. " + }; + + static const openspace::properties::Property::PropertyInfo TransparencyInfo = { + "Transparency", + "Transparency", + "This value determines the transparency of part of the rings depending on the " + "color values. For this value v, the transparency is equal to length(color) / v." + }; +} // namespace + +namespace openspace { + +documentation::Documentation RenderableOrbitdisc::Documentation() { + using namespace documentation; + return { + "Renderable Orbitdisc", + "exoplanets_renderable_orbitdisc", + { + { + "Type", + new StringEqualVerifier("RenderableOrbitdisc"), + Optional::No + }, + { + TextureInfo.identifier, + new StringVerifier, + Optional::No, + TextureInfo.description + }, + { + SizeInfo.identifier, + new DoubleVerifier, + Optional::No, + SizeInfo.description + }, + { + EccentricityInfo.identifier, + new DoubleVerifier, + Optional::No, + EccentricityInfo.description + }, + { + OffsetInfo.identifier, + new DoubleVector2Verifier, + Optional::Yes, + OffsetInfo.description + }, + { + TransparencyInfo.identifier, + new DoubleVerifier, + Optional::Yes, + TransparencyInfo.description + } + } + }; +} + +RenderableOrbitdisc::RenderableOrbitdisc(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _texturePath(TextureInfo) + , _size(SizeInfo, 1.f, 0.f, 3.0e11f) + , _eccentricity(EccentricityInfo, 0.f, 0.f, 1.f) + , _offset(OffsetInfo, glm::vec2(0.f, 1.f), glm::vec2(0.f), glm::vec2(1.f)) + , _transparency(TransparencyInfo, 0.15f, 0.f, 1.f) + , _shader(nullptr) + , _texture(nullptr) + , _textureFile(nullptr) + , _textureIsDirty(false) + , _quad(0) + , _vertexPositionBuffer(0) + , _planeIsDirty(false) +{ + using ghoul::filesystem::File; + + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableOrbitdisc" + ); + + if (dictionary.hasKey(OffsetInfo.identifier)) { + _offset = dictionary.value(OffsetInfo.identifier); + } + addProperty(_offset); + + _size = static_cast(dictionary.value(SizeInfo.identifier)); + _size = _size + (_offset.value().y * 149597870700); + setBoundingSphere(_size); + _size.onChange([&]() { _planeIsDirty = true; }); + addProperty(_size); + + _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _textureFile = std::make_unique(_texturePath); + + _texturePath.onChange([&]() { loadTexture(); }); + addProperty(_texturePath); + + _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); + + if (dictionary.hasKey(TransparencyInfo.identifier)) { + _transparency = static_cast( + dictionary.value(TransparencyInfo.identifier) + ); + } + addProperty(_transparency); + + _eccentricity = static_cast(dictionary.value(EccentricityInfo.identifier)); + _eccentricity.onChange([&]() { _planeIsDirty = true; }); + addProperty(_eccentricity); +} + +bool RenderableOrbitdisc::isReady() const { + return _shader && _texture; +} + +void RenderableOrbitdisc::initializeGL() { + _shader = OsEng.renderEngine().buildRenderProgram( + "OrbitdiscProgram", + absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_vs.glsl"), + absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_fs.glsl") + ); + + _uniformCache.modelViewProjection = _shader->uniformLocation( + "modelViewProjectionTransform" + ); + _uniformCache.textureOffset = _shader->uniformLocation("textureOffset"); + _uniformCache.transparency = _shader->uniformLocation("transparency"); + //_uniformCache.sunPosition = _shader->uniformLocation("sunPosition"); + _uniformCache.texture = _shader->uniformLocation("texture1"); + _uniformCache.eccentricity = _shader->uniformLocation("eccentricity"); + _uniformCache.semiMajorAxis = _shader->uniformLocation("semiMajorAxis"); + + glGenVertexArrays(1, &_quad); + glGenBuffers(1, &_vertexPositionBuffer); + + createPlane(); + loadTexture(); +} + +void RenderableOrbitdisc::deinitializeGL() { + glDeleteVertexArrays(1, &_quad); + _quad = 0; + + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; + + _textureFile = nullptr; + _texture = nullptr; + + OsEng.renderEngine().removeRenderProgram(_shader.get()); + _shader = nullptr; +} + +void RenderableOrbitdisc::render(const RenderData& data, RendererTasks&) { + _shader->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform( + _uniformCache.modelViewProjection, + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _shader->setUniform(_uniformCache.textureOffset, _offset); + _shader->setUniform(_uniformCache.transparency, _transparency); + _shader->setUniform(_uniformCache.eccentricity, _eccentricity); + _shader->setUniform(_uniformCache.semiMajorAxis, _size); + //_shader->setUniform(_uniformCache.sunPosition, _sunPosition); + + //setPscUniforms(*_shader, data.camera, data.position); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.texture, unit); + + glDisable(GL_CULL_FACE); + + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glEnable(GL_CULL_FACE); + _shader->deactivate(); +} + +void RenderableOrbitdisc::update(const UpdateData& data) { + if (_shader->isDirty()) { + _shader->rebuildFromFile(); + + _uniformCache.modelViewProjection = _shader->uniformLocation( + "modelViewProjectionTransform" + ); + _uniformCache.textureOffset = _shader->uniformLocation("textureOffset"); + _uniformCache.transparency = _shader->uniformLocation("transparency"); + //_uniformCache.sunPosition = _shader->uniformLocation("sunPosition"); + _uniformCache.texture = _shader->uniformLocation("texture1"); + _uniformCache.eccentricity = _shader->uniformLocation("eccentricity"); + _uniformCache.semiMajorAxis = _shader->uniformLocation("semiMajorAxis"); + } + + if (_planeIsDirty) { + createPlane(); + _planeIsDirty = false; + } + + if (_textureIsDirty) { + loadTexture(); + _textureIsDirty = false; + } + + //_sunPosition = OsEng.renderEngine().scene()->sceneGraphNode("Sun")->worldPosition() - + //data.modelTransform.translation; +} + +void RenderableOrbitdisc::loadTexture() { + if (_texturePath.value() != "") { + std::unique_ptr texture = + ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); + + if (texture) { + LDEBUGC( + "RenderableOrbitdisc", + fmt::format("Loaded texture from '{}'", absPath(_texturePath)) + ); + _texture = std::move(texture); + + _texture->uploadTexture(); + _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + + _textureFile = std::make_unique(_texturePath); + _textureFile->setCallback( + [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } + ); + } + } +} + +void RenderableOrbitdisc::createPlane() { + const GLfloat size = _size.value() * (1.0 + _eccentricity.value()); + + struct VertexData { + GLfloat x; + GLfloat y; + GLfloat s; + GLfloat t; + }; + + VertexData data[] = { + { -size, -size, 0.f, 0.f }, + { size, size, 1.f, 1.f }, + { -size, size, 0.f, 1.f }, + { -size, -size, 0.f, 0.f }, + { size, -size, 1.f, 0.f }, + { size, size, 1.f, 1.f }, + }; + + glBindVertexArray(_quad); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + nullptr + ); + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + reinterpret_cast(offsetof(VertexData, s)) + ); +} + +} // namespace openspace diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h new file mode 100644 index 0000000000..8ddc4be64d --- /dev/null +++ b/modules/exoplanets/rendering/renderableorbitdisc.h @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_EXOPLENETS___RENDERABLEORBITDISC___H__ +#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEORBITDISC___H__ + +#include + +#include +#include +#include +#include + +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl { + class ProgramObject; + class Texture; +} // namespace ghoul::opengl + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableOrbitdisc : public Renderable { +public: + RenderableOrbitdisc(const ghoul::Dictionary& dictionary); + + void initializeGL() override; + void deinitializeGL() override; + + bool isReady() const override; + + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + + static documentation::Documentation Documentation(); + +private: + void loadTexture(); + void createPlane(); + + properties::StringProperty _texturePath; + properties::FloatProperty _size; + properties::FloatProperty _eccentricity; + properties::Vec2Property _offset; + //properties::FloatProperty _nightFactor; + properties::FloatProperty _transparency; + + std::unique_ptr _shader; + UniformCache(modelViewProjection, textureOffset, transparency, + texture, eccentricity, semiMajorAxis) _uniformCache; + std::unique_ptr _texture; + std::unique_ptr _textureFile; + + bool _textureIsDirty; + GLuint _quad; + GLuint _vertexPositionBuffer; + bool _planeIsDirty; + +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SPACE___RENDERABLERINGS___H__ diff --git a/modules/exoplanets/shaders/orbitdisc_fs.glsl b/modules/exoplanets/shaders/orbitdisc_fs.glsl new file mode 100644 index 0000000000..aacf432515 --- /dev/null +++ b/modules/exoplanets/shaders/orbitdisc_fs.glsl @@ -0,0 +1,115 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 "PowerScaling/powerScaling_fs.hglsl" +#include "fragment.glsl" + +in vec2 vs_st; +in vec4 vs_position; +//in vec4 vs_gPosition; +//in vec3 vs_gNormal; + +uniform sampler1D texture1; +uniform vec2 textureOffset; +uniform float transparency; +uniform float eccentricity; +uniform float semiMajorAxis; + +uniform bool hasSunPosition; +uniform vec3 sunPosition; +//uniform float _nightFactor; + + +Fragment getFragment() { + // Moving the origin to the center + vec2 st = (vs_st - vec2(0.5)) * 2.0; + + + // The length of the texture coordinates vector is our distance from the center + float radius; + float radius_inner; + + float semiMinorAxis = semiMajorAxis * sqrt(1.0 - pow(eccentricity, 2.0)); + float focus = sqrt(pow(semiMajorAxis, 2.0) - pow(semiMinorAxis, 2.0)); + float apoapsisDistance = semiMajorAxis * (1 + eccentricity); + + float semiMajorAxis_inner = semiMajorAxis - textureOffset.x * 149597870700.0 - textureOffset.y * 149597870700.0; + float semiMinorAxis_inner = semiMajorAxis_inner * sqrt(1.0 - pow(eccentricity, 2.0)); + float focus_inner = sqrt(pow(semiMajorAxis_inner, 2.0) - pow(semiMinorAxis_inner, 2.0)); + + if(eccentricity <= 0.0){ + radius = length(st); + radius_inner = pow(st.x , 2.0) / pow(semiMajorAxis_inner/apoapsisDistance, 2.0) + ( pow(st.y, 2.0) / (pow(semiMajorAxis_inner/apoapsisDistance, 2.0)) ); + } + else { + radius = ( pow((st.x + focus/apoapsisDistance), 2.0) ) / pow(semiMajorAxis/apoapsisDistance, 2.0) + ( pow(st.y, 2.0) / (pow(semiMinorAxis/apoapsisDistance, 2.0)) ); + radius_inner = ( pow((st.x + focus_inner/apoapsisDistance), 2.0) ) / pow(semiMajorAxis_inner/apoapsisDistance, 2.0) + ( pow(st.y, 2.0) / (pow(semiMinorAxis_inner/apoapsisDistance, 2.0)) ); + } + + // We only want to consider ring-like objects so we need to discard everything outside the largest radius + if (radius > 1.0 ) + discard; + // We also need to discard ecerthing inside the smallest radius + if (radius_inner < 1.0 ) + discard; + + // Remapping the texture coordinates + // Radius \in [0,1], texCoord \in [textureOffset.x, textureOffset.y] + // textureOffset.x -> 0 + // textureOffset.y -> 1 + + // textureOffset is not the same as it was when the following row was written. + // But as long as the texture is one color it doesnt seem to matter. + float texCoord = (radius - textureOffset.x) / (textureOffset.y - textureOffset.x); + + vec4 diffuse = texture(texture1, texCoord); + float colorValue = length(diffuse.rgb); + // times 3 as length of vec3(1.0, 1.0, 1.0) will return 3 and we want + // to normalize the transparency value to [0,1] + if (colorValue < 3.0 * transparency) { + diffuse.a = pow(colorValue / (3.0 * transparency), 1); + } + + // The normal for the one plane depends on whether we are dealing + // with a front facing or back facing fragment + vec3 normal; + // The plane is oriented on the xz plane + // WARNING: This might not be the case for Uranus + if (gl_FrontFacing) { + normal = vec3(-1.0, 0.0, 0.0); + } + else { + normal = vec3(1.0, 0.0, 0.0); + } + + + Fragment frag; + frag.color = diffuse; + frag.depth = vs_position.w; + + //frag.gPosition = vs_gPosition; + //frag.gNormal = vs_gNormal; + + return frag; +} diff --git a/modules/exoplanets/shaders/orbitdisc_vs.glsl b/modules/exoplanets/shaders/orbitdisc_vs.glsl new file mode 100644 index 0000000000..2f71337783 --- /dev/null +++ b/modules/exoplanets/shaders/orbitdisc_vs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out vec4 vs_position; +//out vec4 vs_gPosition; +//out vec3 vs_gNormal; + +uniform mat4 modelViewProjectionTransform; + +void main() { + vs_st = in_st; + + vs_position = z_normalization( + modelViewProjectionTransform * vec4(in_position.xy, 0.0, 1.0) + ); + gl_Position = vs_position; + +}