diff --git a/.gitignore b/.gitignore index eaaa3e4a61..ec3414bf7d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ include/openspace/version.h data/scene/67P/obj/67P_rotated_5_130.obj data/spice/NewHorizonsKernels/ data/spice/RosettaKernels/ +data/scene/plutoprojectionhybrid/textures/ data/scene/plutoprojectionhybrid/textures/Shenk_180.jpg data/scene/plutoprojectionhybrid/textures/barycenter.png data/scene/plutoprojectionhybrid/textures/defaultProj.png @@ -105,6 +106,7 @@ data/scene/newhorizons/models/NewHorizonsCleanModel.obj data/scene/newhorizons/textures/NHTextureFlipCol.jpg data/scene/newhorizons/textures/goldfoilbump.tif data/scene/newhorizons/textures/labels.png +data/scene/pluto/textures/ data/scene/pluto/textures/Shenk_180.jpg data/scene/pluto/textures/pluto_highres_180.jpg data/scene/plutoprojectionhybrid/assets/core_v9h_obs_getmets_v8_time_fix_nofrcd_mld.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e66e5517b..f006b1afb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ set(GHOUL_BASE_DIR "${OPENSPACE_BASE_DIR}/ext/ghoul") include(${OPENSPACE_CMAKE_EXT_DIR}/support_macros.cmake) include(${OPENSPACE_CMAKE_EXT_DIR}/module_common.cmake) -include(${GHOUL_BASE_DIR}/ext/CopySharedLibraries.cmake) +include(${GHOUL_BASE_DIR}/support/cmake/CopySharedLibraries.cmake) test_compiler_compatibility() cleanup_project() diff --git a/apps/Launcher/CMakeLists.txt b/apps/Launcher/CMakeLists.txt index 6e26370ce8..58fbf79702 100644 --- a/apps/Launcher/CMakeLists.txt +++ b/apps/Launcher/CMakeLists.txt @@ -25,7 +25,7 @@ set(APPLICATION_NAME Launcher) set(APPLICATION_LINK_TO_OPENSPACE ON) -include (${GHOUL_BASE_DIR}/ext/handle_external_library.cmake) +include (${GHOUL_BASE_DIR}/support/cmake/handle_external_library.cmake) set(application_path ${OPENSPACE_APPS_DIR}/Launcher) diff --git a/data/scene/debugglobe/debugglobe.mod b/data/scene/debugglobe/debugglobe.mod new file mode 100644 index 0000000000..0f6cad8b01 --- /dev/null +++ b/data/scene/debugglobe/debugglobe.mod @@ -0,0 +1,23 @@ +return { + -- DebugGlobe module + { + Name = "DebugGlobe", + Parent = "Root", + Renderable = { + Type = "RenderableGlobe", + Frame = "IAU_EARTH", + Body = "EARTH", + }, + Ephemeris = { + Type = "Spice", + Body = "EARTH", + Reference = "ECLIPJ2000", + Observer = "EARTH", + Kernels = { + "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp" + } + }, + GuiName = "/Solar/Planets/DebugGlobe" + }, + +} diff --git a/data/scene/debugglobe/earth.data b/data/scene/debugglobe/earth.data new file mode 100644 index 0000000000..240c1d5212 --- /dev/null +++ b/data/scene/debugglobe/earth.data @@ -0,0 +1,5 @@ +return { + FileRequest = { + { Identifier = "earth_textures", Destination = "textures", Version = 1 } + }, +} \ No newline at end of file diff --git a/data/scene/debugglobe/textures/ToastMapOfEarth.jpg b/data/scene/debugglobe/textures/ToastMapOfEarth.jpg new file mode 100644 index 0000000000..9064235622 Binary files /dev/null and b/data/scene/debugglobe/textures/ToastMapOfEarth.jpg differ diff --git a/data/scene/debugglobe/textures/earth_bluemarble.jpg b/data/scene/debugglobe/textures/earth_bluemarble.jpg new file mode 100644 index 0000000000..55b715d061 Binary files /dev/null and b/data/scene/debugglobe/textures/earth_bluemarble.jpg differ diff --git a/data/scene/debugglobe/textures/earth_bluemarble_height.jpg b/data/scene/debugglobe/textures/earth_bluemarble_height.jpg new file mode 100644 index 0000000000..6658823163 Binary files /dev/null and b/data/scene/debugglobe/textures/earth_bluemarble_height.jpg differ diff --git a/data/scene/debugglobe/textures/earth_night.jpg b/data/scene/debugglobe/textures/earth_night.jpg new file mode 100644 index 0000000000..bf1a1a483c Binary files /dev/null and b/data/scene/debugglobe/textures/earth_night.jpg differ diff --git a/data/scene/debugglobe/textures/marker.png b/data/scene/debugglobe/textures/marker.png new file mode 100644 index 0000000000..fc42c047b8 Binary files /dev/null and b/data/scene/debugglobe/textures/marker.png differ diff --git a/data/scene/earth/earth.mod b/data/scene/earth/earth.mod index aa5fcde2f5..987ed1f0be 100644 --- a/data/scene/earth/earth.mod +++ b/data/scene/earth/earth.mod @@ -25,9 +25,14 @@ return { Name = "Earth", Parent = "EarthBarycenter", Renderable = { - Type = "RenderableGlobe", + Type = "RenderablePlanet", Frame = "IAU_EARTH", Body = "EARTH", + Geometry = { + Type = "SimpleSphere", + Radius = { 6.371, 6 }, + Segments = 100 + }, Textures = { Type = "simple", Color = "textures/earth_bluemarble.jpg", @@ -67,4 +72,39 @@ return { }, GuiName = "/Solar/EarthTrail" }, + { + Name = "EarthMarker", + Parent = "Earth", + Renderable = { + Type = "RenderablePlane", + Size = {3.0, 11.0}, + Origin = "Center", + Billboard = true, + Texture = "textures/marker.png" + }, + Ephemeris = { + Type = "Static", + Position = {0, 0, 0, 5} + } + } + -- Plane + -- { + -- Name = "EarthPlane", + -- Parent = "Earth", + -- Renderable = { + -- Type = "RenderablePlane", + -- Billboard = true, + -- Size = { 6.371, 6 }, + -- Texture = "textures/graph.jpg", + -- Atmosphere = { + -- Type = "Nishita", -- for example, values missing etc etc + -- MieFactor = 1.0, + -- MieColor = {1.0, 1.0, 1.0} + -- } + -- }, + -- Ephemeris = { + -- Type = "Static", + -- Position = { 6.371*2, 0, 0, 6}, + -- }, + -- } } diff --git a/data/scene/planetbrowsing.scene b/data/scene/globebrowsing.scene similarity index 75% rename from data/scene/planetbrowsing.scene rename to data/scene/globebrowsing.scene index a32c4d732e..594cd7c5ed 100644 --- a/data/scene/planetbrowsing.scene +++ b/data/scene/globebrowsing.scene @@ -2,12 +2,11 @@ return { ScenePath = ".", CommonFolder = "common", Camera = { - Focus = "Earth", + Focus = "DebugGlobe", Position = {1, 0, 0, 5}, }, Modules = { - "sun", - "earth", + "debugglobe", "stars", "milkyway", } diff --git a/data/scene/toyvolume/toyvolume.mod b/data/scene/toyvolume/toyvolume.mod new file mode 100644 index 0000000000..2a432c2a5b --- /dev/null +++ b/data/scene/toyvolume/toyvolume.mod @@ -0,0 +1,51 @@ +return { + { + Name = "ToyVolume 1", + Parent = "Sun", + Ephemeris = { + Type = "Static", + Position = {0, 0, 0, 0} + }, + Renderable = { + Type = "RenderableToyVolume", + Color = {1.0, 0.0, 0.0, 0.7}, + Translation = {0, 0, 0}, + Rotation = {0.5, 0, 0}, + ScalingExponent = 11 + }, + GuiName = "/Volumes/ToyVolume1" + }, + { + Name = "ToyVolume 2", + Parent = "Earth", + Ephemeris = { + Type = "Static", + Position = {0, 0, 0, 0} + }, + Renderable = { + Type = "RenderableToyVolume", + Color = {1.0, 0.8, 0.0, 0.7}, + Translation = {0.0, 0.0, 0.0}, + Scaling = {5.0, 2.5, 5.0}, + ScalingExponent = 6 + }, + GuiName = "/Volumes/ToyVolume2" + }, + { + Name = "ToyVolume 3", + Parent = "Earth", + Ephemeris = { + Type = "Static", + Translation = {0, 0, 0, 0} + }, + Renderable = { + Type = "RenderableToyVolume", + Scaling = {2.0, 2.0, 2.0}, + Rotation = {3.14/2.0, 0, 0}, + Color = {1.0, 1.0, 1.0, 0.7}, + Translation = {0.0, 0.0, 0.0}, + ScalingExponent = 6 + }, + GuiName = "/Volumes/ToyVolume3" + } +} diff --git a/ext/ghoul b/ext/ghoul index ae36394e9c..849cc67bdc 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit ae36394e9c12ae302d88931ff6963998125f94cc +Subproject commit 849cc67bdc2550a43d8174490d39b14ee148b795 diff --git a/include/openspace/rendering/abufferrenderer.h b/include/openspace/rendering/abufferrenderer.h index 3f4f6af4bd..46d802f4fb 100644 --- a/include/openspace/rendering/abufferrenderer.h +++ b/include/openspace/rendering/abufferrenderer.h @@ -34,8 +34,11 @@ #include #include + #include #include +#include +#include namespace ghoul { @@ -54,7 +57,7 @@ class RenderableVolume; class Camera; class Scene; -class ABufferRenderer : public Renderer { +class ABufferRenderer : public Renderer, public RaycasterListener { public: ABufferRenderer(); virtual ~ABufferRenderer(); @@ -69,42 +72,52 @@ public: void update(); void render(float blackoutFactor, bool doPerformanceMeasurements) override; + /** * Update render data * Responsible for calling renderEngine::setRenderData */ virtual void updateRendererData() override; - + virtual void raycastersChanged(VolumeRaycaster& raycaster, bool attached) override; private: void clear(); void updateResolution(); - ghoul::Dictionary createResolveDictionary(); - std::unique_ptr createResolveProgram(const ghoul::Dictionary& dict); + void updateRaycastData(); + void updateResolveDictionary(); Camera* _camera; Scene* _scene; glm::ivec2 _resolution; + bool _dirtyResolution; + bool _dirtyRendererData; + bool _dirtyRaycastData; + bool _dirtyResolveDictionary; std::unique_ptr _resolveProgram; /** * When a volume is attached or detached from the scene graph, * the resolve program needs to be recompiled. - * The #_volumes vector keeps track of which volumes that can - * be rendered using the current resolve program. + * The #_volumes map keeps track of which volumes that can + * be rendered using the current resolve program, along with their raycast data + * (id, namespace, etc) */ - std::vector _volumes; + std::map _raycastData; + std::map> _boundsPrograms; + std::vector _helperPaths; - GLuint _screenQuad; - GLuint _anchorPointerTexture; - GLuint _anchorPointerTextureInitializer; - GLuint _atomicCounterBuffer; - GLuint _fragmentBuffer; - GLuint _fragmentTexture; - GLuint _vertexPositionBuffer; - int _nAaSamples; + ghoul::Dictionary _resolveDictionary; + + GLuint _screenQuad; + GLuint _anchorPointerTexture; + GLuint _anchorPointerTextureInitializer; + GLuint _atomicCounterBuffer; + GLuint _fragmentBuffer; + GLuint _fragmentTexture; + GLuint _vertexPositionBuffer; + int _nAaSamples; ghoul::Dictionary _rendererData; }; // ABufferRenderer diff --git a/include/openspace/rendering/framebufferrenderer.h b/include/openspace/rendering/framebufferrenderer.h index 2651189b48..01ec98b204 100644 --- a/include/openspace/rendering/framebufferrenderer.h +++ b/include/openspace/rendering/framebufferrenderer.h @@ -32,8 +32,9 @@ #include #include -#include +#include #include +#include namespace ghoul { class Dictionary; @@ -53,13 +54,16 @@ class RenderableVolume; class Camera; class Scene; -class FramebufferRenderer : public Renderer { +class FramebufferRenderer : public Renderer, public RaycasterListener { public: FramebufferRenderer(); virtual ~FramebufferRenderer(); void initialize() override; void deinitialize() override; + + void updateResolution(); + void updateRaycastData(); void setCamera(Camera* camera) override; void setScene(Scene* scene) override; @@ -73,11 +77,34 @@ public: * Responsible for calling renderEngine::setRenderData */ virtual void updateRendererData() override; + + virtual void raycastersChanged(VolumeRaycaster& raycaster, bool attached) override; private: + std::map _raycastData; + std::map> _exitPrograms; + std::map> _raycastPrograms; + + std::unique_ptr _resolveProgram; + + GLuint _screenQuad; + GLuint _vertexPositionBuffer; + GLuint _mainColorTexture; + GLuint _mainDepthTexture; + GLuint _exitColorTexture; + GLuint _mainFramebuffer; + GLuint _exitDepthTexture; + GLuint _exitFramebuffer; + + bool _dirtyRaycastData; + bool _dirtyResolution; + Camera* _camera; Scene* _scene; - glm::vec2 _resolution; + glm::vec2 _resolution; + int _nAaSamples; + + ghoul::Dictionary _rendererData; }; // FramebufferRenderer } // openspace diff --git a/include/openspace/rendering/raycasterlistener.h b/include/openspace/rendering/raycasterlistener.h new file mode 100644 index 0000000000..97a88b2d33 --- /dev/null +++ b/include/openspace/rendering/raycasterlistener.h @@ -0,0 +1,39 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __RAYCASTERLISTENER_H__ +#define __RAYCASTERLISTENER_H__ + +namespace openspace { + +class VolumeRaycaster; + +class RaycasterListener { +public: + virtual void raycastersChanged(VolumeRaycaster& raycaster, bool attached) = 0; +}; // RaycasterListener + +} // openspace + +#endif // __RAYCASTERLISTENER_H__ diff --git a/include/openspace/rendering/raycastermanager.h b/include/openspace/rendering/raycastermanager.h new file mode 100644 index 0000000000..18e2e7f35f --- /dev/null +++ b/include/openspace/rendering/raycastermanager.h @@ -0,0 +1,53 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __RAYCASTERMANAGER_H__ +#define __RAYCASTERMANAGER_H__ + +#include + +namespace openspace { + +class VolumeRaycaster; +class RaycasterListener; + +class RaycasterManager { +public: + RaycasterManager(); + ~RaycasterManager(); + void attachRaycaster(VolumeRaycaster& raycaster); + void detachRaycaster(VolumeRaycaster& raycaster); + bool isAttached(VolumeRaycaster& raycaster); + const std::vector& raycasters(); + + void addListener(RaycasterListener& listener); + void removeListener(RaycasterListener& listener); +private: + std::vector _raycasters; + std::vector _listeners; +}; // Volume + +} // openspace + +#endif // __RAYCASTERMANAGER_H__ diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 59c4a8b89c..89f31cc7cf 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -1,3 +1,4 @@ + /***************************************************************************************** * * * OpenSpace * @@ -29,7 +30,6 @@ #include #include #include -#include #include @@ -45,8 +45,7 @@ namespace ghoul { namespace openspace { // Forward declare to minimize dependencies -struct RenderData; -struct UpdateData; + class Camera; class PowerScaledCoordinate; @@ -68,9 +67,9 @@ public: void setBoundingSphere(const PowerScaledScalar& boundingSphere); const PowerScaledScalar& getBoundingSphere(); - virtual void render(const RenderData& data) = 0; + virtual void render(const RenderData& data); + virtual void render(const RenderData& data, RendererTasks& rendererTask); virtual void update(const UpdateData& data); - virtual std::vector volumesToRender(const RenderData& data) const; bool isVisible() const; @@ -81,12 +80,12 @@ public: bool getBody(std::string& body); void setBody(std::string& body); -protected: - void setPscUniforms(ghoul::opengl::ProgramObject* program, const Camera* camera, const PowerScaledCoordinate& position); + void onEnabledChange(std::function callback); + + static void setPscUniforms(ghoul::opengl::ProgramObject& program, const Camera& camera, const PowerScaledCoordinate& position); private: properties::BoolProperty _enabled; - PowerScaledScalar boundingSphere_; std::string _startTime; std::string _endTime; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 91aee642a1..3265817389 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -30,6 +30,7 @@ #include #include + namespace ghoul { namespace fontrendering { class Font; @@ -48,6 +49,7 @@ class Camera; class SyncBuffer; class Scene; class Renderer; +class RaycasterManager; class ScreenLog; class RenderEngine { @@ -75,6 +77,7 @@ public: Camera* camera() const; Renderer* renderer() const; RendererImplementation rendererImplementation() const; + RaycasterManager& raycasterManager(); // sgct wrapped functions bool initializeGL(); @@ -148,6 +151,8 @@ private: Camera* _mainCamera; Scene* _sceneGraph; + RaycasterManager* _raycasterManager; + std::unique_ptr _renderer; RendererImplementation _rendererImplementation; ghoul::Dictionary _rendererData; diff --git a/include/openspace/rendering/volumeraycaster.h b/include/openspace/rendering/volumeraycaster.h new file mode 100644 index 0000000000..5dfb480df8 --- /dev/null +++ b/include/openspace/rendering/volumeraycaster.h @@ -0,0 +1,125 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __VOLUMERAYCASTER_H__ +#define __VOLUMERAYCASTER_H__ + +#include +#include +#include + +namespace ghoul { + namespace opengl { + class Texture; + class ProgramObject; + } +} + +namespace openspace { + +class RenderData; +class RaycastData; + +class VolumeRaycaster { +public: + /** + * Destructor + */ + virtual ~VolumeRaycaster() {}; + + /** + * Render the volume's entry points (front face of the bounding geometry) + */ + virtual void renderEntryPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) = 0; + + /** + * Render the volume's exit points (back face of the bounding geometry) + */ + virtual void renderExitPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) = 0; + + /** + * Prepare the volume for the ABuffer's resolve step. + * Make sure textures are up to date, bind them to texture units, set program uniforms etc. + */ + virtual void preRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) {}; + + /** + * Clean up for the volume after the ABuffer's resolve step. + * Make sure texture units are deinitialized, etc. + */ + virtual void postRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) {}; + + /** + * Return a path the file to use as vertex shader + * + * The shader preprocessor will have acceess to + * A #{namespace} variable (unique per helper file) + */ + virtual std::string getBoundsVsPath() const = 0; + + /* + * Return a path to a file with the functions, uniforms and fragment shader in variables + * required to generate the fragment color and depth. + * + * Should define the function: + * Fragment getFragment() + * + * The shader preprocessor will have acceess to + * A #{namespace} variable (unique per helper file) + */ + virtual std::string getBoundsFsPath() const = 0 ; + + /** + * Return a path to a file with all the uniforms, functions etc + * required to perform ray casting through this volume. + * + * The header should define the following two functions: + * vec4 sample#{id}(vec3 samplePos, vec3 dir, float occludingAlpha, inout float maxStepSize) + * (return color of sample) + * float stepSize#{id}(vec3 samplePos, vec3 dir) + * (return the preferred step size at this sample position) + * + * The shader preprocessor will have acceess to + * An #{id} variable (unique per volume) + * A #{namespace} variable (unique per helper file) + */ + virtual std::string getRaycastPath() const = 0; + + /** + * Return a path to a glsl file with helper functions required for the + * transformation and raycast steps. + * This file will be included once per shader program generated, + * regardless of how many volumes say they require the file. + * Ideal to avoid redefinitions of helper functions. + * + * The shader preprocessor will have access to the #{namespace} variable (unique per helper file) + * which should be a prefix to all symbols defined by the helper + */ + virtual std::string getHelperPath() const = 0; + +}; // Raycaster + +} // openspace + +#endif // __VOLUMERAYCASTER_H__ diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 6d6a6d599b..f70bbcabfe 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -41,7 +41,6 @@ namespace openspace { -class Volume; class SceneGraphNode; // Notifications: @@ -83,12 +82,8 @@ public: /* * Render visible SceneGraphNodes using the provided camera */ - void render(const RenderData& data); + void render(const RenderData& data, RendererTasks& tasks); - /* - * Return a vector of volumes to render and their acciciated render data - */ - std::vector> volumesToRender(const RenderData& data) const; /* * Returns the root SceneGraphNode */ diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index b2977e5c37..0ae92c4713 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -66,7 +66,7 @@ public: void update(const UpdateData& data); void evaluate(const Camera* camera, const psc& parentPosition = psc()); - void render(const RenderData& data); + void render(const RenderData& data, RendererTasks& tasks); void updateCamera(Camera* camera) const; //void addNode(SceneGraphNode* child); @@ -90,7 +90,6 @@ public: void setRenderable(Renderable* renderable); const Renderable* renderable() const; Renderable* renderable(); - std::vector> volumesToRender(const RenderData& data) const; // @TODO Remove once the scalegraph is in effect ---abock void setEphemeris(Ephemeris* eph) { diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 83416ea1a7..1a2e43f1f2 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -30,6 +30,8 @@ namespace openspace { +class VolumeRaycaster; + struct InitializeData { }; @@ -47,6 +49,21 @@ struct RenderData { bool doPerformanceMeasurement; }; +struct RaycasterTask { + VolumeRaycaster* raycaster; + RenderData renderData; +}; + +struct RendererTasks { + std::vector raycasterTasks; +}; + +struct RaycastData { + int id; + std::string namespaceName; +}; + + } #endif // __UPDATESTRUCTURES_H__ diff --git a/modules/base/rendering/multimodelgeometry.cpp b/modules/base/rendering/multimodelgeometry.cpp index 6c37523a1c..3c28530276 100644 --- a/modules/base/rendering/multimodelgeometry.cpp +++ b/modules/base/rendering/multimodelgeometry.cpp @@ -67,6 +67,7 @@ namespace openspace { { Vertex vv; memcpy(vv.location, v.location, sizeof(GLfloat) * 3); + vv.location[3] = 0.0; memcpy(vv.tex, v.tex, sizeof(GLfloat) * 2); memcpy(vv.normal, v.normal, sizeof(GLfloat) * 3); _vertices.push_back(vv); diff --git a/modules/base/rendering/renderableconstellationbounds.cpp b/modules/base/rendering/renderableconstellationbounds.cpp index 0162740458..0dd67d5b8a 100644 --- a/modules/base/rendering/renderableconstellationbounds.cpp +++ b/modules/base/rendering/renderableconstellationbounds.cpp @@ -162,7 +162,7 @@ void RenderableConstellationBounds::render(const RenderData& data) { glm::mat4 viewMatrix = data.camera.viewMatrix(); glm::mat4 projectionMatrix = data.camera.projectionMatrix(); - setPscUniforms(_program.get(), &data.camera, data.position); + setPscUniforms(*_program.get(), data.camera, data.position); _program->setUniform("exponent", _distance); _program->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 2cedd9f929..f5a282e5b1 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -200,7 +200,7 @@ void RenderableModel::render(const RenderData& data) { _programObject->setUniform("sun_pos", _sunPosition.vec3()); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); _programObject->setUniform("_performShading", _performShading); diff --git a/modules/base/rendering/renderablepath.cpp b/modules/base/rendering/renderablepath.cpp index 327ccad32c..9a3db1f4dd 100644 --- a/modules/base/rendering/renderablepath.cpp +++ b/modules/base/rendering/renderablepath.cpp @@ -162,7 +162,7 @@ void RenderablePath::render(const RenderData& data) { _programObject->setUniform("ModelTransform", transform); _programObject->setUniform("color", _lineColor); _programObject->setUniform("lastPosition", _lastPosition); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); if (_drawLine) { glLineWidth(_lineWidth); diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index 348aa6b731..08af66a937 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -206,7 +206,7 @@ void RenderablePlane::render(const RenderData& data) { _shader->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _shader->setUniform("ModelTransform", transform); - setPscUniforms(_shader.get(), &data.camera, data.position); + setPscUniforms(*_shader.get(), data.camera, data.position); ghoul::opengl::TextureUnit unit; unit.activate(); diff --git a/modules/base/rendering/renderableplanet.cpp b/modules/base/rendering/renderableplanet.cpp index 08032110cf..25f4c201b4 100644 --- a/modules/base/rendering/renderableplanet.cpp +++ b/modules/base/rendering/renderableplanet.cpp @@ -213,7 +213,7 @@ void RenderablePlanet::render(const RenderData& data) _programObject->setUniform("transparency", _alpha); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); _programObject->setUniform("_performShading", _performShading); diff --git a/modules/base/rendering/renderablesphere.cpp b/modules/base/rendering/renderablesphere.cpp index 72e5ff6589..879086eb33 100644 --- a/modules/base/rendering/renderablesphere.cpp +++ b/modules/base/rendering/renderablesphere.cpp @@ -162,7 +162,7 @@ void RenderableSphere::render(const RenderData& data) { _shader->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _shader->setUniform("ModelTransform", transform); - setPscUniforms(_shader.get(), &data.camera, data.position); + setPscUniforms(*_shader.get(), data.camera, data.position); _shader->setUniform("alpha", _transparency); ghoul::opengl::TextureUnit unit; diff --git a/modules/base/rendering/renderablesphericalgrid.cpp b/modules/base/rendering/renderablesphericalgrid.cpp index a08f95ca81..8de5c30c83 100644 --- a/modules/base/rendering/renderablesphericalgrid.cpp +++ b/modules/base/rendering/renderablesphericalgrid.cpp @@ -212,7 +212,7 @@ void RenderableSphericalGrid::render(const RenderData& data){ _gridProgram->setIgnoreUniformLocationError(IgnoreError::Yes); _gridProgram->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _gridProgram->setUniform("ModelTransform", transform); - setPscUniforms(_gridProgram, &data.camera, data.position); + setPscUniforms(*_gridProgram, data.camera, data.position); _gridProgram->setUniform("gridColor", _gridColor); glLineWidth(0.5f); diff --git a/modules/base/rendering/renderablestars.cpp b/modules/base/rendering/renderablestars.cpp index e1d35fd81b..503eaa1c67 100644 --- a/modules/base/rendering/renderablestars.cpp +++ b/modules/base/rendering/renderablestars.cpp @@ -203,7 +203,7 @@ void RenderableStars::render(const RenderData& data) { _program->setUniform("scaleFactor", _scaleFactor); _program->setUniform("minBillboardSize", _minBillboardSize); - setPscUniforms(_program.get(), &data.camera, data.position); + setPscUniforms(*_program.get(), data.camera, data.position); _program->setUniform("scaling", scaling); ghoul::opengl::TextureUnit psfUnit; diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index cce8732c33..279792bb07 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -155,7 +155,7 @@ void RenderableTrail::render(const RenderData& data) { // setup the data to the shader _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); _programObject->setUniform("color", _lineColor); _programObject->setUniform("nVertices", static_cast(_vertexArray.size())); diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 67e7f01350..bf02729c03 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -25,17 +25,22 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableglobe.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/distanceswitch.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableglobe.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/distanceswitch.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/geometry.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gridgeometry.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/globemesh.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/latlonpatch.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/clipmapglobe.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/chunklodglobe.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/converter.h ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/chunknode.h ${CMAKE_CURRENT_SOURCE_DIR}/datastructures/chunknode.inl - ) -source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableglobe.cpp @@ -43,13 +48,16 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/geometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gridgeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/globemesh.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/latlonpatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/clipmapglobe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/chunklodglobe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/converter.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES - # ${CMAKE_CURRENT_SOURCE_DIR}/shaders/crawlingline_fs.glsl ) source_group("Shader Files" FILES ${SHADER_FILES}) diff --git a/modules/globebrowsing/rendering/clipmapglobe.cpp b/modules/globebrowsing/rendering/clipmapglobe.cpp new file mode 100644 index 0000000000..02ba1964de --- /dev/null +++ b/modules/globebrowsing/rendering/clipmapglobe.cpp @@ -0,0 +1,105 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 + +// open space includes +#include +#include +#include +#include + +// ghoul includes +#include + +#define _USE_MATH_DEFINES +#include + +namespace { + const std::string _loggerCat = "ClipMapGlobe"; + + const std::string keyFrame = "Frame"; + const std::string keyGeometry = "Geometry"; + const std::string keyShading = "PerformShading"; + + const std::string keyBody = "Body"; +} + +namespace openspace { + ClipMapGlobe::ClipMapGlobe(const ghoul::Dictionary& dictionary) + : _patch(10, 10, 0, 0, M_PI / 6, M_PI / 6) + , _rotation("rotation", "Rotation", 0, 0, 360) + { + std::string name; + bool success = dictionary.getValue(SceneGraphNode::KeyName, name); + ghoul_assert(success, + "ClipMapGlobe need the '" << SceneGraphNode::KeyName << "' be specified"); + setName(name); + + dictionary.getValue(keyFrame, _frame); + dictionary.getValue(keyBody, _target); + if (_target != "") + setBody(_target); + + // Mainly for debugging purposes @AA + addProperty(_rotation); + } + + ClipMapGlobe::~ClipMapGlobe() { + } + + bool ClipMapGlobe::initialize() { + _patch.initialize(); + return isReady(); + } + + bool ClipMapGlobe::deinitialize() { + _patch.deinitialize(); + return true; + } + + bool ClipMapGlobe::isReady() const { + bool ready = true; + ready &= _patch.isReady(); + return ready; + } + + void ClipMapGlobe::render(const RenderData& data) + { + // Set patch to follow camera + _patch.setPositionLatLon(converter::cartesianToLatLon(data.camera.position().dvec3())); + // render + _patch.render(data); + } + + void ClipMapGlobe::update(const UpdateData& data) { + _patch.update(data); + // set spice-orientation in accordance to timestamp + _stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); + _time = data.time; + } + +} // namespace openspace diff --git a/modules/globebrowsing/rendering/clipmapglobe.h b/modules/globebrowsing/rendering/clipmapglobe.h new file mode 100644 index 0000000000..6a5296f9ab --- /dev/null +++ b/modules/globebrowsing/rendering/clipmapglobe.h @@ -0,0 +1,72 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 __CLIPMAPGLOBE_H__ +#define __CLIPMAPGLOBE_H__ + +// open space includes +#include + +#include +#include + +#include +#include +#include +#include + +namespace ghoul { + namespace opengl { + class ProgramObject; + } +} + +namespace openspace { + + class ClipMapGlobe : public Renderable { + public: + ClipMapGlobe(const ghoul::Dictionary& dictionary); + ~ClipMapGlobe(); + + bool initialize() override; + bool deinitialize() override; + bool isReady() const override; + + void render(const RenderData& data) override; + void update(const UpdateData& data) override; + + private: + LatLonPatch _patch; + + properties::IntProperty _rotation; + + glm::dmat3 _stateMatrix; + std::string _frame; + std::string _target; + double _time; + }; + +} // namespace openspace + +#endif // __CLIPMAPGLOBE_H__ \ No newline at end of file diff --git a/modules/globebrowsing/rendering/globemesh.cpp b/modules/globebrowsing/rendering/globemesh.cpp index 0beddb14e4..5d7af17b10 100644 --- a/modules/globebrowsing/rendering/globemesh.cpp +++ b/modules/globebrowsing/rendering/globemesh.cpp @@ -48,8 +48,7 @@ namespace { namespace openspace { GlobeMesh::GlobeMesh(const ghoul::Dictionary& dictionary) - : DistanceSwitch() - , _programObject(nullptr) + : _programObject(nullptr) , _grid(10, 10, Geometry::Positions::Yes, Geometry::TextureCoordinates::No, Geometry::Normals::No) , _rotation("rotation", "Rotation", 0, 0, 360) { @@ -75,7 +74,6 @@ namespace openspace { RenderEngine& renderEngine = OsEng.renderEngine(); if (_programObject == nullptr) { - // Night texture program _programObject = renderEngine.buildRenderProgram( "simpleTextureProgram", "${MODULE_GLOBEBROWSING}/shaders/simple_vs.glsl", @@ -130,10 +128,13 @@ namespace openspace { // _programObject->setUniform("camdir", camSpaceEye); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + glm::dmat4 cameraTransform = data.camera.viewMatrix(); // TODO : NEEDS TO BE DOUBLE PRECISION + glm::dmat4 cameraProjectionTransform = data.camera.viewProjectionMatrix(); // TODO : NEEDS TO BE DOUBLE PRECISION + + glDisable(GL_CULL_FACE); + //glCullFace(GL_BACK); // render _grid.drawUsingActiveProgram(); diff --git a/modules/globebrowsing/rendering/globemesh.h b/modules/globebrowsing/rendering/globemesh.h index 0c28989ab1..bf435a2b7a 100644 --- a/modules/globebrowsing/rendering/globemesh.h +++ b/modules/globebrowsing/rendering/globemesh.h @@ -43,7 +43,7 @@ namespace ghoul { namespace openspace { - class GlobeMesh : public DistanceSwitch { + class GlobeMesh : public Renderable { public: GlobeMesh(const ghoul::Dictionary& dictionary); ~GlobeMesh(); diff --git a/modules/globebrowsing/rendering/latlonpatch.cpp b/modules/globebrowsing/rendering/latlonpatch.cpp new file mode 100644 index 0000000000..3fea6a51d2 --- /dev/null +++ b/modules/globebrowsing/rendering/latlonpatch.cpp @@ -0,0 +1,190 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 + +// open space includes +#include +#include +// ghoul includes +#include + +#define _USE_MATH_DEFINES +#include + +namespace { + const std::string _loggerCat = "LatLonPatch"; + + const std::string keyFrame = "Frame"; + const std::string keyGeometry = "Geometry"; + const std::string keyShading = "PerformShading"; + + const std::string keyBody = "Body"; +} + +namespace openspace { + LatLonPatch::LatLonPatch( + unsigned int xRes, + unsigned int yRes, + double posLat, + double posLon, + double sizeLat, + double sizeLon) + : _grid( + xRes, + yRes, + Geometry::Positions::No, + Geometry::TextureCoordinates::Yes, + Geometry::Normals::No) + , _programObject(nullptr) + , _posLatLon(posLat, posLon) + , _sizeLatLon(sizeLat, sizeLon) + { + + } + + LatLonPatch::~LatLonPatch() { + + } + + + bool LatLonPatch::initialize() { + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_programObject == nullptr) { + _programObject = renderEngine.buildRenderProgram( + "LatLonSphereMappingProgram", + "${MODULE_GLOBEBROWSING}/shaders/latlonpatch_spheremapping_vs.glsl", + "${MODULE_GLOBEBROWSING}/shaders/simple_fs.glsl"); + if (!_programObject) return false; + } + + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + + return isReady(); + } + + bool LatLonPatch::deinitialize() { + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_programObject) { + renderEngine.removeRenderProgram(_programObject); + _programObject = nullptr; + } + + return true; + } + + bool LatLonPatch::isReady() const { + bool ready = true; + ready &= (_programObject != nullptr); + return ready; + } + + void LatLonPatch::render(const RenderData& data) { + // activate shader + _programObject->activate(); + + // TODO : Not sure if double precision will be needed for all these calculations + // Using doubles in case but might slow things down. + // TODO : Need to get the radius of the globe + double r = 6e6; + + // Create control points (double) + glm::dvec3 p00, p01, p10, p11; + + // Calculate global positions of control points + p00 = glm::dvec3(converter::latLonToCartesian( + _posLatLon.x - _sizeLatLon.x, + _posLatLon.y - _sizeLatLon.y, + r)); + p10 = glm::dvec3(converter::latLonToCartesian( + _posLatLon.x + _sizeLatLon.x, + _posLatLon.y - _sizeLatLon.y, + r)); + p01 = glm::dvec3(converter::latLonToCartesian( + _posLatLon.x - _sizeLatLon.x, + _posLatLon.y + _sizeLatLon.y, + r)); + p11 = glm::dvec3(converter::latLonToCartesian( + _posLatLon.x + _sizeLatLon.x, + _posLatLon.y + _sizeLatLon.y, + r)); + + // TODO : Transformation to world space from model space should also consider + // rotations. Now it only uses translatation for simplicity. Should be done + // With a matrix transform + glm::dvec3 position = data.position.dvec3(); + p00 += position; + p10 += position; + p01 += position; + p11 += position; + + // Calculate global position of camera + // TODO : Should only need to fetch the camera transform and use directly + // Now the viewTransform is wrong due to the constant lookUpVector + glm::dvec3 camPos = data.camera.position().dvec3(); + glm::dvec3 camDir = glm::normalize(position - camPos); + glm::dvec3 camUp = glm::dvec3(0,1,0);// data.camera.lookUpVector(); + // Get camera transform matrix (double precision) + glm::dmat4 viewTransform = glm::inverse(glm::translate(glm::dmat4(1.0), camPos)); + //glm::dmat4 viewTransform = glm::lookAt(camPos, camPos + camDir, camUp); + viewTransform = glm::dmat4( data.camera.viewRotationMatrix()) * viewTransform; + // Transform control points to camera space + p00 = glm::dvec3(viewTransform * glm::dvec4(p00, 1.0)); + p10 = glm::dvec3(viewTransform * glm::dvec4(p10, 1.0)); + p01 = glm::dvec3(viewTransform * glm::dvec4(p01, 1.0)); + p11 = glm::dvec3(viewTransform * glm::dvec4(p11, 1.0)); + + // Send control points to GPU to be used in shader + // TODO : Will need more control points or possibly normals to be able to + // do better than linear interpolation + _programObject->setUniform("p00", glm::vec3(p00)); + _programObject->setUniform("p10", glm::vec3(p10)); + _programObject->setUniform("p01", glm::vec3(p01)); + _programObject->setUniform("p11", glm::vec3(p11)); + + _programObject->setUniform("Projection", data.camera.projectionMatrix()); + + // Render triangles (use texture coordinates to interpolate to new positions) + glDisable(GL_CULL_FACE); + //glCullFace(GL_BACK); + + // render + _grid.drawUsingActiveProgram(); + + // disable shader + _programObject->deactivate(); + } + + void LatLonPatch::update(const UpdateData& data) { + + } + + void LatLonPatch::setPositionLatLon(glm::dvec2 posLatLon) { + _posLatLon = posLatLon; + } + +} // namespace openspace diff --git a/modules/globebrowsing/rendering/latlonpatch.h b/modules/globebrowsing/rendering/latlonpatch.h new file mode 100644 index 0000000000..5267f8f0eb --- /dev/null +++ b/modules/globebrowsing/rendering/latlonpatch.h @@ -0,0 +1,73 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 __LATLONPATCH_H__ +#define __LATLONPATCH_H__ + +#include + +// open space includes +#include + +#include + +namespace ghoul { +namespace opengl { + class ProgramObject; +} +} + + +namespace openspace { + class LatLonPatch : public Renderable + { + public: + LatLonPatch( + unsigned int xRes, + unsigned int yRes, + double posLat, + double posLon, + double sizeLat, + double sizeLon); + ~LatLonPatch(); + + bool initialize() override; + bool deinitialize() override; + bool isReady() const override; + + void render(const RenderData& data) override; + void update(const UpdateData& data) override; + + void setPositionLatLon(glm::dvec2 posLatLon); + + private: + std::unique_ptr _programObject; + + glm::dvec2 _posLatLon; + glm::dvec2 _sizeLatLon; + GridGeometry _grid; + }; +} // namespace openspace + +#endif // __LATLONPATCH_H__ \ No newline at end of file diff --git a/modules/globebrowsing/rendering/renderableglobe.cpp b/modules/globebrowsing/rendering/renderableglobe.cpp index 2111cc8a28..b2270c3124 100644 --- a/modules/globebrowsing/rendering/renderableglobe.cpp +++ b/modules/globebrowsing/rendering/renderableglobe.cpp @@ -25,6 +25,7 @@ #include #include +#include // open space includes #include @@ -68,7 +69,8 @@ namespace openspace { // Mainly for debugging purposes @AA addProperty(_rotation); - addSwitchValue(std::shared_ptr(new GlobeMesh(dictionary)), 1000000000); + addSwitchValue(std::shared_ptr(new ClipMapGlobe(dictionary)), 1e9); + addSwitchValue(std::shared_ptr(new GlobeMesh(dictionary)), 1e10); } RenderableGlobe::~RenderableGlobe() { diff --git a/modules/globebrowsing/shaders/latlonpatch_spheremapping_vs.glsl b/modules/globebrowsing/shaders/latlonpatch_spheremapping_vs.glsl new file mode 100644 index 0000000000..541470d16b --- /dev/null +++ b/modules/globebrowsing/shaders/latlonpatch_spheremapping_vs.glsl @@ -0,0 +1,49 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * 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__ + +uniform mat4 Projection; + +uniform vec3 p00; +uniform vec3 p10; +uniform vec3 p01; +uniform vec3 p11; + +layout(location = 1) in vec2 in_UV; + +out vec4 vs_position; + +#include "PowerScaling/powerScaling_vs.hglsl" + +void main() +{ + // Bilinear interpolation + vec3 p0 = (1 - in_UV.x) * p00 + in_UV.x * p10; + vec3 p1 = (1 - in_UV.x) * p01 + in_UV.x * p11; + vec3 p = (1 - in_UV.y) * p0 + in_UV.y * p1; + + vec4 position = Projection * vec4(p, 1); + gl_Position = z_normalization(position); +} \ No newline at end of file diff --git a/modules/globebrowsing/shaders/simple_vs.glsl b/modules/globebrowsing/shaders/simple_vs.glsl index ae2870f620..718ebfd048 100644 --- a/modules/globebrowsing/shaders/simple_vs.glsl +++ b/modules/globebrowsing/shaders/simple_vs.glsl @@ -36,8 +36,8 @@ out vec4 vs_position; void main() { // set variables - vs_position = in_position; - vec4 tmp = in_position; + vs_position = vec4(in_position.xyz * 60000000.0f, 1); + vec4 tmp = vec4(in_position.xyz * 60000000.0f, 1); vec4 position = pscTransform(tmp, ModelTransform); vs_position = tmp; diff --git a/modules/globebrowsing/util/converter.cpp b/modules/globebrowsing/util/converter.cpp new file mode 100644 index 0000000000..e56f7b4291 --- /dev/null +++ b/modules/globebrowsing/util/converter.cpp @@ -0,0 +1,52 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 + +// ghoul includes +#include + +#define _USE_MATH_DEFINES +#include + +namespace openspace { + +namespace converter { + + glm::dvec3 latLonToCartesian(double latitude, double longitude, double radius) { + return radius * glm::dvec3( + glm::cos(latitude) * glm::cos(longitude), + glm::cos(latitude) * glm::sin(longitude), + glm::sin(latitude)); + } + + glm::dvec2 cartesianToLatLon(glm::dvec3 position) { + double r = glm::length(position); + double lat = glm::asin(position.z / r); + double lon = atan2(position.y, position.x); + return glm::vec2(lat, lon); + } + +} // namespace converter +} // namespace openspace diff --git a/modules/globebrowsing/util/converter.h b/modules/globebrowsing/util/converter.h new file mode 100644 index 0000000000..bedc7f1f45 --- /dev/null +++ b/modules/globebrowsing/util/converter.h @@ -0,0 +1,56 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2016 * +* * +* 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 __CONVERTER_H__ +#define __CONVERTER_H__ + +// open space includes +#include + +#include +#include + +#include +#include +#include + + +namespace ghoul { +namespace opengl { + class ProgramObject; +} +} + + +namespace openspace { + +namespace converter { + + glm::dvec3 latLonToCartesian(double latitude, double longitude, double radius); + glm::dvec2 cartesianToLatLon(glm::dvec3 position); + +} // namespace converter +} // namespace openspace + +#endif // __CONVERTER_H__ \ No newline at end of file diff --git a/modules/kameleon/CMakeLists.txt b/modules/kameleon/CMakeLists.txt index edc593869b..22b1e2c13b 100644 --- a/modules/kameleon/CMakeLists.txt +++ b/modules/kameleon/CMakeLists.txt @@ -72,5 +72,7 @@ create_new_module( endif () set_property(TARGET cdf PROPERTY FOLDER "External") endif () - +# Boost +find_package(Boost REQUIRED) +target_include_directories(openspace-module-kameleon SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) #include_external_library(${onscreengui_module} Imgui ${CMAKE_CURRENT_SOURCE_DIR}/ext/kameleon) diff --git a/modules/newhorizons/rendering/renderablecrawlingline.cpp b/modules/newhorizons/rendering/renderablecrawlingline.cpp index e2118342a3..2b63e17383 100644 --- a/modules/newhorizons/rendering/renderablecrawlingline.cpp +++ b/modules/newhorizons/rendering/renderablecrawlingline.cpp @@ -140,7 +140,7 @@ void RenderableCrawlingLine::render(const RenderData& data) { _program->setUniform("_alpha", alpha); _program->setUniform("color", _lineColor); - setPscUniforms(_program.get(), &data.camera, data.position); + setPscUniforms(*_program.get(), data.camera, data.position); glBindVertexArray(_vao); glBindBuffer(GL_ARRAY_BUFFER, _vbo); diff --git a/modules/newhorizons/rendering/renderablefov.cpp b/modules/newhorizons/rendering/renderablefov.cpp index bac5f40e02..d0c5cbb91c 100644 --- a/modules/newhorizons/rendering/renderablefov.cpp +++ b/modules/newhorizons/rendering/renderablefov.cpp @@ -549,7 +549,7 @@ void RenderableFov::render(const RenderData& data) { // setup the data to the shader _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", glm::mat4(1)); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); if (openspace::ImageSequencer2::ref().isReady()) _drawFOV = ImageSequencer2::ref().instrumentActive(_instrumentID); diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index 70a0758ae2..5ecbc90ccd 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -331,7 +331,7 @@ void RenderableModelProjection::render(const RenderData& data) { _viewProjection = data.camera.viewProjectionMatrix(); _programObject->setUniform("ViewProjection", _viewProjection); _programObject->setUniform("ModelTransform", _transform); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); textureBind(); _geometry->render(); diff --git a/modules/newhorizons/rendering/renderableplaneprojection.cpp b/modules/newhorizons/rendering/renderableplaneprojection.cpp index 9dd45d40a8..a0b928c17d 100644 --- a/modules/newhorizons/rendering/renderableplaneprojection.cpp +++ b/modules/newhorizons/rendering/renderableplaneprojection.cpp @@ -147,7 +147,7 @@ void RenderablePlaneProjection::render(const RenderData& data) { _shader->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _shader->setUniform("ModelTransform", transform); - setPscUniforms(_shader.get(), &data.camera, data.position); + setPscUniforms(*_shader.get(), data.camera, data.position); ghoul::opengl::TextureUnit unit; unit.activate(); diff --git a/modules/newhorizons/rendering/renderableplanetprojection.cpp b/modules/newhorizons/rendering/renderableplanetprojection.cpp index 23367c0b70..383516051c 100644 --- a/modules/newhorizons/rendering/renderableplanetprojection.cpp +++ b/modules/newhorizons/rendering/renderableplanetprojection.cpp @@ -541,7 +541,7 @@ void RenderablePlanetProjection::render(const RenderData& data){ _programObject->setUniform("ViewProjection" , data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform" , _transform); _programObject->setUniform("boresight" , _boresight); - setPscUniforms(_programObject.get(), &data.camera, data.position); + setPscUniforms(*_programObject.get(), data.camera, data.position); textureBind(); diff --git a/modules/newhorizons/rendering/renderableshadowcylinder.cpp b/modules/newhorizons/rendering/renderableshadowcylinder.cpp index a6aa0bb07f..062706fd3a 100644 --- a/modules/newhorizons/rendering/renderableshadowcylinder.cpp +++ b/modules/newhorizons/rendering/renderableshadowcylinder.cpp @@ -136,7 +136,7 @@ void RenderableShadowCylinder::render(const RenderData& data){ _shader->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _shader->setUniform("ModelTransform", _transform); _shader->setUniform("shadowColor", _shadowColor); - setPscUniforms(_shader.get(), &data.camera, data.position); + setPscUniforms(*_shader.get(), data.camera, data.position); glBindVertexArray(_vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast(_vertices.size())); diff --git a/modules/toyvolume/CMakeLists.txt b/modules/toyvolume/CMakeLists.txt new file mode 100644 index 0000000000..56d52a4d2f --- /dev/null +++ b/modules/toyvolume/CMakeLists.txt @@ -0,0 +1,43 @@ +######################################################################################### +# # +# OpenSpace # +# # +# Copyright (c) 2014-2016 # +# # +# 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_CMAKE_EXT_DIR}/module_definition.cmake) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderabletoyvolume.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/toyvolumeraycaster.h +) +source_group("Header Files" FILES ${HEADER_FILES}) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderabletoyvolume.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/toyvolumeraycaster.cpp +) +source_group("Source Files" FILES ${SOURCE_FILES}) + +create_new_module( + "ToyVolume" + toyvolume_module + ${HEADER_FILES} ${SOURCE_FILES} +) diff --git a/modules/toyvolume/include.cmake b/modules/toyvolume/include.cmake new file mode 100644 index 0000000000..3ccace7c97 --- /dev/null +++ b/modules/toyvolume/include.cmake @@ -0,0 +1 @@ +set (DEFAULT_MODULE ON) diff --git a/modules/toyvolume/rendering/renderabletoyvolume.cpp b/modules/toyvolume/rendering/renderabletoyvolume.cpp new file mode 100644 index 0000000000..59c93d426f --- /dev/null +++ b/modules/toyvolume/rendering/renderabletoyvolume.cpp @@ -0,0 +1,140 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 + + +namespace { + const std::string GlslRayCastPath = "${MODULES}/toyvolume/shaders/rayCast.glsl"; + const std::string GlslBoundsVsPath = "${MODULES}/toyvolume/shaders/boundsVs.glsl"; + const std::string GlslBoundsFsPath = "${MODULES}/toyvolume/shaders/boundsFs.glsl"; +} + +namespace openspace { + + RenderableToyVolume::RenderableToyVolume(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _scalingExponent("scalingExponent", "Scaling Exponent", 1, -10, 20) + , _stepSize("stepSize", "Step Size", 0.02, 0.01, 1) + , _scaling("scaling", "Scaling", glm::vec3(1.0, 1.0, 1.0), glm::vec3(0.0), glm::vec3(10.0)) + , _translation("translation", "Translation", glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0), glm::vec3(10.0)) + , _rotation("rotation", "Euler rotation", glm::vec3(0.0, 0.0, 0.0), glm::vec3(0), glm::vec3(6.28)) + , _color("color", "Color", glm::vec4(1.0, 0.0, 0.0, 0.1), glm::vec4(0.0), glm::vec4(1.0)) { + + float scalingExponent, stepSize; + glm::vec3 scaling, translation, rotation; + glm::vec4 color; + if (dictionary.getValue("ScalingExponent", scalingExponent)) { + _scalingExponent = scalingExponent; + } + if (dictionary.getValue("Scaling", scaling)) { + _scaling = scaling; + } + if (dictionary.getValue("Translation", translation)) { + _translation = translation; + } + if (dictionary.getValue("Rotation", rotation)) { + _rotation = rotation; + } + if (dictionary.getValue("Color", color)) { + _color = color; + } + if (dictionary.getValue("StepSize", stepSize)) { + _stepSize = stepSize; + } +} + +RenderableToyVolume::~RenderableToyVolume() {} + +bool RenderableToyVolume::initialize() { + _raycaster = std::make_unique(ToyVolumeRaycaster(_color)); + _raycaster->initialize(); + + OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get()); + + std::function onChange = [&](bool enabled) { + if (enabled) { + OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get()); + } + else { + OsEng.renderEngine().raycasterManager().detachRaycaster(*_raycaster.get()); + } + }; + + onEnabledChange(onChange); + + addProperty(_scaling); + addProperty(_scalingExponent); + addProperty(_stepSize); + addProperty(_translation); + addProperty(_rotation); + addProperty(_color); + + return true; +} + +bool RenderableToyVolume::deinitialize() { + if (_raycaster) { + OsEng.renderEngine().raycasterManager().detachRaycaster(*_raycaster.get()); + _raycaster = nullptr; + } + return true; +} + +bool RenderableToyVolume::isReady() const { + return true; +} + +void RenderableToyVolume::update(const UpdateData& data) { + if (_raycaster) { + + glm::mat4 transform = glm::translate(glm::mat4(1.0), static_cast(_translation) * std::pow(10.0f, static_cast(_scalingExponent))); + glm::vec3 eulerRotation = static_cast(_rotation); + transform = glm::rotate(transform, eulerRotation.x, glm::vec3(1, 0, 0)); + transform = glm::rotate(transform, eulerRotation.y, glm::vec3(0, 1, 0)); + transform = glm::rotate(transform, eulerRotation.z, glm::vec3(0, 0, 1)); + transform = glm::scale(transform, static_cast(_scaling) * std::pow(10.0f, static_cast(_scalingExponent))); + + _raycaster->setColor(_color); + _raycaster->setStepSize(_stepSize); + _raycaster->setModelTransform(transform); + _raycaster->setTime(data.time); + } +} + +void RenderableToyVolume::render(const RenderData& data, RendererTasks& tasks) { + RaycasterTask task{ _raycaster.get(), data }; + tasks.raycasterTasks.push_back(task); +} + +} diff --git a/modules/toyvolume/rendering/renderabletoyvolume.h b/modules/toyvolume/rendering/renderabletoyvolume.h new file mode 100644 index 0000000000..9c08f1af14 --- /dev/null +++ b/modules/toyvolume/rendering/renderabletoyvolume.h @@ -0,0 +1,62 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __RENDERABLETOYVOLUME_H__ +#define __RENDERABLETOYVOLUME_H__ + +#include +#include +#include + +#include +#include + +namespace openspace { + +struct RenderData; + +class RenderableToyVolume : public Renderable { +public: + RenderableToyVolume(const ghoul::Dictionary& dictionary); + ~RenderableToyVolume(); + + bool initialize() override; + bool deinitialize() override; + bool isReady() const override; + void render(const RenderData& data, RendererTasks& tasks) override; + void update(const UpdateData& data) override; + +private: + properties::Vec3Property _scaling; + properties::IntProperty _scalingExponent; + properties::FloatProperty _stepSize; + properties::Vec3Property _translation; + properties::Vec3Property _rotation; + properties::Vec4Property _color; + + std::unique_ptr _raycaster; +}; +} + +#endif // __RENDERABLETOYVOLUME_H__ diff --git a/modules/toyvolume/rendering/toyvolumeraycaster.cpp b/modules/toyvolume/rendering/toyvolumeraycaster.cpp new file mode 100644 index 0000000000..8687f93744 --- /dev/null +++ b/modules/toyvolume/rendering/toyvolumeraycaster.cpp @@ -0,0 +1,131 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 + +namespace { + const std::string GlslRaycastPath = "${MODULES}/toyvolume/shaders/raycast.glsl"; + const std::string GlslBoundsVsPath = "${MODULES}/toyvolume/shaders/boundsVs.glsl"; + const std::string GlslBoundsFsPath = "${MODULES}/toyvolume/shaders/boundsFs.glsl"; +} + +namespace openspace { + +ToyVolumeRaycaster::ToyVolumeRaycaster(glm::vec4 color) + : _boundingBox(glm::vec3(1.0)) + , _color(color) {} + +ToyVolumeRaycaster::~ToyVolumeRaycaster() {} + +void ToyVolumeRaycaster::initialize() { + _boundingBox.initialize(); +} + +void ToyVolumeRaycaster::deinitialize() { +} + +void ToyVolumeRaycaster::renderEntryPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) { + program.setUniform("modelTransform", _modelTransform); + program.setUniform("viewProjection", data.camera.viewProjectionMatrix()); + Renderable::setPscUniforms(program, data.camera, data.position); + + // Cull back face + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // Render bounding geometry + _boundingBox.render(); +} + +void ToyVolumeRaycaster::renderExitPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) { + // Uniforms + program.setUniform("modelTransform", _modelTransform); + program.setUniform("viewProjection", data.camera.viewProjectionMatrix()); + Renderable::setPscUniforms(program, data.camera, data.position); + + // Cull front face + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + // Render bounding geometry + _boundingBox.render(); + + // Restore defaults + glCullFace(GL_BACK); +} + +void ToyVolumeRaycaster::preRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) { + std::string colorUniformName = "color" + std::to_string(data.id); + std::string timeUniformName = "time" + std::to_string(data.id); + std::string stepSizeUniformName = "maxStepSize" + std::to_string(data.id); + program.setUniform(colorUniformName, _color); + program.setUniform(stepSizeUniformName, _stepSize); + program.setUniform(timeUniformName, static_cast(std::fmod(_time, 3600.0))); +} + +void ToyVolumeRaycaster::postRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) { + // For example: release texture units +} + +std::string ToyVolumeRaycaster::getBoundsVsPath() const { + return GlslBoundsVsPath; +} + +std::string ToyVolumeRaycaster::getBoundsFsPath() const { + return GlslBoundsFsPath; +} + +std::string ToyVolumeRaycaster::getRaycastPath() const { + return GlslRaycastPath; +} + +std::string ToyVolumeRaycaster::getHelperPath() const { + return ""; // no helper file +} + +void ToyVolumeRaycaster::setColor(glm::vec4 color) { + _color = color; +} + +void ToyVolumeRaycaster::setModelTransform(glm::mat4 transform) { + _modelTransform = transform; +} + +void ToyVolumeRaycaster::setTime(double time) { + _time = time; +} + +void ToyVolumeRaycaster::setStepSize(float stepSize) { + _stepSize = stepSize; +} + +} diff --git a/modules/toyvolume/rendering/toyvolumeraycaster.h b/modules/toyvolume/rendering/toyvolumeraycaster.h new file mode 100644 index 0000000000..4924276a20 --- /dev/null +++ b/modules/toyvolume/rendering/toyvolumeraycaster.h @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __TOYVOLUMERAYCASTER_H__ +#define __TOYVOLUMERAYCASTER_H__ + +#include +#include +#include +#include +#include +#include + +namespace ghoul { + namespace opengl { + class Texture; + class ProgramObject; + } +} + +namespace openspace { + +class RenderData; +class RaycastData; + +class ToyVolumeRaycaster : public VolumeRaycaster { +public: + + ToyVolumeRaycaster(glm::vec4 color); + + virtual ~ToyVolumeRaycaster(); + void initialize(); + void deinitialize(); + void renderEntryPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) override; + void renderExitPoints(const RenderData& data, ghoul::opengl::ProgramObject& program) override; + void preRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) override; + void postRaycast(const RaycastData& data, ghoul::opengl::ProgramObject& program) override; + + std::string getBoundsVsPath() const override; + std::string getBoundsFsPath() const override; + std::string getRaycastPath() const override; + std::string getHelperPath() const override; + + void setColor(glm::vec4 color); + void setModelTransform(glm::mat4 transform); + void setTime(double time); + void setStepSize(float time); +private: + BoxGeometry _boundingBox; + glm::vec4 _color; + glm::mat4 _modelTransform; + float _stepSize; + double _time; + +}; // ToyVolumeRaycaster + +} // openspace + +#endif // __TOYVOLUMERAYCASTER_H__ diff --git a/modules/toyvolume/shaders/boundsFs.glsl b/modules/toyvolume/shaders/boundsFs.glsl new file mode 100644 index 0000000000..34b184df57 --- /dev/null +++ b/modules/toyvolume/shaders/boundsFs.glsl @@ -0,0 +1,40 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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. * + ****************************************************************************************/ + +in vec3 vPosition; +in vec4 worldPosition; + +#include "PowerScaling/powerScaling_fs.hglsl" +#include "fragment.glsl" + +Fragment getFragment() { + vec4 fragColor = vec4(vPosition+0.5, 1.0); + vec4 position = worldPosition; + float depth = pscDepth(position); + + Fragment frag; + frag.color = fragColor; + frag.depth = depth; + return frag; +} diff --git a/modules/toyvolume/shaders/boundsVs.glsl b/modules/toyvolume/shaders/boundsVs.glsl new file mode 100644 index 0000000000..fc328f30df --- /dev/null +++ b/modules/toyvolume/shaders/boundsVs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2016 * + * * + * 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__ + +layout(location = 0) in vec4 vertPosition; + +uniform mat4 viewProjection; +uniform mat4 modelTransform; + +out vec3 vPosition; +out vec4 worldPosition; + +#include "PowerScaling/powerScaling_vs.hglsl" + +void main() { + vPosition = vertPosition.xyz; + worldPosition = modelTransform*vertPosition; + + vec4 position = pscTransform(worldPosition, mat4(1.0)); + + // project the position to view space + gl_Position = viewProjection * position; + + gl_Position.z = 1.0; +} diff --git a/modules/toyvolume/shaders/raycast.glsl b/modules/toyvolume/shaders/raycast.glsl new file mode 100644 index 0000000000..e78478f058 --- /dev/null +++ b/modules/toyvolume/shaders/raycast.glsl @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2016 * + * * + * 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. * + ****************************************************************************************/ + + +uniform vec4 color#{id}; +uniform float time#{id}; +uniform float maxStepSize#{id} = 0.02; + +vec4 sample#{id}(vec3 samplePos, vec3 dir, vec4 foregroundColor, inout float maxStepSize) { + maxStepSize = maxStepSize#{id}; + + // Generate an arbitrary procedural volume. + // In real situations, the sample function would sample a + // 3D texture to retrieve the color contribution of a given point. + + vec3 fromCenter = vec3(0.5, 0.5, 0.5) - samplePos; + + vec4 c = color#{id}; + float r = length(fromCenter); + c.a *= (1.0 - smoothstep(0.4, 0.45, r)); + c.a *= (1.0 - smoothstep(0.35, 0.3, r)); + c.a *= (1.0 - smoothstep(0.1, 0.2, abs(fromCenter.y))); + + float theta = atan(fromCenter.x, fromCenter.z); + float angularRatio = (theta + 3.1415) / 6.283; + + angularRatio = mod(angularRatio + time#{id}*0.01, 1.0); + + c.a *= smoothstep(0.0, 0.2, clamp(angularRatio, 0.0, 1.0)); + c.a *= smoothstep(1.0, 0.8, clamp(angularRatio, 0.0, 1.0)); + + return c; +} + +float stepSize#{id}(vec3 samplePos, vec3 dir) { + return maxStepSize#{id}; +} diff --git a/modules/toyvolume/toyvolumemodule.cpp b/modules/toyvolume/toyvolumemodule.cpp new file mode 100644 index 0000000000..77b65bf4ed --- /dev/null +++ b/modules/toyvolume/toyvolumemodule.cpp @@ -0,0 +1,44 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 + +namespace openspace { + +ToyVolumeModule::ToyVolumeModule() : OpenSpaceModule("ToyVolume") {} + +void ToyVolumeModule::internalInitialize() { + auto fRenderable = FactoryManager::ref().factory(); + ghoul_assert(fRenderable, "No renderable factory existed"); + fRenderable->registerClass("RenderableToyVolume"); +} + +} // namespace openspace diff --git a/modules/toyvolume/toyvolumemodule.h b/modules/toyvolume/toyvolumemodule.h new file mode 100644 index 0000000000..510156fef2 --- /dev/null +++ b/modules/toyvolume/toyvolumemodule.h @@ -0,0 +1,40 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __TOYVOLUMEMODULE_H__ +#define __TOYVOLUMEMODULE_H__ + +#include + +namespace openspace { + +class ToyVolumeModule : public OpenSpaceModule { +public: + ToyVolumeModule(); + void internalInitialize() override; +}; + +} // namespace openspace + +#endif // __TOYVOLUMEMODULE_H__ diff --git a/openspace.cfg b/openspace.cfg index 3e5e251fc2..5fc1a77c02 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -12,7 +12,7 @@ return { -- Scene = "${SCENE}/default-modified.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", - Scene = "${SCENE}/planetbrowsing.scene", + Scene = "${SCENE}/globebrowsing.scene", Paths = { SGCT = "${BASE_PATH}/config/sgct", diff --git a/shaders/PowerScaling/powerScalingMath.hglsl b/shaders/PowerScaling/powerScalingMath.hglsl index 9c72f299e3..2fb96797f9 100644 --- a/shaders/PowerScaling/powerScalingMath.hglsl +++ b/shaders/PowerScaling/powerScalingMath.hglsl @@ -88,4 +88,82 @@ vec4 z_normalization(vec4 v_in) { return v_out; } +/** + * Compute the length of a vector. + * Supporting huge vectors, where the square of any of the components is too large to represent as a float. + */ +float safeLength(vec4 v) { + float m = max(max(max(abs(v.x), abs(v.y)), abs(v.z)), abs(v.w)); + if (m > 0.0) { + return length(v / m) * m; + } else { + return 0; + } +} + +float safeLength(vec3 v) { + float m = max(max(abs(v.x), abs(v.y)), abs(v.z)); + if (m > 0.0) { + return length(v / m) * m; + } else { + return 0; + } +} + +float safeLength(vec2 v) { + float m = max(abs(v.x), abs(v.y)); + if (m > 0.0) { + return length(v / m) * m; + } else { + return 0; + } +} + +/** + * Normalize a vector + * Supporting huge vectors, where the square of any of the components is too large to represent as a float. + */ +vec3 safeNormalize(vec3 v) { + float m = max(max(abs(v.x), abs(v.y)), abs(v.z)); + return normalize(v / m); +} + + +/** + * Convert a psc vector to a float + */ +vec3 pscToLinear(vec4 position) { + return pow(k, position.w) * position.xyz; +} + +/** + * Convert a psc scalar to a float + */ +float pscToLinear(vec2 position) { + return pow(k, position.y) * position.x; +} + +/** + * Convert a positive floating point distance [0, 10^27] + * (size of observable universe) + * to a float in the range [-1, 1], suitable for depth buffer storage. + * Note: This needs to be a monotonic function, so that the value can + * still be used for depth comparison. + */ +float normalizeFloat(float inpt) { + if (inpt > 1.0) { + return inpt / pow(10, 27); + } else { + return inpt - 1.0; + } +} + +float denormalizeFloat(float inpt) { + if (inpt < 0.0) { + return inpt + 1.0; + } else { + return inpt * pow(10, 27); + } +} + #endif diff --git a/shaders/PowerScaling/powerScaling_fs.hglsl b/shaders/PowerScaling/powerScaling_fs.hglsl index 2971be8d6a..7aec0d5398 100644 --- a/shaders/PowerScaling/powerScaling_fs.hglsl +++ b/shaders/PowerScaling/powerScaling_fs.hglsl @@ -47,11 +47,15 @@ vec4 psc_normlization(vec4 invec) { } } + + float pscDepth(vec4 position) { // For now: simply convert power scaled coordinates to a linear scale. // TODO: get rid of power scaled coordinates and use scale graph instead. - return (position.w + log(abs(position.z) + 1/pow(k, position.w))/log(k)) / 27.0; + // return (position.w + log(abs(position.z) + 1/pow(k, position.w))/log(k)) / 27.0; + return safeLength(pscToLinear(position)); } + #endif diff --git a/shaders/abuffer/abufferfragment.glsl b/shaders/abuffer/abufferfragment.glsl index 77c68cc87d..eb4eef87c7 100644 --- a/shaders/abuffer/abufferfragment.glsl +++ b/shaders/abuffer/abufferfragment.glsl @@ -41,7 +41,7 @@ struct ABufferFragment { // -------DEPTH------- // depth 32 bits // -------DATA-------- -// type 8 bits 0: geometry, >0: volume, <0: reserved +// type 8 bits (signed char) 0: geometry, >0: volume entry, <0: volume exit // msaa 8 bits // reserved 16 bits // ----COMPOSITION---- @@ -104,13 +104,22 @@ float _depth_(ABufferFragment frag) { * Type */ void _type_(inout ABufferFragment frag, int type) { - uint val = uint(type); + uint val; + if (type < 0) { + val = uint(-type) + 128; + } else { + val = type; + } bitinsert(frag.data, val, mask_type, shift_type); } int _type_(ABufferFragment frag) { uint val = bitextract(frag.data, mask_type, shift_type); - return int(val); + if (val > 127) { + return 128 - int(val); + } else { + return int(val); + } } /** diff --git a/shaders/abuffer/abufferresources.glsl b/shaders/abuffer/abufferresources.glsl index cea67bb69a..60abbe48f9 100644 --- a/shaders/abuffer/abufferresources.glsl +++ b/shaders/abuffer/abufferresources.glsl @@ -25,16 +25,15 @@ #ifndef _ABUFFERRESOURCES_GLSL_ #define _ABUFFERRESOURCES_GLSL_ +#include "abufferfragment.glsl" #define MAX_LAYERS #{rendererData.maxLayers} -#include "abufferfragment.glsl" +ABufferFragment fragments[MAX_LAYERS]; layout (binding = 0, r32ui) uniform uimage2D anchorPointerTexture; layout (binding = 1, rgba32ui) uniform uimageBuffer fragmentTexture; layout (binding = 0, offset = 0) uniform atomic_uint atomicCounterBuffer; -ABufferFragment fragments[MAX_LAYERS]; -uint indices[MAX_LAYERS]; const uint NULL_POINTER = 0; void storeFragment(uint index, ABufferFragment aBufferFrag) { @@ -50,17 +49,15 @@ ABufferFragment loadFragment(uint index) { /** * Load fragments into the #fragments array. - * Also set #indices to the used indices. */ uint loadFragments() { uint currentIndex = imageLoad(anchorPointerTexture, ivec2(gl_FragCoord.xy)).x; int nFrags = 0; while (currentIndex != NULL_POINTER && nFrags < MAX_LAYERS) { ABufferFragment frag = loadFragment(currentIndex); - indices[nFrags] = currentIndex; fragments[nFrags] = frag; - nFrags++; currentIndex = _next_(frag); + nFrags++; } return nFrags; } diff --git a/shaders/abuffer/boundsabuffer.frag b/shaders/abuffer/boundsabuffer.frag new file mode 100644 index 0000000000..0253e74da1 --- /dev/null +++ b/shaders/abuffer/boundsabuffer.frag @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 - 2016 * + * * + * 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 "fragment.glsl" +#include <#{fragmentPath}> +#include "abufferfragment.glsl" +#include "abufferresources.glsl" + +uniform bool _exit_; +out vec4 _out_color_; + +void main() { + Fragment frag = getFragment(); + + int sampleMask = gl_SampleMaskIn[0]; + + uint newHead = atomicCounterIncrement(atomicCounterBuffer); + uint prevHead = imageAtomicExchange(anchorPointerTexture, ivec2(gl_FragCoord.xy), newHead); + + ABufferFragment aBufferFrag; + _color_(aBufferFrag, frag.color); + _depth_(aBufferFrag, frag.depth); + + int fragmentType = #{fragmentType}; + + if (_exit_) { + fragmentType *= -1; + } + + _type_(aBufferFrag, fragmentType); + _msaa_(aBufferFrag, gl_SampleMaskIn[0]); + + _next_(aBufferFrag, prevHead); + + storeFragment(newHead, aBufferFrag); + discard; +} diff --git a/shaders/abuffer/raycasterdata.glsl b/shaders/abuffer/raycasterdata.glsl new file mode 100644 index 0000000000..5176f5342a --- /dev/null +++ b/shaders/abuffer/raycasterdata.glsl @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 - 2016 * + * * + * 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 _RAYCASTERDATA_GLSL_ +#define _RAYCASTERDATA_GLSL_ + +struct RaycasterData { + vec3 position; + vec3 direction; + float scale; + float previousJitterDistance; +} + +#endif diff --git a/shaders/abuffer/renderabuffer.frag b/shaders/abuffer/renderabuffer.frag index f698b39720..db12828a6c 100644 --- a/shaders/abuffer/renderabuffer.frag +++ b/shaders/abuffer/renderabuffer.frag @@ -35,6 +35,9 @@ void main() { int sampleMask = gl_SampleMaskIn[0]; uint newHead = atomicCounterIncrement(atomicCounterBuffer); + if (newHead >= #{rendererData.maxTotalFragments}) { + discard; // ABuffer is full! + } uint prevHead = imageAtomicExchange(anchorPointerTexture, ivec2(gl_FragCoord.xy), newHead); ABufferFragment aBufferFrag; diff --git a/shaders/abuffer/resolveabuffer.frag b/shaders/abuffer/resolveabuffer.frag index 556cfeca3a..bda831088c 100644 --- a/shaders/abuffer/resolveabuffer.frag +++ b/shaders/abuffer/resolveabuffer.frag @@ -27,32 +27,52 @@ #include "abufferfragment.glsl" #include "abufferresources.glsl" #include "fragment.glsl" +#include "PowerScaling/powerScalingMath.hglsl" +#include "blending.glsl" +#include "rand.glsl" layout (location = 0) out vec4 finalColor; uniform float blackoutFactor; uniform int nAaSamples; -void sortFragments(uint nFrags) { - ABufferFragment tmp; - uint i, j; - - // Insertion sort - for(i = 1; i < nFrags; ++i) { - tmp = fragments[i]; - for(j = i; j > 0 && _depth_(tmp) < _depth_(fragments[j-1]); --j) { - fragments[j] = fragments[j-1]; - } - fragments[j] = tmp; - } -} +#define RAYCASTING_ENABLED #{raycastingEnabled} +#define N_RAYCASTERS #{nRaycasters} +#define ALPHA_LIMIT 0.99 +#define RAYCAST_MAX_STEPS 1000 +#define INT_MAX 2147483647 -vec4 blend(vec4 front, vec4 back) { - vec4 result; - result.a = front.a + (1.0 - front.a) * back.a; - result.rgb = ((front.rgb * front.a) + (back.rgb * back.a * (1.0 - front.a))) / result.a; - result = clamp(result, 0.0, 1.0); - return result; +///////////////////////// +#if RAYCASTING_ENABLED + +#include "raycasterdata.glsl" + +RaycasterData raycasterData[N_RAYCASTERS]; +// Include all ray caster helpers +#for id, helperPath in helperPaths +#include <#{helperPath}> +#endfor + +// Include all ray casters +#for id, raycaster in raycasters +#include <#{raycaster.raycastPath}> +#endfor + +#endif +///////////////////////// + +void sortFragments(uint nFrags) { + ABufferFragment tmp; + uint i, j; + + // Insertion sort + for(i = 1; i < nFrags; ++i) { + tmp = fragments[i]; + for(j = i; j > 0 && _depth_(tmp) < _depth_(fragments[j-1]); --j) { + fragments[j] = fragments[j-1]; + } + fragments[j] = tmp; + } } uint countSamples(uint mask) { @@ -66,39 +86,172 @@ uint countSamples(uint mask) { + ((mask >> 7) & 1); } +uint reduceFragments(uint nFrags) { + uint outputIndex = 0; + for (uint inputIndex = 0; inputIndex < nFrags; inputIndex++, outputIndex++) { + + ABufferFragment frag = fragments[inputIndex]; + uint accumulatedMask = _msaa_(fragments[inputIndex]); + uint newMask = _msaa_(fragments[inputIndex]); + int type = _type_(fragments[inputIndex]); + + // Accumulate sample mask + for (uint j = inputIndex + 1; + j < nFrags && ((newMask = _msaa_(fragments[j])) & accumulatedMask) == 0 && _type_(fragments[j]) == type; + j++) { + accumulatedMask |= newMask; + inputIndex = j; + } + uint nSamples = countSamples(accumulatedMask); + vec4 color = _color_(fragments[inputIndex]); // TODO: Possibly weigh all samples together? + + // Adjust the alpha by the ratio of accumulated samples + float alpha = float(nSamples) / float(nAaSamples); + color.a *= alpha; + + ABufferFragment outputFragment = fragments[inputIndex]; + _color_(outputFragment, color); + + fragments[outputIndex] = outputFragment; + } + + // return number of outputted fragments + return outputIndex; +} + +#if RAYCASTING_ENABLED + +/** + * Iterate through list of sorted fragments, + * and retrieve raycasting position, direction, scale + */ +void retrieveRaycasterData(uint nFrags) { + float entryDepths[N_RAYCASTERS]; + for (int i = 0; i < N_RAYCASTERS; i++) { + entryDepths[i] = -1; + } + for (int i = 0; i < nFrags; i++) { + int type = _type_(fragments[i]); // - 1; + vec4 color = _color_(fragments[i]); + float depth = _depth_(fragments[i]); + if (type > 0) { // enter raycaster + int raycasterId = type - 1; + if (entryDepths[raycasterId] < 0) { // first entry + raycasterData[raycasterId].position = color.rgb; + raycasterData[raycasterId].previousJitterDistance = 0; + entryDepths[raycasterId] = depth; + raycasterData[raycasterId].scale = -1; + } + } else if (type < 0) { // exit raycaster + int raycasterId = -type - 1; + vec3 localDirection = color.xyz - raycasterData[raycasterId].position; + raycasterData[raycasterId].direction = safeNormalize(localDirection); + raycasterData[raycasterId].scale = safeLength(localDirection) / (depth - entryDepths[raycasterId]); + } + } +} + +/** + * Perform raycasting + */ +void raycast(float raycastDepth, uint raycasterMask, inout vec4 finalColor) { + float nextStepSize = raycastDepth; + float currentStepSize = 0.0; + float jitterFactor = 0.5 + 0.5 * rand(gl_FragCoord.xy); // should be between 0.5 and 1.0 + +#for index, raycaster in raycasters + if ((raycasterMask & #{raycaster.bitmask}) != 0) { + RaycasterData data = raycasterData[#{index}]; + float maxStepSizeLocal = stepSize#{raycaster.id}(data.position, data.direction); + float maxStepSize = maxStepSizeLocal / data.scale; + nextStepSize = min(nextStepSize, maxStepSize); + } +#endfor + + float currentDepth = 0.0; + + for (int steps = 0; finalColor.a < ALPHA_LIMIT && steps < RAYCAST_MAX_STEPS; ++steps) { + bool exceededDepth = currentDepth + nextStepSize * jitterFactor > raycastDepth; + bool shortStepSize = nextStepSize < raycastDepth / 10000000000.0; + + if (exceededDepth || shortStepSize) { + break; + } + + currentStepSize = nextStepSize; + currentDepth += currentStepSize; + nextStepSize = raycastDepth - currentDepth; + +#for index, raycaster in raycasters + if ((raycasterMask & #{raycaster.bitmask}) != 0) { + RaycasterData data = raycasterData[#{raycaster.id}]; + float stepSizeLocal = currentStepSize * data.scale; + float jitteredStepSizeLocal = stepSizeLocal * jitterFactor; + + vec3 jitteredPosition = data.position + data.direction*jitteredStepSizeLocal; + raycasterData[#{raycaster.id}].position += data.direction * stepSizeLocal; + + float maxStepSizeLocal; + + vec4 raycasterContribution = sample#{raycaster.id}(jitteredPosition, data.direction, finalColor, maxStepSizeLocal); + float sampleDistance = jitteredStepSizeLocal + data.previousJitterDistance; + + blendStep(finalColor, raycasterContribution, sampleDistance); + + raycasterData[#{raycaster.id}].previousJitterDistance = stepSizeLocal - jitteredStepSizeLocal; + float maxStepSize = maxStepSizeLocal/data.scale; + nextStepSize = min(nextStepSize, maxStepSize); + } +#endfor + } +} +#endif // RAYCASTING_ENABLED void main() { finalColor = vec4(0.0); - uint nFrags = loadFragments(); - - sortFragments(nFrags); - int realFrags = 0; + uint nOriginalFrags = loadFragments(); + uint raycasterMask = 0; + + sortFragments(nOriginalFrags); + + uint nFrags = reduceFragments(nOriginalFrags); +#if RAYCASTING_ENABLED + retrieveRaycasterData(nFrags); +#endif for (uint i = 0; i < nFrags; i++) { ABufferFragment frag = fragments[i]; - uint accumulatedMask = _msaa_(fragments[i]); - uint newMask = _msaa_(fragments[i]); + int type = _type_(frag); - vec4 color = vec4(0.0); - float totalAlpha = 0.0; - - for (uint j = i + 1; - j < nFrags - && ((newMask = _msaa_(fragments[j])) & accumulatedMask) == 0; - j++) { - - accumulatedMask |= newMask; - i = j; + if (type == 0) { // geometry fragment + vec4 color = _color_(frag); + blend(finalColor, color); } - - uint nSamples = countSamples(accumulatedMask); - color = _color_(fragments[i]); // TODO: Possibly weigh all samples together? - color.a *= float(nSamples) / float(nAaSamples); - - finalColor = blend(finalColor, color); +#if RAYCASTING_ENABLED + else if (type > 0) { // enter volume + int raycasterId = type - 1; + // only enter volume if a valid scale was detected + if (raycasterData[raycasterId].scale > 0) { + raycasterMask |= (1 << (raycasterId)); + } + } else { // exit volume + int raycasterId = -type - 1; + raycasterMask &= INT_MAX - (1 << (raycasterId)); + } + // Ray cast to next fragment + if (i + 1 < nFrags && raycasterMask != 0) { + float startDepth = _depth_(fragments[i]); + float endDepth = _depth_(fragments[i + 1]); + raycast(endDepth - startDepth, raycasterMask, finalColor); + } +#endif } - finalColor.a *= blackoutFactor; + // finalColor is expressed with premultiplied alpha + finalColor.rgb *= blackoutFactor; + + // Render everything on a black background + finalColor.a = 1.0; } diff --git a/shaders/blending.glsl b/shaders/blending.glsl new file mode 100644 index 0000000000..9606abc607 --- /dev/null +++ b/shaders/blending.glsl @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2016 * + * * + * 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 _BLENDING_GLSL_ +#define _BLENDING_GLSL_ + +/** + * Blend in src behind dst + * dst is premultiplied + * src is expressed in straight RGBA + */ +void blend(inout vec4 dst, vec4 src) { + dst.rgb = dst.rgb + (1.0 - dst.a) * src.a * src.rgb; + dst.a = dst.a + (1.0 - dst.a) * src.a; +} + +/** + * Blend in src behind dst + * dst is premultiplied + * src is expressed in straight RGBA + * stepSize = 0: alpha becomes 0 + * stepSize = 1: alpha becomes src.a + */ +void blendStep(inout vec4 dst, vec4 src, float stepSize) { + src.a = 1.0 - pow(1.0 - src.a, stepSize); + blend(dst, src); +} + +#endif \ No newline at end of file diff --git a/shaders/framebuffer/exitframebuffer.frag b/shaders/framebuffer/exitframebuffer.frag new file mode 100644 index 0000000000..e65beb9460 --- /dev/null +++ b/shaders/framebuffer/exitframebuffer.frag @@ -0,0 +1,37 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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/powerScalingMath.hglsl" +#include <#{fragmentPath}> + +out vec4 _out_color_; + +void main() { + Fragment f = getFragment(); + _out_color_ = f.color; + gl_FragDepth = normalizeFloat(f.depth); +} diff --git a/shaders/framebuffer/raycastframebuffer.frag b/shaders/framebuffer/raycastframebuffer.frag new file mode 100644 index 0000000000..9be8afe46d --- /dev/null +++ b/shaders/framebuffer/raycastframebuffer.frag @@ -0,0 +1,151 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2016 * + * * + * 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__ + +uniform sampler2D exitColorTexture; +uniform sampler2D exitDepthTexture; +uniform sampler2DMS mainDepthTexture; + +#include "blending.glsl" +#include "rand.glsl" +#include "PowerScaling/powerScalingMath.hglsl" +#include <#{fragmentPath}> + +#for id, helperPath in helperPaths +#include <#{helperPath}> +#endfor + +#include <#{raycastPath}> + +out vec4 finalColor; + + +#define ALPHA_LIMIT 0.99 +#define RAYCAST_MAX_STEPS 1000 +#define MAX_AA_SAMPLES 8 + +uniform int nAaSamples; + + +void main() { + + vec2 texCoord = vec2(gl_FragCoord.x / #{rendererData.windowWidth}, + gl_FragCoord.y / #{rendererData.windowHeight}); + + + vec4 exitColorTexture = texture(exitColorTexture, texCoord); + if (exitColorTexture.a < 1.0) { + discard; + } + + // fetch exit point from texture + vec3 exitPos = exitColorTexture.rgb; + float exitDepth = denormalizeFloat(texture(exitDepthTexture, texCoord).x); + + + + float jitterFactor = 0.5 + 0.5 * rand(gl_FragCoord.xy); // should be between 0.5 and 1.0 + + // fetch entry point from rendered fragment + Fragment f = getFragment(); + vec3 entryPos = f.color.xyz; + float entryDepth = f.depth; + + vec3 position = entryPos; + vec3 diff = exitPos - entryPos; + + vec3 direction = normalize(diff); + float raycastDepth = length(diff); + + float raycastDepths[MAX_AA_SAMPLES]; + + int i, j; + float tmp; + + for (i = 0; i < nAaSamples; i++) { + float geoDepth = denormalizeFloat(texelFetch(mainDepthTexture, ivec2(gl_FragCoord), i).x); + float geoRatio = clamp((geoDepth - entryDepth) / (exitDepth - entryDepth), 0.0, 1.0); + raycastDepths[i] = geoRatio * raycastDepth; + } + + for(i = 1; i < nAaSamples; ++i) { + tmp = raycastDepths[i]; + for(j = i; j > 0 && tmp < raycastDepths[j - 1]; --j) { + raycastDepths[j] = raycastDepths[j-1]; + } + raycastDepths[j] = tmp; + } + + + finalColor = vec4(0.0); + float currentDepth = 0.0; + // todo: shorten depth if geometry is intersecting! + float nextStepSize = stepSize#{id}(position, direction); + float currentStepSize; + float previousJitterDistance = 0.0; + + int steps = 0; + + float aaOpacity = 1.0; + int sampleIndex = 0; + float opacityDecay = 1.0 / nAaSamples; + + for (steps = 0; finalColor.a < ALPHA_LIMIT && steps < RAYCAST_MAX_STEPS; ++steps) { + + + while (sampleIndex < nAaSamples && currentDepth + nextStepSize * jitterFactor > raycastDepths[sampleIndex]) { + sampleIndex++; + aaOpacity -= opacityDecay; + } + bool shortStepSize = nextStepSize < raycastDepth / 10000000000.0; + + if (sampleIndex >= nAaSamples || shortStepSize) { + break; + } + + currentStepSize = nextStepSize; + currentDepth += currentStepSize; + + float jitteredStepSize = currentStepSize * jitterFactor; + vec3 jitteredPosition = position + direction*jitteredStepSize; + position += direction * currentStepSize; + + vec4 raycasterContribution = sample#{id}(jitteredPosition, direction, finalColor, nextStepSize); + + float sampleDistance = aaOpacity * (jitteredStepSize + previousJitterDistance); + + blendStep(finalColor, raycasterContribution, sampleDistance); + + previousJitterDistance = currentStepSize - jitteredStepSize; + + float maxStepSize = raycastDepths[nAaSamples - 1] - currentDepth; + + nextStepSize = min(nextStepSize, maxStepSize); + + } + + finalColor.rgb /= finalColor.a; + gl_FragDepth = normalizeFloat(entryDepth); +} diff --git a/shaders/framebuffer/renderframebuffer.frag b/shaders/framebuffer/renderframebuffer.frag new file mode 100644 index 0000000000..88540a28c9 --- /dev/null +++ b/shaders/framebuffer/renderframebuffer.frag @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 <#{fragmentPath}> + +out vec4 _out_color_; + +void main() { + Fragment f = getFragment(); + _out_color_ = f.color; + gl_FragDepth = normalizeFloat(f.depth); +} diff --git a/shaders/framebuffer/resolveframebuffer.frag b/shaders/framebuffer/resolveframebuffer.frag new file mode 100644 index 0000000000..df8b872298 --- /dev/null +++ b/shaders/framebuffer/resolveframebuffer.frag @@ -0,0 +1,45 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 - 2016 * + * * + * 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/powerScalingMath.hglsl" + +layout (location = 0) out vec4 finalColor; +uniform float blackoutFactor; +uniform int nAaSamples; + +uniform sampler2DMS mainColorTexture; + +void main() { + vec4 color = vec4(0.0); + for (int i = 0; i < nAaSamples; i++) { + color += texelFetch(mainColorTexture, ivec2(gl_FragCoord), i); + } + + color /= nAaSamples; + color.rgb *= blackoutFactor; + + finalColor = vec4(color.rgb, 1.0); +} diff --git a/shaders/framebuffer/resolveframebuffer.vert b/shaders/framebuffer/resolveframebuffer.vert new file mode 100644 index 0000000000..d691d5208d --- /dev/null +++ b/shaders/framebuffer/resolveframebuffer.vert @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 - 2016 * + * * + * 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__ + +in vec4 position; +out vec2 texCoord; + +void main() { + gl_Position = position; + texCoord = 0.5 + position.xy / 2.0; +} diff --git a/shaders/rand.glsl b/shaders/rand.glsl new file mode 100644 index 0000000000..e1d4646839 --- /dev/null +++ b/shaders/rand.glsl @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2016 * + * * + * 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 _RAND_GLSL_ +#define _RAND_GLSL_ + +/** + * Return a random number between 0 and 1, based on a vec2 + */ +float rand(vec2 co){ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +#endif \ No newline at end of file diff --git a/shaders/renderframebuffer.frag b/shaders/renderframebuffer.frag deleted file mode 100644 index f6f000019e..0000000000 --- a/shaders/renderframebuffer.frag +++ /dev/null @@ -1,9 +0,0 @@ -#include <#{fragmentPath}> - -out vec4 _out_color_; - -void main() { - Fragment f = getFragment(); - _out_color_ = f.color; - gl_FragDepth = f.depth; -} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f57874ac5a..8a941baf63 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/query/query.cpp ${OPENSPACE_BASE_DIR}/src/rendering/abufferrenderer.cpp ${OPENSPACE_BASE_DIR}/src/rendering/framebufferrenderer.cpp + ${OPENSPACE_BASE_DIR}/src/rendering/raycastermanager.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderable.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderengine.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderengine_lua.inl @@ -128,10 +129,12 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/query/query.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/abufferrenderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/framebufferrenderer.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycasterlistener.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycastermanager.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderable.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderengine.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volume.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/ephemeris.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraph.h diff --git a/src/engine/downloadmanager.cpp b/src/engine/downloadmanager.cpp index c094e11033..7c69aa0638 100644 --- a/src/engine/downloadmanager.cpp +++ b/src/engine/downloadmanager.cpp @@ -225,7 +225,7 @@ std::vector DownloadManager::downloadRequestFiles( ++nFiles; #ifdef __APPLE__ // @TODO: Fix this so that the ifdef is not necessary anymore ---abock - std::string file = ghoul::filesystem::File(line, true).filename(); + std::string file = ghoul::filesystem::File(line, ghoul::filesystem::File::RawPath::Yes).filename(); #else std::string file = ghoul::filesystem::File(line).filename(); #endif diff --git a/src/network/parallelconnection.cpp b/src/network/parallelconnection.cpp index f54ff5dbf1..11c5c2b4a2 100644 --- a/src/network/parallelconnection.cpp +++ b/src/network/parallelconnection.cpp @@ -27,9 +27,7 @@ #define _ERRNO WSAGetLastError() #endif #else //Use BSD sockets -#ifdef _XCODE #include -#endif #include #include #include diff --git a/src/properties/matrixproperty.cpp b/src/properties/matrixproperty.cpp index a1a671f555..2bdb434b60 100644 --- a/src/properties/matrixproperty.cpp +++ b/src/properties/matrixproperty.cpp @@ -39,8 +39,8 @@ namespace properties { [](lua_State* state, bool& success) -> __TYPE__ { \ __TYPE__ result; \ int number = 1; \ - for (glm::length_t i = 0; i < __TYPE__::rows; ++i) { \ - for (glm::length_t j = 0; j < __TYPE__::cols; ++j) { \ + for (glm::length_t i = 0; i < ghoul::glm_rows<__TYPE__>::value; ++i) { \ + for (glm::length_t j = 0; j < ghoul::glm_cols<__TYPE__>::value; ++j) { \ lua_getfield(state, -1, std::to_string(number).c_str()); \ if (lua_isnumber(state, -1) != 1) { \ success = false; \ @@ -61,8 +61,8 @@ namespace properties { [](lua_State* state, __TYPE__ value) -> bool { \ lua_newtable(state); \ int number = 1; \ - for (glm::length_t i = 0; i < __TYPE__::rows; ++i) { \ - for (glm::length_t j = 0; j < __TYPE__::cols; ++j) { \ + for (glm::length_t i = 0; i < ghoul::glm_rows<__TYPE__>::value; ++i) { \ + for (glm::length_t j = 0; j < ghoul::glm_cols<__TYPE__>::value; ++j) { \ lua_pushnumber(state, static_cast(value[i][j])); \ lua_setfield(state, -2, std::to_string(number).c_str()); \ ++number; \ @@ -75,13 +75,15 @@ namespace properties { [](std::string value, bool& success) -> __TYPE__ { \ __TYPE__ result; \ std::vector tokens = ghoul::tokenizeString(value, ','); \ - if (tokens.size() != (__TYPE__::rows * __TYPE__::cols)) { \ + if (tokens.size() != \ + (ghoul::glm_rows<__TYPE__>::value * ghoul::glm_cols<__TYPE__>::value)) \ + { \ success = false; \ return result; \ } \ int number = 0; \ - for (glm::length_t i = 0; i < __TYPE__::rows; ++i) { \ - for (glm::length_t j = 0; j < __TYPE__::cols; ++j) { \ + for (glm::length_t i = 0; i < ghoul::glm_rows<__TYPE__>::value; ++i) { \ + for (glm::length_t j = 0; j < ghoul::glm_cols<__TYPE__>::value; ++j) { \ std::stringstream s(tokens[number]); \ __TYPE__::value_type v; \ s >> v; \ @@ -102,8 +104,8 @@ namespace properties { #define DEFAULT_TO_STRING_LAMBDA(__TYPE__) \ [](std::string& outValue, __TYPE__ inValue) -> bool { \ outValue = ""; \ - for (glm::length_t i = 0; i < __TYPE__::rows; ++i) { \ - for (glm::length_t j = 0; j < __TYPE__::cols; ++j) { \ + for (glm::length_t i = 0; i < ghoul::glm_rows<__TYPE__>::value; ++i) { \ + for (glm::length_t j = 0; j < ghoul::glm_cols<__TYPE__>::value; ++j) { \ outValue += std::to_string(inValue[i][j]) + ","; \ } \ outValue.pop_back(); \ diff --git a/src/properties/vectorproperty.cpp b/src/properties/vectorproperty.cpp index bb2a00d321..90de82180b 100644 --- a/src/properties/vectorproperty.cpp +++ b/src/properties/vectorproperty.cpp @@ -39,7 +39,7 @@ namespace properties { [](lua_State * state, bool& success) -> __TYPE__ { \ __TYPE__ result; \ lua_pushnil(state); \ - for (glm::length_t i = 0; i < __TYPE__::components; ++i) { \ + for (glm::length_t i = 0; i < ghoul::glm_components<__TYPE__>::value; ++i) { \ int success = lua_next(state, -2); \ if (success != 1) { \ success = false; \ @@ -61,7 +61,7 @@ namespace properties { [](lua_State * state, __TYPE__ value) -> bool { \ lua_newtable(state); \ int number = 1; \ - for (glm::length_t i = 0; i < __TYPE__::components; ++i) { \ + for (glm::length_t i = 0; i < ghoul::glm_components<__TYPE__>::value; ++i) { \ lua_pushnumber(state, static_cast(value[i])); \ lua_setfield(state, -2, std::to_string(number).c_str()); \ ++number; \ @@ -77,7 +77,7 @@ namespace properties { success = false; \ return result; \ } \ - for (glm::length_t i = 0; i < __TYPE__::components; ++i) { \ + for (glm::length_t i = 0; i < ghoul::glm_components<__TYPE__>::value; ++i) { \ std::stringstream s(tokens[i]); \ __TYPE__::value_type v; \ s >> v; \ @@ -95,7 +95,7 @@ namespace properties { #define DEFAULT_TO_STRING_LAMBDA(__TYPE__) \ [](std::string& outValue, __TYPE__ inValue) -> bool { \ outValue = "{"; \ - for (glm::length_t i = 0; i < __TYPE__::components; ++i) \ + for (glm::length_t i = 0; i < ghoul::glm_components<__TYPE__>::value; ++i) \ outValue += std::to_string(inValue[i]) + ","; \ outValue.pop_back(); \ outValue += "}"; \ diff --git a/src/rendering/abufferrenderer.cpp b/src/rendering/abufferrenderer.cpp index 3eaa32608c..0d0dd27d45 100644 --- a/src/rendering/abufferrenderer.cpp +++ b/src/rendering/abufferrenderer.cpp @@ -23,31 +23,44 @@ ****************************************************************************************/ #include +#include #include #include #include +#include #include #include +#include + #include #include +#include #include +#include namespace { const std::string _loggerCat = "ABufferRenderer"; + const std::string BoundsFragmentShaderPath = "${SHADERS}/abuffer/boundsabuffer.frag"; + const std::string RenderFragmentShaderPath = "${SHADERS}/abuffer/renderabuffer.frag"; + const int MaxRaycasters = 32; const int MaxLayers = 16; + const int MaxAverageLayers = 8; } namespace openspace { - ABufferRenderer::ABufferRenderer() +ABufferRenderer::ABufferRenderer() : _camera(nullptr) , _scene(nullptr) , _resolution(glm::ivec2(0)) , _dirtyResolution(true) + , _dirtyRaycastData(true) + , _dirtyRendererData(true) + , _dirtyResolveDictionary(true) , _resolveProgram(nullptr) { } ABufferRenderer::~ABufferRenderer() {} @@ -85,23 +98,30 @@ void ABufferRenderer::initialize() { glGenBuffers(1, &_fragmentBuffer); glGenTextures(1, &_fragmentTexture); - if (_dirtyResolution) { - updateResolution(); - } - updateRendererData(); - ghoul::Dictionary dict = createResolveDictionary(); - - _resolveProgram = ghoul::opengl::ProgramObject::Build("ABuffer Resolve", - "${SHADERS}/abuffer/resolveabuffer.vert", - "${SHADERS}/abuffer/resolveabuffer.frag", - dict); - _nAaSamples = OsEng.windowWrapper().currentNumberOfAaSamples(); + if (_nAaSamples == 0) { + _nAaSamples = 1; + } if (_nAaSamples > 8) { - LERROR("ABuffer does not support more than 8 MSAA samples."); + LERROR("ABuffer renderer does not support more than 8 MSAA samples."); _nAaSamples = 8; } + updateResolution(); + updateRendererData(); + updateRaycastData(); + updateResolveDictionary(); + + try { + _resolveProgram = ghoul::opengl::ProgramObject::Build("ABuffer Resolve", + "${SHADERS}/abuffer/resolveabuffer.vert", + "${SHADERS}/abuffer/resolveabuffer.frag", + _resolveDictionary); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + + OsEng.renderEngine().raycasterManager().addListener(*this); } void ABufferRenderer::deinitialize() { @@ -115,65 +135,134 @@ void ABufferRenderer::deinitialize() { glDeleteBuffers(1, &_vertexPositionBuffer); glDeleteVertexArrays(1, &_screenQuad); + + OsEng.renderEngine().raycasterManager().removeListener(*this); +} + +void ABufferRenderer::raycastersChanged(VolumeRaycaster& raycaster, bool attached) { + (void) raycaster; + (void) attached; + _dirtyRaycastData = true; } void ABufferRenderer::update() { - bool dirtyRendererData = false; - bool dirtyResolveDictionary = false; - + // Make sure that the fragment buffer has the correct resoliution + // according to the output render buffer size if (_dirtyResolution) { updateResolution(); } - - if (dirtyRendererData) { - dirtyResolveDictionary = true; + + // Make sure that the renderengine gets the correct render data + // to feed into all render programs. + // This will trigger a recompilation of all the shader programs + // involved in rendering geometries. + if (_dirtyRendererData) { updateRendererData(); } - // TODO: Collect volumes from scene graph. - // Diff against cache, update cache. - // possibly mark resolve dictionary as dirty - - if (dirtyResolveDictionary) { - ghoul::Dictionary dict = createResolveDictionary(); - _resolveProgram->setDictionary(dict); + // Make sure that all raycaster data is up to date. + if (_dirtyRaycastData) { + updateRaycastData(); } - if (_resolveProgram->isDirty()) { - _resolveProgram->rebuildFromFile(); + // Make sure that the resolve dictionary is up to date. + // The resolve dictionary contains information for all + // ray casters, including shader include paths. + + if (_dirtyResolveDictionary) { + updateResolveDictionary(); + _resolveProgram->setDictionary(_resolveDictionary); } + + // If the resolve dictionary changed (or a file changed on disk) + // then rebuild the resolve program. + if (_resolveProgram->isDirty()) { + try { + _resolveProgram->rebuildFromFile(); + } catch (ghoul::RuntimeError& error) { + LERROR(error.message); + } + } + + for (auto &program : _boundsPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + } + } + } void ABufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { if (_scene == nullptr) return; if (_camera == nullptr) return; - + // Reset + clear(); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); - clear(); // Step 1: Render geometries to the fragment buffer - // Bind head-pointer image for read-write - glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); + // Bind head-pointer image for read-write + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); glBindImageTexture(0, _anchorPointerTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); - _scene->render({ *_camera, psc(), doPerformanceMeasurements }); - - // Step 2: Render volumes to the fragment buffer - //TODO: Implement this + // Render the scene to the fragment buffer. Collect renderer tasks (active raycasters) + RenderData data{ *_camera, psc(), doPerformanceMeasurements }; + RendererTasks tasks; + _scene->render(data, tasks); + + + // Step 2: Perform raycasting tasks requested by the scene + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + ghoul::opengl::ProgramObject* program = _boundsPrograms[raycaster].get(); + if (program) { + program->activate(); + program->setUniform("_exit_", false); + raycaster->renderEntryPoints(raycasterTask.renderData, *program); + program->setUniform("_exit_", true); + raycaster->renderExitPoints(raycasterTask.renderData, *program); + program->deactivate(); + } + else { + LWARNING("Raycaster is not attached when trying to perform raycaster task"); + } + } // Step 3: Resolve the buffer _resolveProgram->activate(); + + // 3a: Perform the pre-raycast step for all raycaster tasks. + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + auto raycastData = _raycastData.find(raycaster); + if (raycastData != _raycastData.end()) { + raycaster->preRaycast(raycastData->second, *_resolveProgram.get()); + } + } + + // 3b: Set "global" uniforms, and start the resolve pass. _resolveProgram->setUniform("blackoutFactor", blackoutFactor); _resolveProgram->setUniform("nAaSamples", _nAaSamples); - // todo: pre-ray-cast for each volume glBindVertexArray(_screenQuad); glDrawArrays(GL_TRIANGLES, 0, 6); - // todo: post-ray-cast for each volume + + // 3c: Perform the post-raycast step for all raycaster tasks. + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + auto raycastData = _raycastData.find(raycaster); + if (raycastData != _raycastData.end()) { + raycaster->postRaycast(raycastData->second, *_resolveProgram.get()); + } + } + _resolveProgram->deactivate(); } @@ -223,7 +312,7 @@ void ABufferRenderer::updateResolution() { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_TEXTURE_BUFFER, _fragmentBuffer); - glBufferData(GL_TEXTURE_BUFFER, MaxLayers*totalPixels*sizeof(GLuint) * 4, NULL, GL_DYNAMIC_COPY); + glBufferData(GL_TEXTURE_BUFFER, MaxAverageLayers*totalPixels*sizeof(GLuint) * 4, NULL, GL_DYNAMIC_COPY); glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); @@ -233,27 +322,125 @@ void ABufferRenderer::updateResolution() { _dirtyResolution = false; - } -ghoul::Dictionary ABufferRenderer::createResolveDictionary() { + + +void ABufferRenderer::updateResolveDictionary() { ghoul::Dictionary dict; + ghoul::Dictionary raycastersDict; + + for (const auto &raycastPair : _raycastData) { + ghoul::Dictionary innerDict; + int id = raycastPair.second.id; + std::string namespaceName = raycastPair.second.namespaceName; + std::string raycastPath = raycastPair.first->getRaycastPath(); + + innerDict.setValue("id", id); + innerDict.setValue("namespace", namespaceName); + innerDict.setValue("bitmask", 1 << id); + innerDict.setValue("raycastPath", raycastPath); + + raycastersDict.setValue(std::to_string(id), innerDict); + } + + dict.setValue("raycasters", raycastersDict); + + ghoul::Dictionary helperPathsDict; + for (int i = 0; i < _helperPaths.size(); i++) { + helperPathsDict.setValue(std::to_string(i), _helperPaths[i]); + } + + dict.setValue("helperPaths", helperPathsDict); dict.setValue("rendererData", _rendererData); - // TODO: Add volume data to dictionary - // such as id, bitmask, path to raycaster frag shader, helpers, nVolumes... - return dict; + dict.setValue("raycastingEnabled", _raycastData.size() > 0); + dict.setValue("nRaycasters", static_cast(_raycastData.size())); + + _resolveDictionary = dict; + _dirtyResolveDictionary = false; } +void ABufferRenderer::updateRaycastData() { + + _raycastData.clear(); + _boundsPrograms.clear(); + _helperPaths.clear(); + + const std::vector& raycasters = OsEng.renderEngine().raycasterManager().raycasters(); + + std::map namespaceIndices; + int nextId = 0; // raycaster ids are positive integers starting at 0. (for raycasters, fragment type is id+1) + int nextNamespaceIndex = 0; + + for (auto &raycaster : raycasters) { + if (nextId > MaxRaycasters) { + int nIgnored = MaxRaycasters - raycasters.size(); + LWARNING("ABufferRenderer does not support more than 32 raycasters. Ignoring " << nIgnored << " raycasters"); + break; + } + + RaycastData data; + data.id = nextId++; + + std::string helperPath = raycaster->getHelperPath(); + // Each new helper path generates a new namespace, + // to avoid glsl name collisions between raycaster implementaitons. + // Assign a new namespace or find an already created index. + + if (helperPath == "") { + data.namespaceName = "NAMESPACE_" + std::to_string(nextNamespaceIndex++); + } else { + auto iter = namespaceIndices.find(helperPath); + if (iter == namespaceIndices.end()) { + int namespaceIndex = nextNamespaceIndex++; + data.namespaceName = std::to_string(namespaceIndex); + namespaceIndices[helperPath] = namespaceIndex; + _helperPaths.push_back(helperPath); + } + else { + data.namespaceName = "NAMESPACE_" + std::to_string(iter->second); + } + } + + _raycastData[raycaster] = data; + std::string vsPath = raycaster->getBoundsVsPath(); + std::string fsPath = raycaster->getBoundsFsPath(); + ghoul::Dictionary dict; + + // set path to the current renderer's main fragment shader + dict.setValue("rendererData", _rendererData); + // parameterize the main fragment shader program with specific contents. + // fsPath should point to a shader file defining a Fragment getFragment() function + // instead of a void main() setting glFragColor, glFragDepth, etc. + dict.setValue("fragmentPath", fsPath); + dict.setValue("fragmentType", data.id + 1); + try { + _boundsPrograms[raycaster] = ghoul::opengl::ProgramObject::Build("Volume " + std::to_string(data.id) + " bounds", vsPath, BoundsFragmentShaderPath, dict); + } + catch (ghoul::RuntimeError& error) { + LERROR(error.message); + } + } + + _dirtyRaycastData = false; + _dirtyResolveDictionary = true; + +} + + void ABufferRenderer::updateRendererData() { ghoul::Dictionary dict; - dict.setValue("windowWidth", OsEng.windowWrapper().currentWindowResolution().x); - dict.setValue("windowHeight", OsEng.windowWrapper().currentWindowResolution().y); + dict.setValue("windowWidth", _resolution.x); + dict.setValue("windowHeight", _resolution.y); + dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); dict.setValue("maxLayers", MaxLayers); - dict.setValue("fragmentRendererPath", std::string("${SHADERS}/abuffer/renderabuffer.frag")); + dict.setValue("maxTotalFragments", MaxLayers * _resolution.x * _resolution.y); + _rendererData = dict; OsEng.renderEngine().setRendererData(dict); + _dirtyRendererData = false; } } diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 55b67adbdb..e2e7213ede 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -30,74 +30,381 @@ #include #include #include +#include +#include + +#include +#include +#include + +#include namespace { const std::string _loggerCat = "FramebufferRenderer"; - const std::string FragmentRendererPath = "${SHADERS}/renderframebuffer.frag"; + const std::string ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; + const std::string RaycastFragmentShaderPath = "${SHADERS}/framebuffer/raycastframebuffer.frag"; + const std::string RenderFragmentShaderPath = "${SHADERS}/framebuffer/renderframebuffer.frag"; } namespace openspace { +FramebufferRenderer::FramebufferRenderer() + : _camera(nullptr) + , _scene(nullptr) + , _resolution(glm::vec2(0)) { +} - FramebufferRenderer::FramebufferRenderer() - : _camera(nullptr) - , _scene(nullptr) - , _resolution(glm::vec2(0)) { - } +FramebufferRenderer::~FramebufferRenderer() {} +void FramebufferRenderer::initialize() { + LINFO("Initializing FramebufferRenderer"); - FramebufferRenderer::~FramebufferRenderer() { - - } + const GLfloat size = 1.0f; + const GLfloat vertex_data[] = { + // x y s t + -size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f, + -size, size, 0.0f, 1.0f, + -size, -size, 0.0f, 1.0f, + size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f + }; + glGenVertexArrays(1, &_screenQuad); + glBindVertexArray(_screenQuad); - void FramebufferRenderer::initialize() { - LINFO("Initializing FramebufferRenderer"); - updateRendererData(); + glGenBuffers(1, &_vertexPositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast(0)); + glEnableVertexAttribArray(0); + + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + // Main framebuffer + glGenTextures(1, &_mainColorTexture); + glGenTextures(1, &_mainDepthTexture); + glGenFramebuffers(1, &_mainFramebuffer); + + // Exit framebuffer + glGenTextures(1, &_exitColorTexture); + glGenTextures(1, &_exitDepthTexture); + glGenFramebuffers(1, &_exitFramebuffer); + + updateResolution(); + updateRendererData(); + updateRaycastData(); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _exitColorTexture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _exitDepthTexture, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main framebuffer is not complete"); } - void FramebufferRenderer::deinitialize() { - LINFO("Deinitializing FramebufferRenderer"); - } - - - void FramebufferRenderer::update() { - // no need to update anything. - } - - void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { - if (_scene == nullptr) return; - if (_camera == nullptr) return; - - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - _scene->render({ *_camera, psc(), doPerformanceMeasurements });; + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + try { + _resolveProgram = ghoul::opengl::ProgramObject::Build("Framebuffer Resolve", + "${SHADERS}/framebuffer/resolveframebuffer.vert", + "${SHADERS}/framebuffer/resolveframebuffer.frag"); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); } - void FramebufferRenderer::setScene(Scene* scene) { - _scene = scene; + OsEng.renderEngine().raycasterManager().addListener(*this); + + _nAaSamples = OsEng.windowWrapper().currentNumberOfAaSamples(); + if (_nAaSamples == 0) { + _nAaSamples = 1; + } + if (_nAaSamples > 8) { + LERROR("Framebuffer renderer does not support more than 8 MSAA samples."); + _nAaSamples = 8; + } +} + +void FramebufferRenderer::deinitialize() { + LINFO("Deinitializing FramebufferRenderer"); + + glDeleteFramebuffers(1, &_mainFramebuffer); + glDeleteFramebuffers(1, &_exitFramebuffer); + + glDeleteTextures(1, &_mainColorTexture); + glDeleteTextures(1, &_mainDepthTexture); + glDeleteTextures(1, &_exitColorTexture); + glDeleteTextures(1, &_exitDepthTexture); + + glDeleteBuffers(1, &_vertexPositionBuffer); + glDeleteVertexArrays(1, &_screenQuad); + + OsEng.renderEngine().raycasterManager().removeListener(*this); +} + +void FramebufferRenderer::raycastersChanged(VolumeRaycaster& raycaster, bool attached) { + (void) raycaster; + (void) attached; + _dirtyRaycastData = true; +} + +void FramebufferRenderer::update() { + if (_dirtyResolution) { + updateResolution(); } - void FramebufferRenderer::setCamera(Camera* camera) { - _camera = camera; + if (_dirtyRaycastData) { + updateRaycastData(); } - void FramebufferRenderer::setResolution(glm::ivec2 res) { - _resolution = res; + // If the resolve dictionary changed (or a file changed on disk) + // then rebuild the resolve program. + if (_resolveProgram->isDirty()) { + try { + _resolveProgram->rebuildFromFile(); + } catch (ghoul::RuntimeError& error) { + LERROR(error.message); + } } - void FramebufferRenderer::updateRendererData() { + for (auto &program : _exitPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + } + } + + for (auto &program : _raycastPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + } + } +} + +void FramebufferRenderer::updateResolution() { + int nSamples = OsEng.windowWrapper().currentNumberOfAaSamples(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + nSamples, + GL_RGBA, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true); + + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + nSamples, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true); + + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_RGBA, + GL_BYTE, + nullptr); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + nullptr); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + +void FramebufferRenderer::updateRaycastData() { + _raycastData.clear(); + _exitPrograms.clear(); + _raycastPrograms.clear(); + + const std::vector& raycasters = OsEng.renderEngine().raycasterManager().raycasters(); + int nextId = 0; + for (auto &raycaster : raycasters) { + RaycastData data; + data.id = nextId++; + data.namespaceName = "HELPER"; + + std::string vsPath = raycaster->getBoundsVsPath(); + std::string fsPath = raycaster->getBoundsFsPath(); + ghoul::Dictionary dict; - dict.setValue("fragmentRendererPath", FragmentRendererPath); - dict.setValue("windowWidth", OsEng.windowWrapper().currentWindowResolution().x); - dict.setValue("windowHeight", OsEng.windowWrapper().currentWindowResolution().y); + dict.setValue("rendererData", _rendererData); + dict.setValue("fragmentPath", fsPath); + dict.setValue("id", data.id); + std::string helperPath = raycaster->getHelperPath(); + ghoul::Dictionary helpersDict; + if (helperPath != "") { + helpersDict.setValue("0", helperPath); + } + dict.setValue("helperPaths", helpersDict); + dict.setValue("raycastPath", raycaster->getRaycastPath()); + _raycastData[raycaster] = data; - OsEng.renderEngine().setRendererData(dict); + try { + _exitPrograms[raycaster] = ghoul::opengl::ProgramObject::Build("Volume " + std::to_string(data.id) + " exit", vsPath, ExitFragmentShaderPath, dict); + } + catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + try { + _raycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build("Volume " + std::to_string(data.id) + " raycast", vsPath, RaycastFragmentShaderPath, dict); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } } + _dirtyRaycastData = false; +} + +void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + if (_scene == nullptr) return; + if (_camera == nullptr) return; + + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + RenderData data = { *_camera, psc(), doPerformanceMeasurements }; + RendererTasks tasks; + + // Capture standard fbo + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // bind new fbo A with color and depth buffer. + _scene->render(data, tasks); + + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ghoul::opengl::ProgramObject* exitProgram = _exitPrograms[raycaster].get(); + if (exitProgram) { + exitProgram->activate(); + raycaster->renderExitPoints(raycasterTask.renderData, *exitProgram); + exitProgram->deactivate(); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + + ghoul::opengl::ProgramObject* raycastProgram = _raycastPrograms[raycaster].get(); + if (raycastProgram) { + raycastProgram->activate(); + raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); + + ghoul::opengl::TextureUnit exitColorTextureUnit; + exitColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + raycastProgram->setUniform("exitColorTexture", exitColorTextureUnit); + + ghoul::opengl::TextureUnit exitDepthTextureUnit; + exitDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + raycastProgram->setUniform("exitDepthTexture", exitDepthTextureUnit); + + ghoul::opengl::TextureUnit mainDepthTextureUnit; + mainDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit); + + raycastProgram->setUniform("nAaSamples", _nAaSamples); + + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + raycaster->renderEntryPoints(raycasterTask.renderData, *raycastProgram); + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + + raycaster->postRaycast(_raycastData[raycaster], *raycastProgram); + raycastProgram->deactivate(); + } else { + LWARNING("Raycaster is not attached when trying to perform raycaster task"); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + _resolveProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + _resolveProgram->setUniform("mainColorTexture", mainColorTextureUnit); + _resolveProgram->setUniform("blackoutFactor", blackoutFactor); + _resolveProgram->setUniform("nAaSamples", _nAaSamples); + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _resolveProgram->deactivate(); +} + +void FramebufferRenderer::setScene(Scene* scene) { + _scene = scene; +} + +void FramebufferRenderer::setCamera(Camera* camera) { + _camera = camera; +} + +void FramebufferRenderer::setResolution(glm::ivec2 res) { + _resolution = res; +} + +void FramebufferRenderer::updateRendererData() { + ghoul::Dictionary dict; + dict.setValue("fragmentRendererPath", RenderFragmentShaderPath); + dict.setValue("windowWidth", _resolution.x); + dict.setValue("windowHeight", _resolution.y); + + _rendererData = dict; + + OsEng.renderEngine().setRendererData(dict); +} } diff --git a/src/rendering/raycastermanager.cpp b/src/rendering/raycastermanager.cpp new file mode 100644 index 0000000000..19e8572097 --- /dev/null +++ b/src/rendering/raycastermanager.cpp @@ -0,0 +1,84 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 + +namespace { + const std::string _loggerCat = "RaycasterManager"; +} + +namespace openspace { + +RaycasterManager::RaycasterManager() {} + +RaycasterManager::~RaycasterManager() {} + +void RaycasterManager::attachRaycaster(VolumeRaycaster& raycaster) { + if (!isAttached(raycaster)) { + _raycasters.push_back(&raycaster); + } + for (auto &listener : _listeners) { + listener->raycastersChanged(raycaster, true); + } +} + +bool RaycasterManager::isAttached(VolumeRaycaster& raycaster) { + auto it = std::find(_raycasters.begin(), _raycasters.end(), &raycaster); + return it != _raycasters.end(); +} + + +void RaycasterManager::detachRaycaster(VolumeRaycaster& raycaster) { + auto it = std::find(_raycasters.begin(), _raycasters.end(), &raycaster); + if (it != _raycasters.end()) { + _raycasters.erase(it); + for (auto &listener : _listeners) { + listener->raycastersChanged(raycaster, false); + } + } +} + + +void RaycasterManager::addListener(RaycasterListener& listener) { + auto it = std::find(_listeners.begin(), _listeners.end(), &listener); + if (it == _listeners.end()) { + _listeners.push_back(&listener); + } +} + +void RaycasterManager::removeListener(RaycasterListener& listener) { + auto it = std::find(_listeners.begin(), _listeners.end(), &listener); + if (it != _listeners.end()) { + _listeners.erase(it); + } +} + +const std::vector& RaycasterManager::raycasters() { + return _raycasters; +} + +} diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 4608a3de02..563f185cea 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -122,15 +122,25 @@ void Renderable::update(const UpdateData&) { } +void Renderable::render(const RenderData& data, RendererTasks& tasks) +{ + (void) tasks; + render(data); +} + +void Renderable::render(const RenderData& data) +{ +} + void Renderable::setPscUniforms( - ghoul::opengl::ProgramObject* program, - const Camera* camera, + ghoul::opengl::ProgramObject& program, + const Camera& camera, const PowerScaledCoordinate& position) { - program->setUniform("campos", camera->position().vec4()); - program->setUniform("objpos", position.vec4()); - program->setUniform("camrot", camera->viewRotationMatrix()); - program->setUniform("scaling", camera->scaling()); + program.setUniform("campos", camera.position().vec4()); + program.setUniform("objpos", position.vec4()); + program.setUniform("camrot", camera.viewRotationMatrix()); + program.setUniform("scaling", camera.scaling()); } bool Renderable::isVisible() const { @@ -177,8 +187,10 @@ bool Renderable::isEnabled() const { return _enabled; } -std::vector Renderable::volumesToRender(const RenderData& data) const { - return std::vector(); +void Renderable::onEnabledChange(std::function callback) { + _enabled.onChange([=] () { + callback(isEnabled()); + }); } } // namespace openspace diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 45f08f3518..f39e8171cd 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ #include #include + #include #include #ifdef GHOUL_USE_DEVIL @@ -130,6 +132,7 @@ RenderEngine::~RenderEngine() { delete _mainCamera; delete _performanceMemory; + delete _raycasterManager; if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); @@ -177,6 +180,8 @@ bool RenderEngine::initialize() { } } + _raycasterManager = new RaycasterManager(); + LINFO("Seting renderer from string: " << renderingMethod); setRendererFromString(renderingMethod); @@ -417,6 +422,10 @@ Scene* RenderEngine::scene() { return _sceneGraph; } +RaycasterManager& RenderEngine::raycasterManager() { + return *_raycasterManager; +} + void RenderEngine::setSceneGraph(Scene* sceneGraph) { _sceneGraph = sceneGraph; } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 7833724dd6..d1724f5b50 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -131,19 +131,10 @@ void Scene::evaluate(Camera* camera) { //_root->evaluate(camera); } -void Scene::render(const RenderData& data) { - for (SceneGraphNode* node : _graph.nodes()) - node->render(data); -} - -std::vector> Scene::volumesToRender(const RenderData& data) const { - std::vector> volumes; - - for (const SceneGraphNode* node : _graph.nodes()) { - std::vector> newVolumes = node->volumesToRender(data); - std::copy(newVolumes.begin(), newVolumes.end(), std::back_inserter(volumes)); +void Scene::render(const RenderData& data, RendererTasks& tasks) { + for (SceneGraphNode* node : _graph.nodes()) { + node->render(data, tasks); } - return volumes; } void Scene::scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath) { diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 2a9697d0a2..c3f36f9e23 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -242,7 +242,7 @@ void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) { // child->evaluate(camera, psc()); } -void SceneGraphNode::render(const RenderData& data) { +void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { const psc thisPosition = worldPosition(); RenderData newData = {data.camera, thisPosition, data.doPerformanceMeasurement}; @@ -253,14 +253,14 @@ void SceneGraphNode::render(const RenderData& data) { glFinish(); auto start = std::chrono::high_resolution_clock::now(); - _renderable->render(newData); + _renderable->render(newData, tasks); glFinish(); auto end = std::chrono::high_resolution_clock::now(); _performanceRecord.renderTime = (end - start).count(); } else - _renderable->render(newData); + _renderable->render(newData, tasks); } // evaluate all the children, tail-recursive function(?) @@ -269,18 +269,6 @@ void SceneGraphNode::render(const RenderData& data) { // child->render(newData); } -std::vector> SceneGraphNode::volumesToRender(const RenderData& data) const { - const psc thisPosition = worldPosition(); - RenderData newData = {data.camera, thisPosition, data.doPerformanceMeasurement}; - std::vector> toRender; - if (_renderableVisible && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled()) { - std::vector volumes = _renderable->volumesToRender(newData); - for (Volume* v : volumes) { - toRender.push_back(std::make_pair(v, newData)); - } - } - return toRender; -} // not used anymore @AA //void SceneGraphNode::addNode(SceneGraphNode* child) diff --git a/src/util/blockplaneintersectiongeometry.cpp b/src/util/blockplaneintersectiongeometry.cpp index e48a87701a..92e7bc2537 100644 --- a/src/util/blockplaneintersectiongeometry.cpp +++ b/src/util/blockplaneintersectiongeometry.cpp @@ -111,19 +111,19 @@ void BlockPlaneIntersectionGeometry::updateVertices() { std::vector< std::pair > angles(nIntersections-1); glm::vec3 vector1 = glm::normalize(intersections[1] - intersections[0]); - angles[0] = std::pair(1, 0.0); + angles[0] = std::pair(1, 0.0f); for (int i = 2; i < nIntersections; i++) { glm::vec3 vectorI = glm::normalize(intersections[i] - intersections[0]); float sinA = glm::dot(glm::cross(vector1, vectorI), _normal); float cosA = glm::dot(vector1, vectorI); - angles[i-1] = std::pair(i, glm::sign(sinA) * (1.0 - cosA)); + angles[i - 1] = std::pair(i, static_cast(glm::sign(sinA) * (1.0 - cosA))); } // Sort the vectors by angle in the plane std::sort(angles.begin(), angles.end(), [](const std::pair& a, const std::pair& b) -> bool { - return a.second > b.second; + return a.second < b.second; } ); @@ -138,6 +138,17 @@ void BlockPlaneIntersectionGeometry::updateVertices() { _vertices.push_back(intersections[j].z); //_vertices.push_back(_w); } + + // First VAO setup + glBindVertexArray(_vaoId); + + glBindBuffer(GL_ARRAY_BUFFER, _vBufferId); + glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(GLfloat), _vertices.data(), GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); + + glBindVertexArray(0); } bool BlockPlaneIntersectionGeometry::initialize() { @@ -154,23 +165,14 @@ bool BlockPlaneIntersectionGeometry::initialize() { } updateVertices(); - // First VAO setup - glBindVertexArray(_vaoId); - - glBindBuffer(GL_ARRAY_BUFFER, _vBufferId); - glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(GLfloat), _vertices.data(), GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0); - - glBindVertexArray(0); return true; } void BlockPlaneIntersectionGeometry::render() { - glBindVertexArray(_vaoId); // select first VAO - glDrawArrays(GL_TRIANGLES, 0, 6*6); - glBindVertexArray(0); + glBindVertexArray(_vaoId); + //glDisable(GL_CULL_FACE); + glDrawArrays(GL_TRIANGLE_FAN, 0, _vertices.size() / 3); + //glEnable(GL_CULL_FACE); } } diff --git a/src/util/boxgeometry.cpp b/src/util/boxgeometry.cpp index 1a47ceced7..ded5c4c954 100644 --- a/src/util/boxgeometry.cpp +++ b/src/util/boxgeometry.cpp @@ -45,53 +45,53 @@ BoxGeometry::~BoxGeometry() { bool BoxGeometry::initialize() { - // Initialize and upload to graphics card + // Initialize and upload to GPU float x = _size.x * 0.5; float y = _size.y * 0.5; float z = _size.z * 0.5; const GLfloat vertices[] = { - -x, y, z, - x, y, z, - -x, y, z, - -x, -y, z, - x, -y, z, - x, y, z, + -x, -y, z, // blue corner + x, y, z, // white corner + -x, y, z, // cyan corner + -x, -y, z, // blue corner + x, -y, z, // magenta corner + x, y, z, // white corner - -x, -y, -z, - x, y, -z, - -x, y, -z, - -x, -y, -z, - x, -y, -z, - x, y, -z, + -x, -y, -z, // black corner + -x, y, -z, // green + x, y, -z, // yellow corner + -x, -y, -z, // black + x, y, -z, // yellow + x, -y, -z, // red - x, -y, -z, - x, y, z, - x, -y, z, - x, -y, -z, - x, y, -z, - x, y, z, + x, -y, -z, // red + x, y, z, // yellow + x, -y, z, // magenta + x, -y, -z, // red + x, y, -z, // yellow + x, y, z, // white - -x, -y, -z, - -x, y, z, - -x, -y, z, - -x, -y, -z, - -x, y, -z, - -x, y, z, - - -x, y, -z, - x, y, z, - -x, y, z, - -x, y, -z, - x, y, -z, - x, y, z, - - -x, -y, -z, - x, -y, z, - -x, -y, z, - -x, -y, -z, - x, -y, -z, - x, -y, z + -x, -y, -z, // black + -x, -y, z, // blue + -x, y, z, // cyan + -x, -y, -z, // black + -x, y, z, // cyan + -x, y, -z, // green + + x, y, z, // white + -x, y, -z, // green + -x, y, z, // cyan + -x, y, -z, // green + x, y, z, // white + x, y, -z, // yellow + + -x, -y, -z, // black + x, -y, z, // magenta + -x, -y, z, // blue + -x, -y, -z, // black + x, -y, -z, // red + x, -y, z // magenta }; if (_vaoId == 0) @@ -113,7 +113,7 @@ bool BoxGeometry::initialize() { glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, 0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0); glBindVertexArray(0); return true; diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index b74839b2db..45f3b5e293 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include namespace { const std::string _loggerCat = "SpiceManager"; diff --git a/support/cmake/module_definition.cmake b/support/cmake/module_definition.cmake index db3320dc8d..0ce121737d 100644 --- a/support/cmake/module_definition.cmake +++ b/support/cmake/module_definition.cmake @@ -23,7 +23,7 @@ ######################################################################################### include (${OPENSPACE_CMAKE_EXT_DIR}/module_common.cmake) -include (${GHOUL_BASE_DIR}/ext/handle_external_library.cmake) +include (${GHOUL_BASE_DIR}/support/cmake/handle_external_library.cmake) # Creates a new project and a library for the module with name . The name of # the library is returned in for outside configuration diff --git a/support/cmake/support_macros.cmake b/support/cmake/support_macros.cmake index 95fc8800d1..0a42c263a9 100644 --- a/support/cmake/support_macros.cmake +++ b/support/cmake/support_macros.cmake @@ -126,7 +126,6 @@ function (add_external_dependencies) target_compile_definitions(libOpenSpace PUBLIC ${GHOUL_DEFINITIONS}) set_property(TARGET Lua PROPERTY FOLDER "External") set_property(TARGET lz4 PROPERTY FOLDER "External") - set_property(TARGET tinyobjloader PROPERTY FOLDER "External") # SGCT find_package(SGCT REQUIRED)