mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-21 12:29:04 -06:00
Interpolating points (#3002)
* Add a class for rendering an interpolated point cloud (WIP) * Make sure that we render the correct number of points * Group interpolation properties into a property owner * Update interpolation stuff (which was broken :) ) * Prevent interpolation from breaking with only one step or invalid interpolation values * Add trigger properties for controlling interpolation * Allow setting start interpolation value from asset * Implement spline-based interpolation * Cleanup, and interpolate to start and end * And asset type documentation * Add example asset * Handle missing data values in interpolation * Always show values at the knots, if there is one * Experiment with more dynamic rendering (batching) * Speed up interpolation by doing it on GPU instead of CPU * Bring back spline interpolation (this time on GPU) * Refactor initial data buffering * Add a helper function to compute transformed positions * Use vec3 positions instead of vec4 (less data to transfer) * Update interpolation value documentation * Apply suggestions from code review Co-authored-by: Alexander Bock <alexander.bock@liu.se> * Increase interpolation speed max value * Fix faulty indentation * I banish thee, redundant empty line --------- Co-authored-by: Alexander Bock <alexander.bock@liu.se>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
time,x,y,z,dynamic_value,static_value
|
||||
0.0,675.0297905065192,1672.6820684730765,-124.14442820502654,1,1
|
||||
0.0,9.0852354697237,1080.363474597831,266.4506394528842,3,3
|
||||
0.0,783.6498618493837,-332.90868790089644,166.73196289611994,5,5
|
||||
0.0,163.88116606175208,-978.1393719572736,1260.016529398092,10,10
|
||||
0.0,-934.1529593143864,-590.4853596059422,-622.5048517597389,11,11
|
||||
0.0,77.99426967464474,-184.5196836590583,1835.5681393474856,13,13
|
||||
0.0,77.99426967464474,-184.5196836590583,1835.5681393474856,14,14
|
||||
0.0,-269.98667369858055,-559.2891044933908,-1487.2591171480176,15,15
|
||||
0.0,-710.8143185498654,-627.4209210346181,-1504.56518583112,17,17
|
||||
0.0,-710.8143185498654,-627.4209210346181,-1504.56518583112,18,18
|
||||
1.0,1350.0595810130385,3345.364136946153,-248.28885641005309,2,1
|
||||
1.0,18.1704709394474,2160.726949195662,532.9012789057684,6,3
|
||||
1.0,1567.2997236987674,-665.8173758017929,333.4639257922399,10,5
|
||||
1.0,327.76233212350417,-1956.2787439145472,2520.033058796184,20,10
|
||||
1.0,-1868.3059186287728,-1180.9707192118844,-1245.0097035194779,22,11
|
||||
1.0,155.98853934928948,-369.0393673181166,3671.136278694971,26,13
|
||||
1.0,155.98853934928948,-369.0393673181166,3671.136278694971,28,14
|
||||
1.0,-539.9733473971611,-1118.5782089867816,-2974.518234296035,30,15
|
||||
1.0,-1421.628637099731,-1254.8418420692362,-3009.13037166224,34,17
|
||||
1.0,-1421.628637099731,-1254.8418420692362,-3009.13037166224,36,18
|
||||
2.0,2700.119162026077,6690.728273892306,-496.57771282010617,4,1
|
||||
2.0,36.3409418788948,4321.453898391324,1065.8025578115369,12,3
|
||||
2.0,3134.5994473975347,-1331.6347516035858,666.9278515844798,20,5
|
||||
2.0,655.5246642470083,-3912.5574878290945,5040.066117592368,40,10
|
||||
2.0,-3736.6118372575456,-2361.941438423769,-2490.0194070389557,44,11
|
||||
2.0,311.97707869857896,-738.0787346362332,7342.272557389942,52,13
|
||||
2.0,311.97707869857896,-738.0787346362332,7342.272557389942,56,14
|
||||
2.0,-1079.9466947943222,-2237.1564179735633,-5949.03646859207,60,15
|
||||
2.0,-2843.257274199462,-2509.6836841384725,-6018.26074332448,68,17
|
||||
2.0,-2843.257274199462,-2509.6836841384725,-6018.26074332448,72,18
|
||||
3.0,5400.238324052154,13381.456547784612,-993.1554256402123,8,1
|
||||
3.0,72.6818837577896,8642.907796782649,2131.6051156230737,24,3
|
||||
3.0,6269.1988947950695,-2663.2695032071715,1333.8557031689595,40,5
|
||||
3.0,1311.0493284940167,-7825.114975658189,10080.132235184736,80,10
|
||||
3.0,-7473.223674515091,-4723.882876847538,-4980.038814077911,88,11
|
||||
3.0,623.9541573971579,-1476.1574692724664,14684.545114779885,104,13
|
||||
3.0,623.9541573971579,-1476.1574692724664,14684.545114779885,112,14
|
||||
3.0,-2159.8933895886444,-4474.312835947127,-11898.07293718414,120,15
|
||||
3.0,-5686.514548398924,-5019.367368276945,-12036.52148664896,136,17
|
||||
3.0,-5686.514548398924,-5019.367368276945,-12036.52148664896,144,18
|
||||
4.0,10800.476648104308,26762.913095569224,-1986.3108512804247,16,1
|
||||
4.0,145.3637675155792,17285.815593565298,4263.2102312461475,48,3
|
||||
4.0,12538.397789590139,-5326.539006414343,2667.711406337919,80,5
|
||||
4.0,2622.0986569880333,-15650.229951316378,20160.26447036947,160,10
|
||||
4.0,-14946.447349030183,-9447.765753695076,-9960.077628155823,176,11
|
||||
4.0,1247.9083147943159,-2952.314938544933,29369.09022955977,208,13
|
||||
4.0,1247.9083147943159,-2952.314938544933,29369.09022955977,224,14
|
||||
4.0,-4319.786779177289,-8948.625671894253,-23796.14587436828,240,15
|
||||
4.0,-11373.029096797847,-10038.73473655389,-24073.04297329792,272,17
|
||||
4.0,-11373.029096797847,-10038.73473655389,-24073.04297329792,288,18
|
||||
5.0,21600.953296208616,53525.82619113845,-3972.6217025608494,32,1
|
||||
5.0,290.7275350311584,34571.631187130595,8526.420462492295,96,3
|
||||
5.0,25076.795579180278,-10653.078012828686,5335.422812675838,160,5
|
||||
5.0,5244.197313976067,-31300.459902632756,40320.52894073894,320,10
|
||||
5.0,-29892.894698060365,-18895.53150739015,-19920.155256311646,352,11
|
||||
5.0,2495.8166295886317,-5904.629877089866,58738.18045911954,416,13
|
||||
5.0,2495.8166295886317,-5904.629877089866,58738.18045911954,448,14
|
||||
5.0,-8639.573558354577,-17897.251343788506,-47592.29174873656,480,15
|
||||
5.0,-22746.058193595694,-20077.46947310778,-48146.08594659584,544,17
|
||||
5.0,-22746.058193595694,-20077.46947310778,-48146.08594659584,576,18
|
||||
|
@@ -0,0 +1,61 @@
|
||||
time,x,y,z
|
||||
0.0,675.0297905065192,1672.6820684730765,-124.14442820502654
|
||||
0.0,9.0852354697237,1080.363474597831,266.4506394528842
|
||||
0.0,783.6498618493837,-332.90868790089644,166.73196289611994
|
||||
0.0,163.88116606175208,-978.1393719572736,1260.016529398092
|
||||
0.0,-934.1529593143864,-590.4853596059422,-622.5048517597389
|
||||
0.0,77.99426967464474,-184.5196836590583,1835.5681393474856
|
||||
0.0,77.99426967464474,-184.5196836590583,1835.5681393474856
|
||||
0.0,-269.98667369858055,-559.2891044933908,-1487.2591171480176
|
||||
0.0,-710.8143185498654,-627.4209210346181,-1504.56518583112
|
||||
0.0,-710.8143185498654,-627.4209210346181,-1504.56518583112
|
||||
1.0,1668.4580965289847,745.846682848152,2807.1531096380813
|
||||
1.0,-267.4433668726456,148.90396745731732,-185.1019615201871
|
||||
1.0,2079.026938050769,151.01585523117177,301.7883722719676
|
||||
1.0,3209.940878877803,-4804.699861272869,-1589.4798430288217
|
||||
1.0,-1402.4597087610582,-4040.3210246320077,-1711.2703008101043
|
||||
1.0,-390.2796442237164,-1309.0947421410037,2057.413318767218
|
||||
1.0,3236.419900689428,-2210.181924327906,-466.4190154971202
|
||||
1.0,1264.882784607237,69.2055606971569,-735.8630804566736
|
||||
1.0,-1649.7630904197697,-2443.46907207704,-2705.84256566873
|
||||
1.0,374.30576862206385,-3452.028323705201,-2087.952685417674
|
||||
2.0,465.0448720701909,2222.779842838973,3455.3210484276715
|
||||
2.0,3437.11300214523,491.6405298372583,-955.2665223528202
|
||||
2.0,2052.032488574901,-80.28070954530929,-1052.0556283399499
|
||||
2.0,1094.5190209660022,-5406.907252451447,-366.127265347086
|
||||
2.0,242.63011544531992,-6997.3650053668625,350.72874418179754
|
||||
2.0,-2831.9669441657607,-2748.783158930421,3919.9735569996146
|
||||
2.0,3654.1470906989384,-3131.459466247481,-2144.8540619423975
|
||||
2.0,-2654.4574631523137,2183.4500131349887,-1354.287832159103
|
||||
2.0,-4306.135188216631,-1756.232492940117,-2043.315702861602
|
||||
2.0,768.0282403603109,-6978.108634430669,-136.86243117295544
|
||||
3.0,-493.303603620389,2945.5710538558005,3015.977272752648
|
||||
3.0,3065.7950488175957,3567.7136627691966,-241.04137932932736
|
||||
3.0,-160.63745943715548,-151.93278776521237,1903.7324611430824
|
||||
3.0,-1297.8942271953392,-2277.6199408234343,-1402.6677018943808
|
||||
3.0,1867.681760233716,-12236.85521354635,-1266.2584616045776
|
||||
3.0,-119.48688702411482,-1104.9781501799732,2916.459469830542
|
||||
3.0,3510.126847538271,-2957.3653297711385,-314.04982653824914
|
||||
3.0,-647.3916673682654,1585.4353122032537,-696.785612839734
|
||||
3.0,-3582.8631381213627,-1572.7109398691125,-3102.8361103956795
|
||||
3.0,-522.2112688499377,-10953.246463632455,889.6724350537568
|
||||
4.0,-299.1485049243082,114.829569754972,-821.5651578454349
|
||||
4.0,5003.085029883374,2726.4230172384787,-294.0691302277611
|
||||
4.0,-1564.7436471918602,-837.3618208187513,2024.1928810251354
|
||||
4.0,-1953.2185203908757,-3882.1744792666723,3523.8165230761915
|
||||
4.0,1083.4654539694006,-12559.426636878368,-1650.9803911668228
|
||||
4.0,-3046.516783288352,-296.8764365508964,3519.554154497767
|
||||
4.0,4102.367401667423,815.0064726499218,-383.47336594873576
|
||||
4.0,-125.2811230084867,1934.5909378669317,-3034.141688078798
|
||||
4.0,-3572.6362248364408,-1057.610158423584,-817.1904813656383
|
||||
4.0,-991.3855356002316,-11102.13829516479,2393.538500427305
|
||||
5.0,1282.9153891617857,-2986.4972923772934,-366.64528863717607
|
||||
5.0,3184.310120293896,2863.5489668505334,2320.216378337095
|
||||
5.0,1240.8449746803383,-2961.969248270961,-1190.7735880973198
|
||||
5.0,-4756.920645975437,-2934.989617996309,3893.0842401408
|
||||
5.0,2257.179641569941,-14398.275105345974,-1131.2148026699756
|
||||
5.0,1334.3944683316054,2802.9923734841823,5083.199898052388
|
||||
5.0,2121.294751406046,-751.5001120225525,-2857.3747877048995
|
||||
5.0,-1257.8765822140306,1290.4679054555804,-5675.05491424735
|
||||
5.0,-3373.3334946611585,569.4242763157556,226.69264986815688
|
||||
5.0,-1998.3368438326302,-13563.866928032701,2987.507846893677
|
||||
|
92
data/assets/examples/pointclouds/interpolated_points.asset
Normal file
92
data/assets/examples/pointclouds/interpolated_points.asset
Normal file
@@ -0,0 +1,92 @@
|
||||
local Points = {
|
||||
Identifier = "Example_InterpolatedPoints_ColorMapped",
|
||||
Renderable = {
|
||||
Type = "RenderableInterpolatedPoints",
|
||||
-- The dataset here is just a linearly expanding dataset, where the points move in
|
||||
-- a straight line
|
||||
File = asset.resource("data/interpolation_expand.csv"),
|
||||
-- Specify how many objects the rows in the dataset represent. Here, the dataset is
|
||||
-- consists of 10 objects with positions at 6 different time steps. This information
|
||||
-- is required
|
||||
NumberOfObjects = 10,
|
||||
-- Both the position and data values will be interpolated, so use a color map
|
||||
Coloring = {
|
||||
ColorMapping = {
|
||||
File = asset.resource("viridis.cmap")
|
||||
}
|
||||
},
|
||||
-- Reduce the scale of the points a bit compared to default, so we see them more clearly
|
||||
SizeSettings = {
|
||||
ScaleExponent = 3.5
|
||||
}
|
||||
},
|
||||
GUI = {
|
||||
Name = "Interpolating Points with Color Map",
|
||||
Path = "/Example/Interpolated Point Clouds",
|
||||
Description = [[Example of interpolating points with a color map. The data value
|
||||
used for the coloring will also be inteprolated, leading to the points changing
|
||||
color throughout the interpolation.]]
|
||||
}
|
||||
}
|
||||
|
||||
local Points_Smoothed = {
|
||||
Identifier = "Example_InterpolatedPoints_Spline",
|
||||
Renderable = {
|
||||
Type = "RenderableInterpolatedPoints",
|
||||
-- Using a random walk dataset, to get movement in some different directions
|
||||
File = asset.resource("data/interpolation_randomwalk.csv"),
|
||||
-- Same number of objects as above - 10 objects with positions at 6 different
|
||||
-- time steps
|
||||
NumberOfObjects = 10,
|
||||
Interpolation = {
|
||||
-- Smoothen transitions between two different sets of points, by
|
||||
-- using a spline based interpolation of the points
|
||||
UseSplineInterpolation = true
|
||||
},
|
||||
-- Just use a fixed coloring here, no color mapping
|
||||
Coloring = {
|
||||
FixedColor = { 0.0, 0.5, 0.0 }
|
||||
},
|
||||
-- Reduce the scale of the points a bit compared to default, so we see them more clearly
|
||||
SizeSettings = {
|
||||
ScaleExponent = 3.0
|
||||
}
|
||||
},
|
||||
GUI = {
|
||||
Name = "Interpolating Points (Spline)",
|
||||
Path = "/Example/Interpolated Point Clouds",
|
||||
Description = [[Example of interpolating points with spline-based interpolation
|
||||
for the position. This leads to smoother transitions at the nodes of the
|
||||
interpolation. Try disabling the spline interpolation in the GUI (under
|
||||
Renderable->Interpolation) to see the difference.]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.addSceneGraphNode(Points)
|
||||
openspace.addSceneGraphNode(Points_Smoothed)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.removeSceneGraphNode(Points_Smoothed)
|
||||
openspace.removeSceneGraphNode(Points)
|
||||
end)
|
||||
|
||||
asset.export(Points)
|
||||
asset.export(Points_Smoothed)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Example - Interpolated Point Clouds",
|
||||
Version = "1.0",
|
||||
Description = [[Example of point clouds that support interpolation. One uses a linear
|
||||
motion and color mapping. The other example uses a spline interpolation for the
|
||||
approximation of the positions, to result in smoother transitions between the sets
|
||||
of positions. The interpolation can be triggered using the properties under
|
||||
Renderable->Interpolation in the Scene menu.]],
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
}
|
||||
@@ -44,6 +44,7 @@ set(HEADER_FILES
|
||||
rendering/grids/renderablegrid.h
|
||||
rendering/grids/renderableradialgrid.h
|
||||
rendering/grids/renderablesphericalgrid.h
|
||||
rendering/pointcloud/renderableinterpolatedpoints.h
|
||||
rendering/pointcloud/renderablepointcloud.h
|
||||
rendering/pointcloud/renderablepolygoncloud.h
|
||||
rendering/renderablecartesianaxes.h
|
||||
@@ -105,6 +106,7 @@ set(SOURCE_FILES
|
||||
rendering/grids/renderablegrid.cpp
|
||||
rendering/grids/renderableradialgrid.cpp
|
||||
rendering/grids/renderablesphericalgrid.cpp
|
||||
rendering/pointcloud/renderableinterpolatedpoints.cpp
|
||||
rendering/pointcloud/renderablepointcloud.cpp
|
||||
rendering/pointcloud/renderablepolygoncloud.cpp
|
||||
rendering/renderablecartesianaxes.cpp
|
||||
@@ -152,9 +154,6 @@ set(SHADER_FILES
|
||||
shaders/arrow_vs.glsl
|
||||
shaders/axes_fs.glsl
|
||||
shaders/axes_vs.glsl
|
||||
shaders/billboardpoint_fs.glsl
|
||||
shaders/billboardpoint_gs.glsl
|
||||
shaders/billboardpoint_vs.glsl
|
||||
shaders/disc_fs.glsl
|
||||
shaders/disc_vs.glsl
|
||||
shaders/grid_vs.glsl
|
||||
@@ -167,6 +166,10 @@ set(SHADER_FILES
|
||||
shaders/model_vs.glsl
|
||||
shaders/plane_fs.glsl
|
||||
shaders/plane_vs.glsl
|
||||
shaders/pointcloud/billboardpoint_fs.glsl
|
||||
shaders/pointcloud/billboardpoint_gs.glsl
|
||||
shaders/pointcloud/billboardpoint_vs.glsl
|
||||
shaders/pointcloud/billboardpoint_interpolated_vs.glsl
|
||||
shaders/polygon_fs.glsl
|
||||
shaders/polygon_gs.glsl
|
||||
shaders/polygon_vs.glsl
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <modules/base/rendering/grids/renderablegrid.h>
|
||||
#include <modules/base/rendering/grids/renderableradialgrid.h>
|
||||
#include <modules/base/rendering/grids/renderablesphericalgrid.h>
|
||||
#include <modules/base/rendering/pointcloud/renderableinterpolatedpoints.h>
|
||||
#include <modules/base/rendering/pointcloud/renderablepointcloud.h>
|
||||
#include <modules/base/rendering/pointcloud/renderablepolygoncloud.h>
|
||||
#include <modules/base/rendering/renderablecartesianaxes.h>
|
||||
@@ -146,6 +147,9 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
fRenderable->registerClass<RenderablePlaneTimeVaryingImage>(
|
||||
"RenderablePlaneTimeVaryingImage"
|
||||
);
|
||||
fRenderable->registerClass<RenderableInterpolatedPoints>(
|
||||
"RenderableInterpolatedPoints"
|
||||
);
|
||||
fRenderable->registerClass<RenderablePointCloud>("RenderablePointCloud");
|
||||
fRenderable->registerClass<RenderablePolygonCloud>("RenderablePolygonCloud");
|
||||
fRenderable->registerClass<RenderablePrism>("RenderablePrism");
|
||||
@@ -226,6 +230,7 @@ std::vector<documentation::Documentation> BaseModule::documentations() const {
|
||||
RenderableCartesianAxes::Documentation(),
|
||||
RenderableDisc::Documentation(),
|
||||
RenderableGrid::Documentation(),
|
||||
RenderableInterpolatedPoints::Documentation(),
|
||||
RenderableLabel::Documentation(),
|
||||
RenderableModel::Documentation(),
|
||||
RenderableNodeArrow::Documentation(),
|
||||
|
||||
@@ -0,0 +1,544 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/base/rendering/pointcloud/renderableinterpolatedpoints.h>
|
||||
|
||||
#include <modules/base/basemodule.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/interpolator.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/opengl/texture.h>
|
||||
#include <optional>
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view _loggerCat = "RenderableInterpolatedPoints";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolationValueInfo = {
|
||||
"Value",
|
||||
"Value",
|
||||
"The value to use for interpolation. The max value is set from the number of "
|
||||
"steps in the dataset, so a step of one corresponds to one step in the dataset "
|
||||
"and values in-between will be determined using interpolation.",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo StepsInfo = {
|
||||
"NumberOfSteps",
|
||||
"Number of Steps",
|
||||
"The number of steps available in the dataset, including the initial positions.",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo JumpToNextInfo = {
|
||||
"JumpToNext",
|
||||
"Jump to Next",
|
||||
"Immediately set the interpolation value to correspond to the next set of point "
|
||||
"positions compared to the current.",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo JumpToPrevInfo = {
|
||||
"JumpToPrevious",
|
||||
"Jump to Previous",
|
||||
"Immediately set the interpolation value to correspond to the previous set of "
|
||||
"point positions compared to the current.",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolateToNextInfo = {
|
||||
"InterpolateToNext",
|
||||
"Interpolate to Next",
|
||||
"Trigger an interpolation to the next set of point positions. The duration of "
|
||||
"the interpolation is set based on the Interpolaton Speed property.",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolateToPrevInfo = {
|
||||
"InterpolateToPrevious",
|
||||
"Interpolate to Previous",
|
||||
"Trigger an interpolation to the previous set of point positions. The duration "
|
||||
"of the interpolation is set based on the Interpolaton Speed property.",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolateToEndInfo = {
|
||||
"InterpolateToEnd",
|
||||
"Interpolate to End",
|
||||
"Trigger an interpolation all the way to the final set of positions. The "
|
||||
"duration of the interpolation is set based on the Interpolaton Speed property.",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolateToStartInfo = {
|
||||
"InterpolateToStart",
|
||||
"Interpolate to Start",
|
||||
"Trigger an inverted interpolation to the initial set of positions. The duration "
|
||||
"of the interpolation is set based on the Interpolaton Speed property.",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InterpolationSpeedInfo = {
|
||||
"Speed",
|
||||
"Interpolation Speed",
|
||||
"Affects how long the interpolation takes when triggered using one of the "
|
||||
"trigger properties. A value of 1 means that a step takes 1 second.",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo UseSplineInfo = {
|
||||
"UseSplineInterpolation",
|
||||
"Use Spline Interpolation",
|
||||
"If true, the points will be interpolated using a Catmull-Rom spline instead of "
|
||||
"linearly. This leads to a smoother transition at the breakpoints, i.e. between "
|
||||
"each step.",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
// RenderableInterpolatedPoints is a version of the RenderablePointCloud class, where
|
||||
// the dataset may contain multiple time steps that can be interpolated between. It
|
||||
// supports interpolation of both of positions and data values used for color mapping
|
||||
// or size.
|
||||
//
|
||||
// The dataset should be structured in a way so that the first N rows correspond to
|
||||
// the first set of positions for the objects, the next N rows to the second set of
|
||||
// positions, and so on. The number of objects in the dataset must be specified in the
|
||||
// asset.
|
||||
struct [[codegen::Dictionary(RenderableInterpolatedPoints)]] Parameters {
|
||||
// The number of objects to read from the dataset. Every N:th datapoint will
|
||||
// be interpreted as the same point, but at a different step in the interpolation
|
||||
int numberOfObjects [[codegen::greaterequal(1)]];
|
||||
|
||||
struct Interpolation {
|
||||
// [[codegen::verbatim(InterpolationValueInfo.description)]]
|
||||
std::optional<double> value;
|
||||
|
||||
// [[codegen::verbatim(InterpolationSpeedInfo.description)]]
|
||||
std::optional<double> speed;
|
||||
|
||||
// [[codegen::verbatim(UseSplineInfo.description)]]
|
||||
std::optional<bool> useSplineInterpolation;
|
||||
};
|
||||
// Initial settings for the interpolation
|
||||
std::optional<Interpolation> interpolation;
|
||||
};
|
||||
|
||||
#include "renderableinterpolatedpoints_codegen.cpp"
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableInterpolatedPoints::Documentation() {
|
||||
return codegen::doc<Parameters>(
|
||||
"base_renderableinterpolatedpoints",
|
||||
RenderablePointCloud::Documentation()
|
||||
);
|
||||
}
|
||||
|
||||
RenderableInterpolatedPoints::Interpolation::Interpolation()
|
||||
: properties::PropertyOwner({ "Interpolation", "Interpolation", "" })
|
||||
, value(InterpolationValueInfo, 0.f, 0.f, 1.f)
|
||||
, nSteps(StepsInfo)
|
||||
, goToNextStep(JumpToNextInfo)
|
||||
, goToPrevStep(JumpToPrevInfo)
|
||||
, interpolateToNextStep(InterpolateToNextInfo)
|
||||
, interpolateToPrevStep(InterpolateToPrevInfo)
|
||||
, interpolateToEnd(InterpolateToEndInfo)
|
||||
, interpolateToStart(InterpolateToStartInfo)
|
||||
, speed(InterpolationSpeedInfo, 1.f, 0.01f, 100.f)
|
||||
, useSpline(UseSplineInfo, false)
|
||||
{
|
||||
addProperty(value);
|
||||
|
||||
auto triggerInterpolation = [](std::string_view identifier, float v, float d) {
|
||||
std::string script = fmt::format(
|
||||
"openspace.setPropertyValueSingle(\"{}\", {}, {})",
|
||||
identifier, v, d
|
||||
);
|
||||
// No syncing, as this was triggered from a property change (which happened
|
||||
// based on an already synced script)
|
||||
global::scriptEngine->queueScript(
|
||||
script,
|
||||
scripting::ScriptEngine::ShouldBeSynchronized::No,
|
||||
scripting::ScriptEngine::ShouldSendToRemote::No
|
||||
);
|
||||
};
|
||||
|
||||
interpolateToEnd.onChange([triggerInterpolation, this]() {
|
||||
float remaining = value.maxValue() - value;
|
||||
float duration = remaining / speed;
|
||||
triggerInterpolation(
|
||||
value.fullyQualifiedIdentifier(),
|
||||
value.maxValue(),
|
||||
duration
|
||||
);
|
||||
});
|
||||
|
||||
interpolateToStart.onChange([triggerInterpolation, this]() {
|
||||
float duration = value / speed;
|
||||
triggerInterpolation(value.fullyQualifiedIdentifier(), 0.f, duration);
|
||||
});
|
||||
|
||||
interpolateToNextStep.onChange([triggerInterpolation, this]() {
|
||||
float prevValue = glm::floor(value);
|
||||
float newValue = glm::min(prevValue + 1.f, value.maxValue());
|
||||
float duration = 1.f / speed;
|
||||
triggerInterpolation(value.fullyQualifiedIdentifier(), newValue, duration);
|
||||
});
|
||||
|
||||
interpolateToPrevStep.onChange([triggerInterpolation, this]() {
|
||||
float prevValue = glm::ceil(value);
|
||||
float newValue = glm::max(prevValue - 1.f, value.minValue());
|
||||
float duration = 1.f / speed;
|
||||
triggerInterpolation(value.fullyQualifiedIdentifier(), newValue, duration);
|
||||
});
|
||||
|
||||
addProperty(interpolateToEnd);
|
||||
addProperty(interpolateToStart);
|
||||
addProperty(interpolateToNextStep);
|
||||
addProperty(interpolateToPrevStep);
|
||||
addProperty(speed);
|
||||
|
||||
goToNextStep.onChange([this]() {
|
||||
float prevValue = glm::floor(value);
|
||||
value = glm::min(prevValue + 1.f, value.maxValue());
|
||||
});
|
||||
|
||||
goToPrevStep.onChange([this]() {
|
||||
float prevValue = glm::ceil(value);
|
||||
value = glm::max(prevValue - 1.f, value.minValue());
|
||||
});
|
||||
|
||||
addProperty(goToNextStep);
|
||||
addProperty(goToPrevStep);
|
||||
|
||||
nSteps.setReadOnly(true);
|
||||
addProperty(nSteps);
|
||||
|
||||
addProperty(useSpline);
|
||||
}
|
||||
|
||||
RenderableInterpolatedPoints::RenderableInterpolatedPoints(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
: RenderablePointCloud(dictionary)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
addPropertySubOwner(_interpolation);
|
||||
|
||||
if (p.interpolation.has_value()) {
|
||||
_interpolation.value = static_cast<float>(
|
||||
p.interpolation->value.value_or(_interpolation.value)
|
||||
);
|
||||
_interpolation.speed = static_cast<float>(
|
||||
p.interpolation->speed.value_or(_interpolation.speed)
|
||||
);
|
||||
_interpolation.useSpline = p.interpolation->useSplineInterpolation.value_or(
|
||||
_interpolation.useSpline
|
||||
);
|
||||
}
|
||||
|
||||
unsigned int nObjects = static_cast<unsigned int>(p.numberOfObjects);
|
||||
|
||||
// At this point, the dataset has been loaded and the number of points computed. We
|
||||
// need to recompute them and compute how many steps the number of points
|
||||
// corresponded to
|
||||
|
||||
if (_nDataPoints % nObjects != 0) {
|
||||
LERROR(fmt::format(
|
||||
"Mismatch between provided number of data entries and the specified number "
|
||||
"of points. Expected the number of entries in the data file {} to be evenly "
|
||||
"divisible by the number of points", _dataFile
|
||||
));
|
||||
}
|
||||
|
||||
_interpolation.nSteps = _nDataPoints / nObjects;
|
||||
_interpolation.value.setMaxValue(static_cast<float>(_interpolation.nSteps - 1));
|
||||
|
||||
_interpolation.value.onChange([this]() {
|
||||
bool passedAKnot =
|
||||
glm::ceil(_interpolation.value) != glm::ceil(_prevInterpolationValue);
|
||||
|
||||
if (passedAKnot) {
|
||||
_dataIsDirty = true;
|
||||
}
|
||||
_prevInterpolationValue = _interpolation.value;
|
||||
});
|
||||
|
||||
_interpolation.useSpline.onChange([this]() {
|
||||
_dataIsDirty = true;
|
||||
_shouldReinitializeBufferdata = true;
|
||||
});
|
||||
|
||||
// This property is mostly for show in the UI, but also used to tell how many points
|
||||
// should be rendered. So make sure it is updated once we know the number of
|
||||
// interpolation steps
|
||||
_nDataPoints = nObjects;
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::initializeShadersAndGlExtras() {
|
||||
_program = BaseModule::ProgramObjectManager.request(
|
||||
"RenderablePointCloud_Interpolated",
|
||||
[]() {
|
||||
return global::renderEngine->buildRenderProgram(
|
||||
"RenderablePointCloud_Interpolated",
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_interpolated_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_fs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_gs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
initializeBufferData();
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::deinitializeShaders() {
|
||||
BaseModule::ProgramObjectManager.release(
|
||||
"RenderablePointCloud_Interpolated",
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
global::renderEngine->removeRenderProgram(p);
|
||||
}
|
||||
);
|
||||
_program = nullptr;
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::bindDataForPointRendering() {
|
||||
RenderablePointCloud::bindDataForPointRendering();
|
||||
|
||||
float t0 = computeCurrentLowerValue();
|
||||
float t = glm::clamp(_interpolation.value - t0, 0.f, 1.f);
|
||||
_program->setUniform("interpolationValue", t);
|
||||
_program->setUniform("useSpline", _interpolation.useSpline);
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::preUpdate() {
|
||||
if (_shouldReinitializeBufferdata) {
|
||||
initializeBufferData();
|
||||
_shouldReinitializeBufferdata = false;
|
||||
}
|
||||
}
|
||||
|
||||
int RenderableInterpolatedPoints::nAttributesPerPoint() const {
|
||||
int n = RenderablePointCloud::nAttributesPerPoint();
|
||||
// Need twice as much information as the regular points
|
||||
n *= 2;
|
||||
if (_interpolation.useSpline) {
|
||||
// Use two more positions (xyz)
|
||||
n += 2 * 3;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::vector<float> RenderableInterpolatedPoints::createDataSlice() {
|
||||
ZoneScoped;
|
||||
|
||||
if (_dataset.entries.empty()) {
|
||||
return std::vector<float>();
|
||||
}
|
||||
|
||||
std::vector<float> result;
|
||||
result.reserve(nAttributesPerPoint() * _nDataPoints);
|
||||
|
||||
// Find the information we need for the interpolation and to identify the points,
|
||||
// and make sure these result in valid indices in all cases
|
||||
float t0 = computeCurrentLowerValue();
|
||||
float t1 = t0 + 1.f;
|
||||
t1 = glm::clamp(t1, 0.f, _interpolation.value.maxValue());
|
||||
unsigned int t0Index = static_cast<unsigned int>(t0);
|
||||
unsigned int t1Index = static_cast<unsigned int>(t1);
|
||||
|
||||
// What datavar is in use for the index color
|
||||
int colorParamIndex = currentColorParameterIndex();
|
||||
|
||||
// What datavar is in use for the size scaling (if present)
|
||||
int sizeParamIndex = currentSizeParameterIndex();
|
||||
|
||||
double maxRadius = 0.0;
|
||||
|
||||
for (unsigned int i = 0; i < _nDataPoints; i++) {
|
||||
using namespace dataloader;
|
||||
const Dataset::Entry& e0 = _dataset.entries[t0Index * _nDataPoints + i];
|
||||
const Dataset::Entry& e1 = _dataset.entries[t1Index * _nDataPoints + i];
|
||||
glm::dvec3 position0 = transformedPosition(e0);
|
||||
glm::dvec3 position1 = transformedPosition(e1);
|
||||
|
||||
const double r = glm::max(glm::length(position0), glm::length(position1));
|
||||
maxRadius = glm::max(maxRadius, r);
|
||||
|
||||
// Positions
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
result.push_back(static_cast<float>(position0[j]));
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
result.push_back(static_cast<float>(position1[j]));
|
||||
}
|
||||
|
||||
if (_interpolation.useSpline && _interpolation.nSteps > 1) {
|
||||
// Compute the extra positions, before and after the other ones
|
||||
unsigned int beforeIndex = static_cast<unsigned int>(
|
||||
glm::max(t0 - 1.f, 0.f)
|
||||
);
|
||||
unsigned int afterIndex = static_cast<unsigned int>(
|
||||
glm::min(t1 + 1.f, _interpolation.value.maxValue() - 1.f)
|
||||
);
|
||||
|
||||
const Dataset::Entry& e00 = _dataset.entries[beforeIndex * _nDataPoints + i];
|
||||
const Dataset::Entry& e11 = _dataset.entries[afterIndex * _nDataPoints + i];
|
||||
glm::dvec3 positionBefore = transformedPosition(e00);
|
||||
glm::dvec3 positionAfter = transformedPosition(e11);
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
result.push_back(static_cast<float>(positionBefore[j]));
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
result.push_back(static_cast<float>(positionAfter[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// Colors
|
||||
if (_hasColorMapFile) {
|
||||
result.push_back(e0.data[colorParamIndex]);
|
||||
result.push_back(e1.data[colorParamIndex]);
|
||||
}
|
||||
|
||||
// Size data
|
||||
if (_hasDatavarSize) {
|
||||
// @TODO: Consider more detailed control over the scaling. Currently the value
|
||||
// is multiplied with the value as is. Should have similar mapping properties
|
||||
// as the color mapping
|
||||
result.push_back(e0.data[sizeParamIndex]);
|
||||
result.push_back(e1.data[sizeParamIndex]);
|
||||
}
|
||||
|
||||
// @TODO: Also need to update label positions, if we have created labels from the dataset
|
||||
// And make sure these are created from only the first set of points..
|
||||
}
|
||||
setBoundingSphere(maxRadius);
|
||||
return result;
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::initializeBufferData() {
|
||||
if (_vao == 0) {
|
||||
glGenVertexArrays(1, &_vao);
|
||||
LDEBUG(fmt::format("Generating Vertex Array id '{}'", _vao));
|
||||
}
|
||||
if (_vbo == 0) {
|
||||
glGenBuffers(1, &_vbo);
|
||||
LDEBUG(fmt::format("Generating Vertex Buffer Object id '{}'", _vbo));
|
||||
}
|
||||
|
||||
const int attibutesPerPoint = nAttributesPerPoint();
|
||||
const unsigned int bufferSize = attibutesPerPoint * _nDataPoints * sizeof(float);
|
||||
|
||||
// Allocate the memory for the buffer (we will want to upload the data quite often)
|
||||
glBindVertexArray(_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
int attributeOffset = 0;
|
||||
|
||||
auto addFloatAttribute = [&](const std::string& name, GLint nValues) {
|
||||
GLint attrib = _program->attributeLocation(name);
|
||||
glEnableVertexAttribArray(attrib);
|
||||
glVertexAttribPointer(
|
||||
attrib,
|
||||
nValues,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
attibutesPerPoint * sizeof(float),
|
||||
(attributeOffset > 0) ?
|
||||
reinterpret_cast<void*>(attributeOffset * sizeof(float)) :
|
||||
nullptr
|
||||
);
|
||||
attributeOffset += nValues;
|
||||
};
|
||||
|
||||
addFloatAttribute("in_position0", 3);
|
||||
addFloatAttribute("in_position1", 3);
|
||||
|
||||
if (_interpolation.useSpline) {
|
||||
addFloatAttribute("in_position_before", 3);
|
||||
addFloatAttribute("in_position_after", 3);
|
||||
}
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
addFloatAttribute("in_colorParameter0", 1);
|
||||
addFloatAttribute("in_colorParameter1", 1);
|
||||
}
|
||||
|
||||
if (_hasDatavarSize) {
|
||||
addFloatAttribute("in_scalingParameter0", 1);
|
||||
addFloatAttribute("in_scalingParameter1", 1);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void RenderableInterpolatedPoints::updateBufferData() {
|
||||
if (!_hasDataFile || _dataset.entries.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScopedN("Data dirty");
|
||||
TracyGpuZone("Data dirty");
|
||||
LDEBUG("Regenerating data");
|
||||
|
||||
// Regenerate data and update buffer
|
||||
std::vector<float> slice = createDataSlice();
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, slice.size() * sizeof(float), slice.data());
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
_dataIsDirty = false;
|
||||
}
|
||||
|
||||
bool RenderableInterpolatedPoints::isAtKnot() const {
|
||||
float v = _interpolation.value;
|
||||
return (v - glm::floor(v)) < std::numeric_limits<float>::epsilon();
|
||||
}
|
||||
|
||||
float RenderableInterpolatedPoints::computeCurrentLowerValue() const {
|
||||
float t0 = glm::floor(_interpolation.value);
|
||||
|
||||
if (isAtKnot()) {
|
||||
t0 = t0 - 1.f;
|
||||
}
|
||||
|
||||
const float maxTValue = _interpolation.value.maxValue();
|
||||
float maxAllowedT0 = glm::max(maxTValue - 1.f, 0.f);
|
||||
t0 = glm::clamp(t0, 0.f, maxAllowedT0);
|
||||
return t0;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
100
modules/base/rendering/pointcloud/renderableinterpolatedpoints.h
Normal file
100
modules/base/rendering/pointcloud/renderableinterpolatedpoints.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEINTERPOLATEDPOINTS___H__
|
||||
#define __OPENSPACE_MODULE_BASE___RENDERABLEINTERPOLATEDPOINTS___H__
|
||||
|
||||
#include <modules/base/rendering/pointcloud/renderablepointcloud.h>
|
||||
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/uintproperty.h>
|
||||
#include <openspace/properties/triggerproperty.h>
|
||||
|
||||
namespace ghoul::opengl { class Texture; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
/**
|
||||
* A specialization of the RenderablePointCloud that supports interpolation beetween
|
||||
* different positions for the points.
|
||||
*/
|
||||
class RenderableInterpolatedPoints : public RenderablePointCloud {
|
||||
public:
|
||||
explicit RenderableInterpolatedPoints(const ghoul::Dictionary& dictionary);
|
||||
~RenderableInterpolatedPoints() override = default;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
protected:
|
||||
void initializeShadersAndGlExtras() override;
|
||||
void deinitializeShaders() override;
|
||||
void bindDataForPointRendering() override;
|
||||
void preUpdate() override;
|
||||
|
||||
int nAttributesPerPoint() const override;
|
||||
|
||||
/**
|
||||
* Create the data slice to use for rendering the points. Compared to the regular
|
||||
* point cloud, the data slice for an interpolated set of points will have to be
|
||||
* recreated when the interpolation value changes, and will only include a subset of
|
||||
* the points in the entire dataset
|
||||
*
|
||||
* \return The dataslice to use for rendering the points
|
||||
*/
|
||||
std::vector<float> createDataSlice() override;
|
||||
|
||||
void initializeBufferData();
|
||||
void updateBufferData() override;
|
||||
|
||||
private:
|
||||
bool isAtKnot() const;
|
||||
float computeCurrentLowerValue() const;
|
||||
|
||||
struct Interpolation : public properties::PropertyOwner {
|
||||
Interpolation();
|
||||
properties::FloatProperty value;
|
||||
properties::UIntProperty nSteps;
|
||||
|
||||
properties::TriggerProperty goToNextStep;
|
||||
properties::TriggerProperty goToPrevStep;
|
||||
properties::TriggerProperty interpolateToNextStep;
|
||||
properties::TriggerProperty interpolateToPrevStep;
|
||||
properties::TriggerProperty interpolateToEnd;
|
||||
properties::TriggerProperty interpolateToStart;
|
||||
properties::FloatProperty speed;
|
||||
|
||||
properties::BoolProperty useSpline;
|
||||
};
|
||||
Interpolation _interpolation;
|
||||
|
||||
float _prevInterpolationValue = 0.f;
|
||||
bool _shouldReinitializeBufferdata = false;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_BASE___RENDERABLEINTERPOLATEDPOINTS___H__
|
||||
@@ -628,17 +628,7 @@ void RenderablePointCloud::initialize() {
|
||||
void RenderablePointCloud::initializeGL() {
|
||||
ZoneScoped;
|
||||
|
||||
_program = BaseModule::ProgramObjectManager.request(
|
||||
"RenderablePointCloud",
|
||||
[]() {
|
||||
return global::renderEngine->buildRenderProgram(
|
||||
"RenderablePointCloud",
|
||||
absPath("${MODULE_BASE}/shaders/billboardpoint_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/billboardpoint_fs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/billboardpoint_gs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
initializeShadersAndGlExtras();
|
||||
|
||||
ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames);
|
||||
|
||||
@@ -653,6 +643,27 @@ void RenderablePointCloud::deinitializeGL() {
|
||||
glDeleteVertexArrays(1, &_vao);
|
||||
_vao = 0;
|
||||
|
||||
deinitializeShaders();
|
||||
|
||||
BaseModule::TextureManager.release(_spriteTexture);
|
||||
_spriteTexture = nullptr;
|
||||
}
|
||||
|
||||
void RenderablePointCloud::initializeShadersAndGlExtras() {
|
||||
_program = BaseModule::ProgramObjectManager.request(
|
||||
"RenderablePointCloud",
|
||||
[]() {
|
||||
return global::renderEngine->buildRenderProgram(
|
||||
"RenderablePointCloud",
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_fs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/pointcloud/billboardpoint_gs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void RenderablePointCloud::deinitializeShaders() {
|
||||
BaseModule::ProgramObjectManager.release(
|
||||
"RenderablePointCloud",
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
@@ -660,9 +671,6 @@ void RenderablePointCloud::deinitializeGL() {
|
||||
}
|
||||
);
|
||||
_program = nullptr;
|
||||
|
||||
BaseModule::TextureManager.release(_spriteTexture);
|
||||
_spriteTexture = nullptr;
|
||||
}
|
||||
|
||||
void RenderablePointCloud::bindTextureForRendering() const {
|
||||
@@ -699,51 +707,8 @@ float RenderablePointCloud::computeDistanceFadeValue(const RenderData& data) con
|
||||
return fadeValue * funcValue;
|
||||
}
|
||||
|
||||
void RenderablePointCloud::renderBillboards(const RenderData& data,
|
||||
const glm::dmat4& modelMatrix,
|
||||
const glm::dvec3& orthoRight,
|
||||
const glm::dvec3& orthoUp,
|
||||
float fadeInVariable)
|
||||
{
|
||||
if (!_hasDataFile || _dataset.entries.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glEnablei(GL_BLEND, 0);
|
||||
|
||||
if (_useAdditiveBlending) {
|
||||
glDepthMask(false);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
}
|
||||
else {
|
||||
// Normal blending, with transparency
|
||||
glDepthMask(true);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
_program->activate();
|
||||
|
||||
_program->setUniform(_uniformCache.cameraPos, data.camera.positionVec3());
|
||||
_program->setUniform(
|
||||
_uniformCache.cameraLookup,
|
||||
glm::vec3(data.camera.lookUpVectorWorldSpace())
|
||||
);
|
||||
void RenderablePointCloud::bindDataForPointRendering() {
|
||||
_program->setUniform(_uniformCache.renderOption, _renderOption.value());
|
||||
_program->setUniform(_uniformCache.modelMatrix, modelMatrix);
|
||||
|
||||
_program->setUniform(
|
||||
_uniformCache.cameraViewMatrix,
|
||||
data.camera.combinedViewMatrix()
|
||||
);
|
||||
|
||||
_program->setUniform(
|
||||
_uniformCache.projectionMatrix,
|
||||
glm::dmat4(data.camera.projectionMatrix())
|
||||
);
|
||||
|
||||
_program->setUniform(_uniformCache.up, glm::vec3(orthoUp));
|
||||
_program->setUniform(_uniformCache.right, glm::vec3(orthoRight));
|
||||
_program->setUniform(_uniformCache.fadeInValue, fadeInVariable);
|
||||
_program->setUniform(_uniformCache.opacity, opacity());
|
||||
|
||||
_program->setUniform(_uniformCache.scaleExponent, _sizeSettings.scaleExponent);
|
||||
@@ -811,9 +776,58 @@ void RenderablePointCloud::renderBillboards(const RenderData& data,
|
||||
_colorSettings.colorMapping->useBelowRangeColor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePointCloud::renderBillboards(const RenderData& data,
|
||||
const glm::dmat4& modelMatrix,
|
||||
const glm::dvec3& orthoRight,
|
||||
const glm::dvec3& orthoUp,
|
||||
float fadeInVariable)
|
||||
{
|
||||
if (!_hasDataFile || _dataset.entries.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glEnablei(GL_BLEND, 0);
|
||||
|
||||
if (_useAdditiveBlending) {
|
||||
glDepthMask(false);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
}
|
||||
else {
|
||||
// Normal blending, with transparency
|
||||
glDepthMask(true);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
_program->activate();
|
||||
|
||||
_program->setUniform(_uniformCache.cameraPos, data.camera.positionVec3());
|
||||
_program->setUniform(
|
||||
_uniformCache.cameraLookup,
|
||||
glm::vec3(data.camera.lookUpVectorWorldSpace())
|
||||
);
|
||||
_program->setUniform(_uniformCache.renderOption, _renderOption.value());
|
||||
_program->setUniform(_uniformCache.modelMatrix, modelMatrix);
|
||||
|
||||
_program->setUniform(
|
||||
_uniformCache.cameraViewMatrix,
|
||||
data.camera.combinedViewMatrix()
|
||||
);
|
||||
|
||||
_program->setUniform(
|
||||
_uniformCache.projectionMatrix,
|
||||
glm::dmat4(data.camera.projectionMatrix())
|
||||
);
|
||||
|
||||
_program->setUniform(_uniformCache.up, glm::vec3(orthoUp));
|
||||
_program->setUniform(_uniformCache.right, glm::vec3(orthoRight));
|
||||
_program->setUniform(_uniformCache.fadeInValue, fadeInVariable);
|
||||
|
||||
bindDataForPointRendering();
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_dataset.entries.size()));
|
||||
glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_nDataPoints));
|
||||
glBindVertexArray(0);
|
||||
_program->deactivate();
|
||||
|
||||
@@ -857,9 +871,13 @@ void RenderablePointCloud::render(const RenderData& data, RendererTasks&) {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePointCloud::preUpdate() {}
|
||||
|
||||
void RenderablePointCloud::update(const UpdateData&) {
|
||||
ZoneScoped;
|
||||
|
||||
preUpdate();
|
||||
|
||||
if (_dataIsDirty) {
|
||||
updateBufferData();
|
||||
}
|
||||
@@ -869,8 +887,16 @@ void RenderablePointCloud::update(const UpdateData&) {
|
||||
}
|
||||
}
|
||||
|
||||
glm::dvec3 RenderablePointCloud::transformedPosition(
|
||||
const dataloader::Dataset::Entry& e) const
|
||||
{
|
||||
const double unitMeter = toMeter(_unit);
|
||||
glm::dvec4 position = glm::dvec4(glm::dvec3(e.position) * unitMeter, 1.0);
|
||||
return glm::dvec3(_transformationMatrix * position);
|
||||
}
|
||||
|
||||
int RenderablePointCloud::nAttributesPerPoint() const {
|
||||
int n = 4; // position
|
||||
int n = 3; // position
|
||||
n += _hasColorMapFile ? 1 : 0;
|
||||
n += _hasDatavarSize ? 1 : 0;
|
||||
return n;
|
||||
@@ -909,13 +935,13 @@ void RenderablePointCloud::updateBufferData() {
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
glVertexAttribPointer(
|
||||
positionAttrib,
|
||||
4,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
attibutesPerPoint * sizeof(float),
|
||||
nullptr
|
||||
);
|
||||
attributeOffset += 4;
|
||||
attributeOffset += 3;
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
GLint colorParamAttrib = _program->attributeLocation("in_colorParameter");
|
||||
@@ -1022,24 +1048,20 @@ std::vector<float> RenderablePointCloud::createDataSlice() {
|
||||
int sizeParamIndex = currentSizeParameterIndex();
|
||||
|
||||
double maxRadius = 0.0;
|
||||
double biggestCoord = -1.0;
|
||||
|
||||
for (const dataloader::Dataset::Entry& e : _dataset.entries) {
|
||||
const double unitMeter = toMeter(_unit);
|
||||
glm::dvec4 position = glm::dvec4(glm::dvec3(e.position) * unitMeter, 1.0);
|
||||
position = _transformationMatrix * position;
|
||||
glm::dvec3 position = transformedPosition(e);
|
||||
|
||||
const double r = glm::length(position);
|
||||
maxRadius = std::max(maxRadius, r);
|
||||
|
||||
// Positions
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
result.push_back(static_cast<float>(position[j]));
|
||||
}
|
||||
|
||||
// Colors
|
||||
if (_hasColorMapFile) {
|
||||
biggestCoord = std::max(biggestCoord, glm::compMax(position));
|
||||
result.push_back(e.data[colorParamIndex]);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,16 @@ public:
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
protected:
|
||||
int nAttributesPerPoint() const;
|
||||
void updateBufferData();
|
||||
virtual void initializeShadersAndGlExtras();
|
||||
virtual void deinitializeShaders();
|
||||
virtual void bindDataForPointRendering();
|
||||
virtual void preUpdate();
|
||||
|
||||
glm::dvec3 transformedPosition(const dataloader::Dataset::Entry& e) const;
|
||||
|
||||
virtual int nAttributesPerPoint() const;
|
||||
|
||||
virtual void updateBufferData();
|
||||
void updateSpriteTexture();
|
||||
|
||||
/// Find the index of the currently chosen color parameter in the dataset
|
||||
@@ -83,7 +91,7 @@ protected:
|
||||
/// Find the index of the currently chosen size parameter in the dataset
|
||||
int currentSizeParameterIndex() const;
|
||||
|
||||
std::vector<float> createDataSlice();
|
||||
virtual std::vector<float> createDataSlice();
|
||||
|
||||
virtual void bindTextureForRendering() const;
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "PowerScaling/powerScaling_vs.hglsl"
|
||||
|
||||
in vec3 in_position0;
|
||||
in vec3 in_position1;
|
||||
|
||||
// Only used if spline interpolation is desired
|
||||
in vec3 in_position_before;
|
||||
in vec3 in_position_after;
|
||||
|
||||
in float in_colorParameter0;
|
||||
in float in_colorParameter1;
|
||||
in float in_scalingParameter0;
|
||||
in float in_scalingParameter1;
|
||||
|
||||
uniform bool useSpline;
|
||||
uniform float interpolationValue;
|
||||
|
||||
flat out float colorParameter;
|
||||
flat out float scalingParameter;
|
||||
|
||||
float interpolateDataValue(float v0, float v1, float t) {
|
||||
const float Epsilon = 1E-7;
|
||||
const float NaN = log(-1.0); // undefined
|
||||
// To make sure we render values at knots with neighboring missing values,
|
||||
// check 0 and 1 expicitly
|
||||
if (abs(t) < Epsilon) {
|
||||
return v0;
|
||||
}
|
||||
if (abs(1.0 - t) < Epsilon) {
|
||||
return v1;
|
||||
}
|
||||
bool isMissing = isnan(v0) || isnan(v1);
|
||||
return isMissing ? NaN : mix(v0, v1, t);
|
||||
}
|
||||
|
||||
vec3 interpolateCatmullRom(float t, vec3 p0, vec3 p1, vec3 p2, vec3 p3) {
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
return 0.5 * (
|
||||
2.0 * p1 +
|
||||
t * (p2 - p0) +
|
||||
t2 * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) +
|
||||
t3 * (3.0 * p1 - p0 - 3.0 * p2 + p3)
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float t = interpolationValue;
|
||||
|
||||
colorParameter = interpolateDataValue(in_colorParameter0, in_colorParameter1, t);
|
||||
scalingParameter = interpolateDataValue(in_scalingParameter0, in_scalingParameter1, t);
|
||||
|
||||
vec3 position = mix(in_position0, in_position1, t);
|
||||
if (useSpline) {
|
||||
position = interpolateCatmullRom(
|
||||
t,
|
||||
in_position_before,
|
||||
in_position0,
|
||||
in_position1,
|
||||
in_position_after
|
||||
);
|
||||
}
|
||||
|
||||
gl_Position = vec4(position, 1.0);
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "PowerScaling/powerScaling_vs.hglsl"
|
||||
|
||||
in vec4 in_position;
|
||||
in vec3 in_position;
|
||||
in float in_colorParameter;
|
||||
in float in_scalingParameter;
|
||||
|
||||
@@ -36,5 +36,5 @@ flat out float scalingParameter;
|
||||
void main() {
|
||||
colorParameter = in_colorParameter;
|
||||
scalingParameter = in_scalingParameter;
|
||||
gl_Position = in_position;
|
||||
gl_Position = vec4(in_position, 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user