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/67P/67P.mod b/data/scene/67P/67P.mod index 0624cf2bcd..dce0892f50 100644 --- a/data/scene/67P/67P.mod +++ b/data/scene/67P/67P.mod @@ -130,4 +130,4 @@ return { }, GuiName = "/Solar/67PTrail" } -} \ No newline at end of file +} 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/data/scene/vestaprojection/vestaprojection.mod b/data/scene/vestaprojection/vestaprojection.mod index efbcb005da..bb5dc312ae 100644 --- a/data/scene/vestaprojection/vestaprojection.mod +++ b/data/scene/vestaprojection/vestaprojection.mod @@ -125,4 +125,4 @@ return { }, GuiName = "/Solar/VestaTrail" } -} \ No newline at end of file +} diff --git a/ext/ghoul b/ext/ghoul index ae36394e9c..f31ddda5d7 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit ae36394e9c12ae302d88931ff6963998125f94cc +Subproject commit f31ddda5d7104f0625059ff00880463a34bdaa6d 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 35b60d6037..1e8554f462 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; @@ -67,9 +66,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; @@ -80,12 +79,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 345ead1292..7dab585aee 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -31,6 +31,7 @@ #include #include + namespace ghoul { namespace fontrendering { class Font; @@ -49,6 +50,7 @@ class Camera; class SyncBuffer; class Scene; class Renderer; +class RaycasterManager; class ScreenLog; class ScreenSpaceRenderable; @@ -77,6 +79,7 @@ public: Camera* camera() const; Renderer* renderer() const; RendererImplementation rendererImplementation() const; + RaycasterManager& raycasterManager(); // sgct wrapped functions bool initializeGL(); @@ -156,6 +159,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/CMakeLists.txt b/modules/base/CMakeLists.txt index 32b7089adc..19735b1337 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -96,4 +96,4 @@ create_new_module( "Base" base_module ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} -) \ No newline at end of file +) 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/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/shaders/PowerScaling/powerScalingMath.hglsl b/shaders/PowerScaling/powerScalingMath.hglsl index 9c72f299e3..72cad25e88 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 input) { + if (input > 1.0) { + return input / pow(10, 27); + } else { + return input - 1.0; + } +} + +float denormalizeFloat(float input) { + if (input < 0.0) { + return input + 1.0; + } else { + return input * 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 b1bd073159..1c5d7b3e01 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 @@ -129,11 +130,14 @@ 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/screenspacerenderable.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/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..84c7d16840 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,27 @@ 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 > 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 +132,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 +309,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 +319,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..f9a441aafe 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -30,74 +30,378 @@ #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 > 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..0e4a806e03 --- /dev/null +++ b/src/rendering/raycastermanager.cpp @@ -0,0 +1,83 @@ +/***************************************************************************************** + * * + * 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 + +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 00f3950e14..812625b755 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -111,15 +111,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 { @@ -166,8 +176,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 82ad72905f..991325387a 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ #include #include + #include #include #ifdef GHOUL_USE_DEVIL @@ -135,6 +137,7 @@ RenderEngine::~RenderEngine() { delete _mainCamera; delete _performanceMemory; + delete _raycasterManager; if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); @@ -182,6 +185,8 @@ bool RenderEngine::initialize() { } } + _raycasterManager = new RaycasterManager(); + LINFO("Seting renderer from string: " << renderingMethod); setRendererFromString(renderingMethod); @@ -441,6 +446,10 @@ Scene* RenderEngine::scene() { return _sceneGraph; } +RaycasterManager& RenderEngine::raycasterManager() { + return *_raycasterManager; +} + void RenderEngine::setSceneGraph(Scene* sceneGraph) { _sceneGraph = sceneGraph; } diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index e26d5c260f..d05cb66d40 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -35,7 +35,7 @@ ScreenSpaceRenderable::ScreenSpaceRenderable() , _alpha("alpha", "Alpha" , 1, 0, 1) , _quad(0) , _vertexPositionBuffer(0) - ,_rendererPath("${SHADERS}/renderframebuffer.frag") + ,_rendererPath("${SHADERS}/framebuffer/renderframebuffer.frag") ,_vertexPath("${MODULE_BASE}/shaders/screnspace_vs.glsl") ,_fragmentPath("${MODULE_BASE}/shaders/screnspace_fs.glsl") ,_texture(nullptr) 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)