diff --git a/modules/globebrowsing/chunk/chunk.cpp b/modules/globebrowsing/chunk/chunk.cpp index 86a98b29db..7113c4acdb 100644 --- a/modules/globebrowsing/chunk/chunk.cpp +++ b/modules/globebrowsing/chunk/chunk.cpp @@ -100,20 +100,44 @@ namespace openspace { // In the future, this should be abstracted away and more easily queryable. // One must also handle how to sample pick one out of multiplte heightmaps - auto tileProvidermanager = owner()->getTileProviderManager(); - auto heightMapProviders = tileProvidermanager->getTileProviderGroup(LayeredTextures::HeightMaps).getActiveTileProviders(); - if (heightMapProviders.size() > 0) { - TileAndTransform tileAndTransform = TileSelector::getHighestResolutionTile(heightMapProviders[0].get(), _index); - if (tileAndTransform.tile.status == Tile::Status::OK) { - std::shared_ptr preprocessData = tileAndTransform.tile.preprocessData; - if ((preprocessData != nullptr) && preprocessData->maxValues.size() > 0) { - boundingHeights.max = preprocessData->maxValues[0]; + auto tileProviderManager = owner()->getTileProviderManager(); + + + auto heightMapProviders = tileProviderManager->getTileProviderGroup(LayeredTextures::HeightMaps).getActiveTileProviders(); + + const TileProviderGroup& heightmaps = tileProviderManager->getTileProviderGroup(LayeredTextures::HeightMaps); + TileAndTransform mostHighResHeightmap = TileSelector::getHighestResolutionTile(heightmaps, _index); + if (mostHighResHeightmap.tile.status == Tile::Status::OK) { + auto preprocessData = mostHighResHeightmap.tile.preprocessData; + if (preprocessData != nullptr && preprocessData->minValues[0] < preprocessData->maxValues[0]) { + boundingHeights.min = preprocessData->minValues[0]; + boundingHeights.max = preprocessData->maxValues[0]; + boundingHeights.available = true; + } + } + + const TileProviderGroup& heightmapOverlays = tileProviderManager->getTileProviderGroup(LayeredTextures::HeightMapOverlays); + TileAndTransform mostHighResHeightmapOverlay = TileSelector::getHighestResolutionTile(heightmapOverlays, _index); + if (mostHighResHeightmapOverlay.tile.status == Tile::Status::OK) { + auto preprocessData = mostHighResHeightmapOverlay.tile.preprocessData; + if (preprocessData != nullptr && preprocessData->minValues[0] < preprocessData->maxValues[0]) { + if (boundingHeights.available) { + boundingHeights.min = std::min(boundingHeights.min, preprocessData->minValues[0]); + boundingHeights.max = std::max(boundingHeights.max, preprocessData->maxValues[0]); + } + else { boundingHeights.min = preprocessData->minValues[0]; + boundingHeights.max = preprocessData->maxValues[0]; boundingHeights.available = true; + + if (preprocessData->hasMissingData[0]) { + boundingHeights.min = std::min(0.0f, preprocessData->minValues[0]); + boundingHeights.max = std::max(0.0f, preprocessData->maxValues[0]); + } } } } - + return boundingHeights; } diff --git a/modules/globebrowsing/chunk/chunkedlodglobe.h b/modules/globebrowsing/chunk/chunkedlodglobe.h index 61efb5d074..cbeb229b40 100644 --- a/modules/globebrowsing/chunk/chunkedlodglobe.h +++ b/modules/globebrowsing/chunk/chunkedlodglobe.h @@ -110,6 +110,8 @@ namespace openspace { bool showChunkEdges = false; bool showChunkBounds = false; bool showChunkAABB = false; + bool showHeightResolution = false; + bool showHeightIntensities = false; bool doHorizonCulling = true; bool doFrustumCulling = true; diff --git a/modules/globebrowsing/chunk/chunkrenderer.cpp b/modules/globebrowsing/chunk/chunkrenderer.cpp index 1229f9e542..d1484ed3b3 100644 --- a/modules/globebrowsing/chunk/chunkrenderer.cpp +++ b/modules/globebrowsing/chunk/chunkrenderer.cpp @@ -186,6 +186,17 @@ namespace openspace { std::to_string(chunk.owner()->debugOptions.showChunkEdges))); + layeredTexturePreprocessingData.keyValuePairs.push_back( + std::pair( + "showHeightResolution", + std::to_string(chunk.owner()->debugOptions.showHeightResolution))); + + layeredTexturePreprocessingData.keyValuePairs.push_back( + std::pair( + "showHeightIntensities", + std::to_string(chunk.owner()->debugOptions.showHeightIntensities))); + + // Now the shader program can be accessed ProgramObject* programObject = layeredTextureShaderProvider->getUpdatedShaderProgram( @@ -308,7 +319,7 @@ namespace openspace { programObject->setUniform("skirtLength", min(static_cast(chunk.surfacePatch().halfSize().lat * 1000000), 8700.0f)); programObject->setUniform("xSegments", _grid->xSegments()); - if (tileProviders[LayeredTextures::ColorTextures].size() == 0) { + if (chunk.owner()->debugOptions.showHeightResolution) { programObject->setUniform("vertexResolution", glm::vec2(_grid->xSegments(), _grid->ySegments())); } diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 32c1d32088..61c3e8ab00 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -104,6 +104,8 @@ namespace openspace { debugSelection.addOption("Show chunk edges", &_chunkedLodGlobe->debugOptions.showChunkEdges); debugSelection.addOption("Show chunk bounds", &_chunkedLodGlobe->debugOptions.showChunkBounds); debugSelection.addOption("Show chunk AABB", &_chunkedLodGlobe->debugOptions.showChunkAABB); + debugSelection.addOption("Show height resolution", &_chunkedLodGlobe->debugOptions.showHeightResolution); + debugSelection.addOption("Show height intensities", &_chunkedLodGlobe->debugOptions.showHeightIntensities); debugSelection.addOption("Culling: Frustum", &_chunkedLodGlobe->debugOptions.doFrustumCulling); debugSelection.addOption("Culling: Horizon", &_chunkedLodGlobe->debugOptions.doHorizonCulling); diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl index 53b42db12b..b0ef5f6320 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl @@ -38,6 +38,13 @@ uniform vec2 minLatLon; uniform vec2 lonLatScalingFactor; uniform vec3 cameraPosition; +layout(location = 1) in vec2 in_uv; + +out vec2 fs_uv; +out vec4 fs_position; +out vec3 ellipsoidNormalCameraSpace; +out LevelWeights levelWeights; + PositionNormalPair globalInterpolation() { vec2 lonLatInput; lonLatInput.y = minLatLon.y + lonLatScalingFactor.y * in_uv.y; // Lat @@ -50,8 +57,13 @@ void main() { PositionNormalPair pair = globalInterpolation(); float distToVertexOnEllipsoid = length(pair.position - cameraPosition); + float levelInterpolationParameter = getLevelInterpolationParameter(chunkLevel, distanceScaleFactor, distToVertexOnEllipsoid); + + // use level weight for height sampling, and output to fragment shader + levelWeights = getLevelWeights(levelInterpolationParameter); + // Get the height value - float height = getTileVertexHeight(distToVertexOnEllipsoid); + float height = getTileVertexHeight(in_uv, levelWeights); // Apply skirts height -= getTileVertexSkirtLength(); diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl index 306ca979bc..effe154b4e 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl @@ -40,6 +40,14 @@ uniform vec3 p01; uniform vec3 p11; uniform vec3 patchNormalCameraSpace; +layout(location = 1) in vec2 in_uv; + +out vec2 fs_uv; +out vec4 fs_position; +out vec3 ellipsoidNormalCameraSpace; +out LevelWeights levelWeights; + + vec3 bilinearInterpolation(vec2 uv) { vec3 p0 = (1 - uv.x) * p00 + uv.x * p10; vec3 p1 = (1 - uv.x) * p01 + uv.x * p11; @@ -48,16 +56,20 @@ vec3 bilinearInterpolation(vec2 uv) { } void main() { - + // Position in cameraspace vec3 p = bilinearInterpolation(in_uv); // Calculate desired level based on distance to the vertex on the ellipsoid // Before any heightmapping is done float distToVertexOnEllipsoid = length(p); + float levelInterpolationParameter = getLevelInterpolationParameter(chunkLevel, distanceScaleFactor, distToVertexOnEllipsoid); + + // use level weight for height sampling, and output to fragment shader + levelWeights = getLevelWeights(levelInterpolationParameter); // Get the height value - float height = getTileVertexHeight(distToVertexOnEllipsoid); + float height = getTileVertexHeight(in_uv, levelWeights); // Apply skirts height -= getTileVertexSkirtLength(); diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index 770ced4fda..2173f45db3 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -66,6 +66,35 @@ // Other key value pairs used for settings #define USE_ATMOSPHERE #{useAtmosphere} #define SHOW_CHUNK_EDGES #{showChunkEdges} +#define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} +#define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} + +float calculateUntransformedHeight( + vec2 uv, + LevelWeights levelWeights, + const Tile heightTiles[NUMLAYERS_HEIGHTMAP], + const Tile heightTilesParent1[NUMLAYERS_HEIGHTMAP], + const Tile heightTilesParent2[NUMLAYERS_HEIGHTMAP]) { + + float height = 0; + + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 +#if !HEIGHTMAP_BLENDING_ENABLED + levelWeights = getDefaultLevelWeights(); +#endif // HEIGHTMAP_BLENDING_ENABLED + + + #for i in 0..#{lastLayerIndexHeightMaps} + { + height = + levelWeights.w1 * getTexVal(heightTiles[#{i}], uv).r + + levelWeights.w2 * getTexVal(heightTilesParent1[#{i}], uv).r + + levelWeights.w3 * getTexVal(heightTilesParent2[#{i}], uv).r; + } + #endfor + return height; +} float calculateHeight( vec2 uv, @@ -98,6 +127,43 @@ float calculateHeight( return height; } + + +float calculateUntransformedHeightOverlay( + float currentHeight, + vec2 uv, + LevelWeights levelWeights, + const Tile heightOverlayTiles[NUMLAYERS_HEIGHTMAP_OVERLAY], + const Tile heightOverlayTilesParent1[NUMLAYERS_HEIGHTMAP_OVERLAY], + const Tile heightOverlayTilesParent2[NUMLAYERS_HEIGHTMAP_OVERLAY]) { + + float height = currentHeight; + + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 +#if !HEIGHTMAP_OVERLAY_BLENDING_ENABLED + levelWeights = getDefaultLevelWeights(); +#endif // HEIGHTMAP_OVERLAY_BLENDING_ENABLED + + #for i in 0..#{lastLayerIndexHeightMapOverlays} + { + vec4 untransformedHeightSample = + levelWeights.w1 * getTexVal(heightOverlayTiles[#{i}], uv) + + levelWeights.w2 * getTexVal(heightOverlayTilesParent1[#{i}], uv) + + levelWeights.w3 * getTexVal(heightOverlayTilesParent2[#{i}], uv); + + if (untransformedHeightSample.g > 0.5){ + // Float datasets will return un-normalized values, and needs to + // be downscaled in order to be visualized. + float scaleFactor = 0.00005; + height = scaleFactor * untransformedHeightSample.r; + } + } + #endfor + + return height; +} + float calculateHeightOverlay( float currentHeight, vec2 uv, diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index e58f93a169..cc91d50657 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -110,6 +110,12 @@ struct LevelWeights { float w3; }; +float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor, float distToVertexOnEllipsoid){ + float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; + float desiredLevel = log2(projectedScaleFactor); + return chunkLevel - desiredLevel; +} + LevelWeights getLevelWeights(float levelInterpolationParameter){ LevelWeights levelWeights; levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1); diff --git a/modules/globebrowsing/shaders/tilefragcolor.hglsl b/modules/globebrowsing/shaders/tilefragcolor.hglsl index e0bc728ee4..84f5b4b397 100644 --- a/modules/globebrowsing/shaders/tilefragcolor.hglsl +++ b/modules/globebrowsing/shaders/tilefragcolor.hglsl @@ -22,6 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#ifndef TILE_FRAG_COLOR_HGLSL +#define TILE_FRAG_COLOR_HGLSL + #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> #include "PowerScaling/powerScaling_fs.hglsl" @@ -30,18 +33,7 @@ // The heightmaps is only used in the fragment shader visually debugging // the alignment and resolution of the heightmaps - -#if USE_HEIGHTMAP -uniform Tile HeightMaps[NUMLAYERS_HEIGHTMAP]; -uniform Tile HeightMapsParent1[NUMLAYERS_HEIGHTMAP]; -uniform Tile HeightMapsParent2[NUMLAYERS_HEIGHTMAP]; -#endif // USE_HEIGHTMAP - -#if USE_HEIGHTMAP_OVERLAY -uniform Tile HeightMapOverlays[NUMLAYERS_HEIGHTMAP_OVERLAY]; -uniform Tile HeightMapOverlaysParent1[NUMLAYERS_HEIGHTMAP_OVERLAY]; -uniform Tile HeightMapOverlaysParent2[NUMLAYERS_HEIGHTMAP_OVERLAY]; -#endif // USE_HEIGHTMAP_OVERLAY +#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexheight.hglsl> @@ -78,14 +70,15 @@ uniform Tile WaterMasksParent1[NUMLAYERS_WATERMASK]; uniform Tile WaterMasksParent2[NUMLAYERS_WATERMASK]; #endif // USE_WATERMASK +#if SHOW_HEIGHT_RESOLUTION +uniform vec2 vertexResolution; +#endif #if USE_ATMOSPHERE // TODO atmosphere uniforms here #endif // USE_ATMOSPHERE -uniform vec2 vertexResolution; - in vec4 fs_position; in vec2 fs_uv; in vec3 ellipsoidNormalCameraSpace; @@ -112,14 +105,6 @@ vec4 getTileFragColor(){ ColorTextures, ColorTexturesParent1, ColorTexturesParent2); -#else - color = calculateDebugColor(fs_uv, fs_position, vertexResolution); - #if USE_HEIGHTMAP - color.r += tileResolution(fs_uv, HeightMaps[0]) > 0.9 ? 1 : 0; - #endif - #if USE_HEIGHTMAP_OVERLAY - color.g += tileResolution(fs_uv, HeightMapOverlays[0]) > 0.9 ? 1 : 0; - #endif // USE_HEIGHTMAP_OVERLAY #endif // USE_COLORTEXTURE @@ -178,5 +163,34 @@ vec4 getTileFragColor(){ #endif // USE_OVERLAY + + +#if SHOW_HEIGHT_INTENSITIES + color.r *= 0.1; + color.g *= 0.1; + color.b *= 0.1; + + float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); + float contourLine = fract(10*untransformedHeight) > 0.98 ? 1 : 0; + color.r += untransformedHeight; + color.b = contourLine; +#endif + + +#if SHOW_HEIGHT_RESOLUTION + + color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); + #if USE_HEIGHTMAP + color.r = min(color.r, 0.8); + color.r += tileResolution(fs_uv, HeightMaps[0]) > 0.9 ? 1 : 0; + #endif + #if USE_HEIGHTMAP_OVERLAY + color.g = min(color.g, 0.8); + color.g += tileResolution(fs_uv, HeightMapOverlays[0]) > 0.9 ? 1 : 0; + #endif // USE_HEIGHTMAP_OVERLAY +#endif + return color; -} \ No newline at end of file +} + +#endif ///TILE_FRAG_COLOR_HGLSL \ No newline at end of file diff --git a/modules/globebrowsing/shaders/tilevertexheight.hglsl b/modules/globebrowsing/shaders/tilevertexheight.hglsl index 78d40888ba..10be5b0aee 100644 --- a/modules/globebrowsing/shaders/tilevertexheight.hglsl +++ b/modules/globebrowsing/shaders/tilevertexheight.hglsl @@ -22,6 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#ifndef TILE_VERTEX_HEIGHT_HGLSL +#define TILE_VERTEX_HEIGHT_HGLSL + #include "PowerScaling/powerScaling_vs.hglsl" #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> @@ -45,28 +48,41 @@ uniform float skirtLength; uniform float distanceScaleFactor; uniform int chunkLevel; -layout(location = 1) in vec2 in_uv; -out vec2 fs_uv; -out vec4 fs_position; -out vec3 ellipsoidNormalCameraSpace; +float getUntransformedTileVertexHeight(vec2 uv, LevelWeights levelWeights){ + float height = 0; -out LevelWeights levelWeights; +#if USE_HEIGHTMAP + // Calculate desired level based on distance to the vertex on the ellipsoid + // Before any heightmapping is done + height = calculateUntransformedHeight( + uv, + levelWeights, // Variable to determine which texture to sample from + HeightMaps, HeightMapsParent1, HeightMapsParent2); // Three textures to sample from -float getTileVertexHeight(float distToVertexOnEllipsoid){ - float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; - float desiredLevel = log2(projectedScaleFactor); +#endif // USE_HEIGHTMAP - float levelInterpolationParameter = chunkLevel - desiredLevel; - levelWeights = getLevelWeights(levelInterpolationParameter); +#if USE_HEIGHTMAP_OVERLAY + height = calculateUntransformedHeightOverlay( + height, + uv, + levelWeights, // Variable to determine which texture to sample from + HeightMapOverlays, HeightMapOverlaysParent1, HeightMapOverlaysParent2); // Three textures to sample from +#endif // USE_HEIGHTMAP_OVERLAY + + return height; +} + + +float getTileVertexHeight(vec2 uv, LevelWeights levelWeights){ float height = 0; #if USE_HEIGHTMAP // Calculate desired level based on distance to the vertex on the ellipsoid // Before any heightmapping is done height = calculateHeight( - in_uv, + uv, levelWeights, // Variable to determine which texture to sample from HeightMaps, HeightMapsParent1, HeightMapsParent2); // Three textures to sample from @@ -75,7 +91,7 @@ float getTileVertexHeight(float distToVertexOnEllipsoid){ #if USE_HEIGHTMAP_OVERLAY height = calculateHeightOverlay( height, - in_uv, + uv, levelWeights, // Variable to determine which texture to sample from HeightMapOverlays, HeightMapOverlaysParent1, HeightMapOverlaysParent2); // Three textures to sample from @@ -93,4 +109,6 @@ bool tileVertexIsSkirtVertex(){ float getTileVertexSkirtLength(){ return tileVertexIsSkirtVertex() ? skirtLength : 0.0; -} \ No newline at end of file +} + +#endif // TILE_VERTEX_HEIGHT_HGLSL \ No newline at end of file diff --git a/modules/globebrowsing/tile/tiledataset.cpp b/modules/globebrowsing/tile/tiledataset.cpp index 76dc393334..72c2378187 100644 --- a/modules/globebrowsing/tile/tiledataset.cpp +++ b/modules/globebrowsing/tile/tiledataset.cpp @@ -675,13 +675,15 @@ namespace openspace { TilePreprocessData* preprocessData = new TilePreprocessData(); preprocessData->maxValues.resize(_dataLayout.numRasters); preprocessData->minValues.resize(_dataLayout.numRasters); - + preprocessData->hasMissingData.resize(_dataLayout.numRasters); + std::vector noDataValues; noDataValues.resize(_dataLayout.numRasters); for (size_t c = 0; c < _dataLayout.numRasters; c++) { preprocessData->maxValues[c] = -FLT_MAX; preprocessData->minValues[c] = FLT_MAX; + preprocessData->hasMissingData[c] = false; noDataValues[c] = _dataset->GetRasterBand(1)->GetNoDataValue(); } @@ -695,23 +697,14 @@ namespace openspace { for (size_t x = 0; x < region.numPixels.x; x++) { for (size_t c = 0; c < _dataLayout.numRasters; c++) { - //float lastMaxR = preprocessData->maxValues[0]; - //float lastMinR = preprocessData->minValues[0]; float val = TileDataType::interpretFloat(_dataLayout.gdalType, &(result->imageData[yi + i])); if (val != noDataValue) { preprocessData->maxValues[c] = std::max(val, preprocessData->maxValues[c]); preprocessData->minValues[c] = std::min(val, preprocessData->minValues[c]); } - - // ugly case for heightmap overlays and alpha - /* - if (c == 1 && _dataLayout.textureFormat.ghoulFormat == Texture::Format::RG) { - if (val < 0.5) { - preprocessData->maxValues[0] = lastMaxR; - preprocessData->minValues[0] = lastMinR; - } - }*/ - + else { + preprocessData->hasMissingData[c] = true; + } i += _dataLayout.bytesPerDatum; } } diff --git a/modules/globebrowsing/tile/tileioresult.h b/modules/globebrowsing/tile/tileioresult.h index 372d8f430d..7307370451 100644 --- a/modules/globebrowsing/tile/tileioresult.h +++ b/modules/globebrowsing/tile/tileioresult.h @@ -46,6 +46,7 @@ namespace openspace { struct TilePreprocessData { std::vector maxValues; std::vector minValues; + std::vector hasMissingData; void serialize(std::ostream& s); static TilePreprocessData deserialize(std::istream& s);