diff --git a/data/scene/debugglobe/debugglobe.mod b/data/scene/debugglobe/debugglobe.mod index 391ca4ffc9..dd494b168f 100644 --- a/data/scene/debugglobe/debugglobe.mod +++ b/data/scene/debugglobe/debugglobe.mod @@ -6,6 +6,7 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {6378137.0, 6378137.0, 6356752.314245}, -- Earth's radii + SegmentsPerPatch = 64, Textures = { ColorTextures = { { diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index fc5640c780..b7f7363691 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -38,6 +38,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.h ${CMAKE_CURRENT_SOURCE_DIR}/meshes/grid.h ${CMAKE_CURRENT_SOURCE_DIR}/meshes/basicgrid.h + ${CMAKE_CURRENT_SOURCE_DIR}/meshes/skirtedgrid.h ${CMAKE_CURRENT_SOURCE_DIR}/meshes/clipmapgrid.h ${CMAKE_CURRENT_SOURCE_DIR}/geodetics/geodetic2.h @@ -76,6 +77,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/meshes/grid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/meshes/basicgrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/meshes/skirtedgrid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/meshes/clipmapgrid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/geodetics/geodetic2.cpp diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp index 0941b84eb1..1c425b685f 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ b/modules/globebrowsing/globes/chunkedlodglobe.cpp @@ -24,7 +24,7 @@ #include -#include +#include // open space includes #include @@ -53,6 +53,7 @@ namespace openspace { ChunkedLodGlobe::ChunkedLodGlobe( const Ellipsoid& ellipsoid, + size_t segmentsPerPatch, std::shared_ptr tileProviderManager) : _ellipsoid(ellipsoid) , _leftRoot(new ChunkNode(Chunk(this, LEFT_HEMISPHERE_INDEX))) @@ -62,9 +63,9 @@ namespace openspace { , _savedCamera(nullptr) { - auto geometry = std::shared_ptr(new BasicGrid( - 64, - 64, + auto geometry = std::shared_ptr(new SkirtedGrid( + segmentsPerPatch, + segmentsPerPatch, TriangleSoup::Positions::No, TriangleSoup::TextureCoordinates::Yes, TriangleSoup::Normals::No)); diff --git a/modules/globebrowsing/globes/chunkedlodglobe.h b/modules/globebrowsing/globes/chunkedlodglobe.h index ab1dc68295..e05628b64e 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.h +++ b/modules/globebrowsing/globes/chunkedlodglobe.h @@ -56,6 +56,7 @@ namespace openspace { public: ChunkedLodGlobe( const Ellipsoid& ellipsoid, + size_t segmentsPerPatch, std::shared_ptr tileProviderManager); virtual ~ChunkedLodGlobe(); diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index f5b0dfaa85..24122d6a3f 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -43,6 +43,7 @@ namespace { // Keys for the dictionary const std::string keyRadii = "Radii"; + const std::string keySegmentsPerPatch = "SegmentsPerPatch"; const std::string keyTextures = "Textures"; const std::string keyColorTextures = "ColorTextures"; const std::string keyHeightMaps = "HeightMaps"; @@ -83,7 +84,13 @@ namespace openspace { // Read the radii in to its own dictionary Vec3 radii; + double patchSegmentsd; + dictionary.getValue(keyRadii, radii); + // Ghoul can't read ints from lua dictionaries + dictionary.getValue(keySegmentsPerPatch, patchSegmentsd); + int patchSegments = patchSegmentsd; + _ellipsoid = Ellipsoid(radii); @@ -150,11 +157,12 @@ namespace openspace { std::shared_ptr heightMapProvider = std::shared_ptr( new TileProvider(tileReader, cacheSize, frameUntilFlushRequestQueue)); + _tileProviderManager->addHeightMap(name, heightMapProvider); } _chunkedLodGlobe = std::shared_ptr( - new ChunkedLodGlobe(_ellipsoid, _tileProviderManager)); + new ChunkedLodGlobe(_ellipsoid, patchSegments, _tileProviderManager)); _distanceSwitch.addSwitchValue(_chunkedLodGlobe, 1e12); } diff --git a/modules/globebrowsing/other/asynctilereader.cpp b/modules/globebrowsing/other/asynctilereader.cpp index 7637292ecc..dede908746 100644 --- a/modules/globebrowsing/other/asynctilereader.cpp +++ b/modules/globebrowsing/other/asynctilereader.cpp @@ -40,6 +40,7 @@ namespace { namespace openspace { + AsyncTileDataProvider::AsyncTileDataProvider( std::shared_ptr tileDataset, std::shared_ptr pool) diff --git a/modules/globebrowsing/other/tiledataset.cpp b/modules/globebrowsing/other/tiledataset.cpp index 03cb0914cf..62ae1f5828 100644 --- a/modules/globebrowsing/other/tiledataset.cpp +++ b/modules/globebrowsing/other/tiledataset.cpp @@ -42,7 +42,7 @@ namespace openspace { // INIT THIS TO FALSE AFTER REMOVED FROM TILEPROVIDER bool TileDataset::GdalHasBeenInitialized = false; - TileDataset::TileDataset(const std::string& fileName, int minimumPixelSize) + TileDataset::TileDataset(const std::string& fileName, int minimumPixelSize, GLuint dataType) : _minimumPixelSize(minimumPixelSize) { @@ -53,6 +53,7 @@ namespace openspace { _dataset = (GDALDataset *)GDALOpen(absPath(fileName).c_str(), GA_ReadOnly); ghoul_assert(_dataset != nullptr, "Failed to load dataset: " << fileName); + _dataLayout = DataLayout(_dataset, dataType); _depthTransform = calculateTileDepthTransform(); _tileLevelDifference = calculateTileLevelDifference(_dataset, minimumPixelSize); @@ -72,10 +73,10 @@ namespace openspace { TileDepthTransform TileDataset::calculateTileDepthTransform() { GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - GDALDataType gdalType = firstBand->GetRasterDataType(); - - double maximumValue = (gdalType == GDT_Float32 || gdalType == GDT_Float64) ? - 1.0 : firstBand->GetMaximum(); + // Floating point types does not have a fix maximum or minimum value and + // can not be normalized when sampling a texture. Hence no rescaling is needed. + double maximumValue = (_dataLayout.gdalType == GDT_Float32 || _dataLayout.gdalType == GDT_Float64) ? + 1.0 : getMaximumValue(_dataLayout.gdalType); TileDepthTransform transform; transform.depthOffset = firstBand->GetOffset(); @@ -96,8 +97,9 @@ namespace openspace { std::shared_ptr TileDataset::readTileData(ChunkIndex chunkIndex) { GdalDataRegion region(_dataset, chunkIndex, _tileLevelDifference); - DataLayout dataLayout(_dataset, region); - char* imageData = new char[dataLayout.totalNumBytes]; + size_t bytesPerLine = _dataLayout.bytesPerPixel * region.numPixels.x; + size_t totalNumBytes = bytesPerLine * region.numPixels.y; + char* imageData = new char[totalNumBytes]; CPLErr worstError = CPLErr::CE_None; @@ -105,7 +107,7 @@ namespace openspace { for (size_t i = 0; i < region.numRasters; i++) { GDALRasterBand* rasterBand = _dataset->GetRasterBand(i + 1)->GetOverview(region.overview); - char* dataDestination = imageData + (i * dataLayout.bytesPerDatum); + char* dataDestination = imageData + (i * _dataLayout.bytesPerDatum); CPLErr err = rasterBand->RasterIO( GF_Read, @@ -116,16 +118,16 @@ namespace openspace { dataDestination, // Where to put data region.numPixels.x, // width to write x in destination region.numPixels.y, // width to write y in destination - dataLayout.gdalType, // Type - dataLayout.bytesPerPixel, // Pixel spacing - dataLayout.bytesPerLine); // Line spacing + _dataLayout.gdalType, // Type + _dataLayout.bytesPerPixel, // Pixel spacing + bytesPerLine); // Line spacing // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 worstError = std::max(worstError, err); } std::shared_ptr tileData = nullptr; - tileData = createRawTileData(region, dataLayout, imageData); + tileData = createRawTileData(region, _dataLayout, imageData); std::shared_ptr result(new TileIOResult); result->error = worstError; @@ -138,15 +140,17 @@ namespace openspace { std::shared_ptr TileDataset::createRawTileData(const GdalDataRegion& region, const DataLayout& dataLayout, const char* imageData) { - + size_t bytesPerLine = dataLayout.bytesPerPixel * region.numPixels.x; + size_t totalNumBytes = bytesPerLine * region.numPixels.y; + //if(cplError == CPLErr::CE_Fatal) // GDAL reads image data top to bottom. We want the opposite. - char* imageDataYflipped = new char[dataLayout.totalNumBytes]; + char* imageDataYflipped = new char[totalNumBytes]; for (size_t y = 0; y < region.numPixels.y; y++) { - for (size_t x = 0; x < dataLayout.bytesPerLine; x++) { - imageDataYflipped[x + y * dataLayout.bytesPerLine] = - imageData[x + (region.numPixels.y - 1 - y) * dataLayout.bytesPerLine]; + for (size_t x = 0; x < bytesPerLine; x++) { + imageDataYflipped[x + y * bytesPerLine] = + imageData[x + (region.numPixels.y - 1 - y) * bytesPerLine]; } } @@ -178,11 +182,25 @@ namespace openspace { case GDT_Float32: return sizeof(GLfloat); case GDT_Float64: return sizeof(GLdouble); default: - //LERROR("Unknown data type"); + LERROR("Unknown data type"); return -1; } } + size_t TileDataset::getMaximumValue(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: return 2 << 7; + case GDT_UInt16: return 2 << 15; + case GDT_Int16: return 2 << 14; + case GDT_UInt32: return 2 << 31; + case GDT_Int32: return 2 << 30; + default: + LERROR("Unknown data type"); + return -1; + } + } + + glm::uvec2 TileDataset::geodeticToPixel(GDALDataset* dataSet, const Geodetic2& geo) { double padfTransform[6]; @@ -238,7 +256,7 @@ namespace openspace { case GDT_Int32: format.glFormat = GL_R32I; break; case GDT_Float32: format.glFormat = GL_R32F; break; //case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float? - default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType); + default: LERROR("GDAL data type unknown to OpenGL: " << gdalType); } break; case 2: @@ -251,7 +269,7 @@ namespace openspace { case GDT_Int32: format.glFormat = GL_RG32I; break; case GDT_Float32: format.glFormat = GL_RG32F; break; case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float? - default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType); + default: LERROR("GDAL data type unknown to OpenGL: " << gdalType); } break; case 3: @@ -264,7 +282,7 @@ namespace openspace { case GDT_Int32: format.glFormat = GL_RGB32I; break; case GDT_Float32: format.glFormat = GL_RGB32F; break; // case GDT_Float64: format.glFormat = GL_RED; break;// No representation of 64 bit float? - default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType); + default: LERROR("GDAL data type unknown to OpenGL: " << gdalType); } break; case 4: @@ -277,11 +295,11 @@ namespace openspace { case GDT_Int32: format.glFormat = GL_RGBA32I; break; case GDT_Float32: format.glFormat = GL_RGBA32F; break; case GDT_Float64: format.glFormat = GL_RED; break; // No representation of 64 bit float? - default: ;//LERROR("GDAL data type unknown to OpenGL: " << gdalType); + default: LERROR("GDAL data type unknown to OpenGL: " << gdalType); } break; default: - //LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); break; } return format; @@ -302,11 +320,26 @@ namespace openspace { case GDT_Float32: return GL_FLOAT; case GDT_Float64: return GL_DOUBLE; default: - //LERROR("GDAL data type unknown to OpenGL: " << gdalType); + LERROR("GDAL data type unknown to OpenGL: " << gdalType); return GL_UNSIGNED_BYTE; } } + GDALDataType TileDataset::getGdalDataType(GLuint glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: return GDT_Byte; + case GL_UNSIGNED_SHORT: return GDT_UInt16; + case GL_SHORT: return GDT_Int16; + case GL_UNSIGNED_INT: return GDT_UInt32; + case GL_INT: return GDT_Int32; + case GL_FLOAT: return GDT_Float32; + case GL_DOUBLE: return GDT_Float64; + default: + LERROR("OpenGL data type unknown to GDAL: " << glType); + return GDT_Unknown; + } + } + TileDataset::GdalDataRegion::GdalDataRegion(GDALDataset * dataSet, const ChunkIndex& chunkIndex, int tileLevelDifference) @@ -351,14 +384,14 @@ namespace openspace { numPixels = pixelEnd - pixelStart; } + TileDataset::DataLayout::DataLayout() { + } - TileDataset::DataLayout::DataLayout(GDALDataset* dataSet, const GdalDataRegion& region) { + TileDataset::DataLayout::DataLayout(GDALDataset* dataSet, GLuint glType) { // Assume all raster bands have the same data type - gdalType = dataSet->GetRasterBand(1)->GetRasterDataType(); + gdalType = glType != 0 ? getGdalDataType(glType) : dataSet->GetRasterBand(1)->GetRasterDataType(); bytesPerDatum = numberOfBytes(gdalType); - bytesPerPixel = bytesPerDatum * region.numRasters; - bytesPerLine = bytesPerPixel * region.numPixels.x; - totalNumBytes = bytesPerLine * region.numPixels.y; + bytesPerPixel = bytesPerDatum * dataSet->GetRasterCount(); } diff --git a/modules/globebrowsing/other/tiledataset.h b/modules/globebrowsing/other/tiledataset.h index a5fbd94c49..ab1e842666 100644 --- a/modules/globebrowsing/other/tiledataset.h +++ b/modules/globebrowsing/other/tiledataset.h @@ -88,8 +88,10 @@ namespace openspace { class TileDataset { public: - - TileDataset(const std::string& fileName, int minimumPixelSize); + + // Default dataType = 0 means GDAL will use the same data type as the data + // is originally in + TileDataset(const std::string& fileName, int minimumPixelSize, GLuint dataType = 0); ~TileDataset(); @@ -126,13 +128,12 @@ namespace openspace { }; struct DataLayout { - DataLayout(GDALDataset* dataSet, const GdalDataRegion& region); + DataLayout(); + DataLayout(GDALDataset* dataSet, GLuint glType); GDALDataType gdalType; size_t bytesPerDatum; size_t bytesPerPixel; - size_t bytesPerLine; - size_t totalNumBytes; }; @@ -153,10 +154,14 @@ namespace openspace { static GLuint getOpenGLDataType(GDALDataType gdalType); + static GDALDataType getGdalDataType(GLuint glType); + static RawTileData::TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); static size_t numberOfBytes(GDALDataType gdalType); + static size_t getMaximumValue(GDALDataType gdalType); + static std::shared_ptr createRawTileData(const GdalDataRegion& region, const DataLayout& dataLayout, const char* imageData); @@ -173,6 +178,7 @@ namespace openspace { TileDepthTransform _depthTransform; GDALDataset* _dataset; + DataLayout _dataLayout; }; diff --git a/modules/globebrowsing/rendering/patchrenderer.cpp b/modules/globebrowsing/rendering/patchrenderer.cpp index e73116991f..f50d03991a 100644 --- a/modules/globebrowsing/rendering/patchrenderer.cpp +++ b/modules/globebrowsing/rendering/patchrenderer.cpp @@ -247,6 +247,7 @@ namespace openspace { programObject->setUniform("minLatLon", vec2(swCorner.toLonLatVec2())); programObject->setUniform("lonLatScalingFactor", vec2(patchSize.toLonLatVec2())); programObject->setUniform("radiiSquared", vec3(ellipsoid.radiiSquared())); + programObject->setUniform("xSegments", _grid->xSegments()); // OpenGL rendering settings glEnable(GL_DEPTH_TEST); @@ -481,6 +482,8 @@ namespace openspace { "projectionTransform", data.camera.projectionMatrix()); + programObject->setUniform("xSegments", _grid->xSegments()); + // OpenGL rendering settings glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl index 990e36e388..da7f692152 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl @@ -37,6 +37,9 @@ uniform vec3 radiiSquared; uniform vec2 minLatLon; uniform vec2 lonLatScalingFactor; +uniform int xSegments; +uniform int ySegments; + uniform TextureTile heightTiles[NUMLAYERS_HEIGHTMAP]; layout(location = 1) in vec2 in_uv; @@ -70,6 +73,16 @@ void main() height = (sampledValue * heightTiles[#{i}].depthTransform.depthScale + heightTiles[#{i}].depthTransform.depthOffset); + + // Skirts + int vertexIDx = gl_VertexID % (xSegments + 3); + int vertexIDy = gl_VertexID / (xSegments + 3); + if (vertexIDx == 0 || + vertexIDy == 0 || + vertexIDx == (xSegments + 2) || + vertexIDy == (xSegments + 2) ) { + height = 0; + } } #endfor diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl index 1eb32ce24b..51128d0a7e 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl @@ -42,6 +42,9 @@ uniform vec3 patchNormalCameraSpace; uniform TextureTile heightTiles[NUMLAYERS_HEIGHTMAP]; +uniform int xSegments; +uniform int ySegments; + layout(location = 1) in vec2 in_uv; out vec2 fs_uv; @@ -74,6 +77,16 @@ void main() height = (sampledValue * heightTiles[#{i}].depthTransform.depthScale + heightTiles[#{i}].depthTransform.depthOffset); + + // Skirts + int vertexIDx = gl_VertexID % (xSegments + 3); + int vertexIDy = gl_VertexID / (xSegments + 3); + if (vertexIDx == 0 || + vertexIDy == 0 || + vertexIDx == (xSegments + 2) || + vertexIDy == (xSegments + 2) ) { + height = 0; + } } #endfor diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index e9ac592a5e..0c4b227f00 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -940,11 +940,11 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates() { 0); glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles); - glm::dquat newRotationCamspace = - _globalCameraRotation * rotationDiffCamSpace; + glm::dquat rotationDiffWorldSpace = _globalCameraRotation * - rotationDiffCamSpace * glm::inverse(_globalCameraRotation); + rotationDiffCamSpace * + glm::inverse(_globalCameraRotation); glm::dvec3 rotationDiffVec3 = (distFromCenterToCamera * directionFromSurfaceToCamera) @@ -954,12 +954,16 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates() { newPosition = camPos + rotationDiffVec3; - glm::dvec3 lookUpWhenFacingCenter = + glm::dvec3 newCenterToSurface = _globe->geodeticSurfaceProjection(newPosition); + glm::dvec3 newSurfaceToCamera = newPosition - (centerPos + newCenterToSurface); + glm::dvec3 newDirectionFromSurfaceToCamera = glm::normalize(newSurfaceToCamera); + + glm::dvec3 lookUpWhenFacingSurface = _globalCameraRotation * glm::dvec3(_camera->lookUpVectorCameraSpace()); glm::dmat4 lookAtMat = glm::lookAt( glm::dvec3(0, 0, 0), - -directionFromSurfaceToCamera, - lookUpWhenFacingCenter); + -newDirectionFromSurfaceToCamera, + lookUpWhenFacingSurface); _globalCameraRotation = glm::normalize(glm::quat_cast(glm::inverse(lookAtMat))); }