Merge remote-tracking branch 'origin/master' into feature/postprocessing-effects

This commit is contained in:
benpm
2025-07-29 15:06:55 -06:00
71 changed files with 854 additions and 541 deletions
-1
View File
@@ -37,7 +37,6 @@ set(OPENSPACE_RELEASE_BUILD OFF)
set(OPENSPACE_VERSION_MAJOR)
set(OPENSPACE_VERSION_MINOR)
set(OPENSPACE_VERSION_PATCH)
set(OPENSPACE_VERSION_STRING)
include(${PROJECT_SOURCE_DIR}/support/cmake/module_common.cmake)
include(${PROJECT_SOURCE_DIR}/ext/ghoul/support/cmake/message_macros.cmake)
+2 -3
View File
@@ -2,7 +2,7 @@
# #
# OpenSpace #
# #
# Copyright (c) 2014-2022 #
# Copyright (c) 2014-2025 #
# #
# 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 #
@@ -22,7 +22,6 @@
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
##########################################################################################
include(${PROJECT_SOURCE_DIR}/ext/ghoul/support/cmake/copy_shared_libraries.cmake)
include(${PROJECT_SOURCE_DIR}/support/cmake/application_definition.cmake)
include(${PROJECT_SOURCE_DIR}/support/cmake/global_variables.cmake)
@@ -50,7 +49,7 @@ target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ex
target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/minvr/external/GLFW/src/include)
target_link_libraries(OpenSpace-MinVR PUBLIC openspace-core MinVR)
target_link_libraries(OpenSpace-MinVR PUBLIC openspace-core openspace-module-collection MinVR)
# Web Browser and Web gui
# Why not put these in the module's path? Because they do not have access to the
+79 -59
View File
@@ -26,6 +26,7 @@
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/settings.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/util/keys.h>
#include <openspace/util/mouse.h>
@@ -36,8 +37,8 @@
#include <ghoul/logging/consolelog.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/logging/visualstudiooutputlog.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <api/MinVR.h>
#include <GLFW/glfw3.h>
#include <numeric>
// @TODO: Add Spout support
@@ -115,7 +116,7 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
const VRAnalogEvent& event = static_cast<const VRAnalogEvent&>(eventData);
}
else if (isButtonEvent) {
if (!global::windowDelegate.isMaster()) {
if (!global::windowDelegate->isMaster()) {
return;
}
const VRButtonEvent& event = static_cast<const VRButtonEvent&>(eventData);
@@ -130,7 +131,7 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
std::string keyName = buttonName.substr(beg, sep - beg);
std::string actionName = buttonName.substr(sep + 1);
Key key = KeyMapping.find(keyName)->second;
Key key = stringToKey(keyName).key;
KeyAction action;
if (actionName == "Up") {
@@ -157,12 +158,12 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
}
using KM = KeyModifier;
KM mod = KM::NoModifier;
mod |= keyboardState.modifierShift ? KM::Shift : KM::NoModifier;
mod |= keyboardState.modifierCtrl ? KM::Control : KM::NoModifier;
mod |= keyboardState.modifierAlt ? KM::Alt : KM::NoModifier;
KM mod = KM::None;
mod |= keyboardState.modifierShift ? KM::Shift : KM::None;
mod |= keyboardState.modifierCtrl ? KM::Control : KM::None;
mod |= keyboardState.modifierAlt ? KM::Alt : KM::None;
openspace::global::openSpaceEngine.keyboardCallback(key, mod, action);
global::openSpaceEngine->keyboardCallback(key, mod, action, IsGuiWindow::Yes);
}
if (buttonName.size() >= 8 && buttonName.substr(0, 8) == "MouseBtn") {
@@ -203,24 +204,29 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
}
using KM = KeyModifier;
KM mod = KM::NoModifier;
mod |= keyboardState.modifierShift ? KM::Shift : KM::NoModifier;
mod |= keyboardState.modifierCtrl ? KM::Control : KM::NoModifier;
mod |= keyboardState.modifierAlt ? KM::Alt : KM::NoModifier;
KM mod = KM::None;
mod |= keyboardState.modifierShift ? KM::Shift : KM::None;
mod |= keyboardState.modifierCtrl ? KM::Control : KM::None;
mod |= keyboardState.modifierAlt ? KM::Alt : KM::None;
global::openSpaceEngine.mouseButtonCallback(button, action, mod);
global::openSpaceEngine->mouseButtonCallback(
button,
action,
mod,
IsGuiWindow::Yes
);
}
}
else if (type == "CursorMove") {
if (!global::windowDelegate.isMaster()) {
if (!global::windowDelegate->isMaster()) {
return;
}
const VRCursorEvent& event = static_cast<const VRCursorEvent&>(eventData);
const float* pos = event.getPos();
windowingGlobals.mousePosition = glm::vec2(pos[0], pos[1]);
openspace::global::openSpaceEngine.mousePositionCallback(pos[0], pos[1]);
global::openSpaceEngine->mousePositionCallback(pos[0], pos[1], IsGuiWindow::Yes);
// @TODO(abock): Support mouse wheel
//openspace::global::openSpaceEngine.mouseScrollWheelCallback(posX, posY);
@@ -229,19 +235,19 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
const VRTrackerEvent& event = static_cast<const VRTrackerEvent&>(eventData);
}
else if (type == "OpenSpaceMessage") {
if (global::windowDelegate.isMaster()) {
if (global::windowDelegate->isMaster()) {
// We don't want the message if we are the master as we already have the state
return;
}
const int frameNumber = eventData.getValue("FrameNumber");
const int nBytes = eventData.getValue("NBytes");
std::vector<int> intData = eventData.getValue("SynchronizationData");
char* data = reinterpret_cast<char*>(intData.data());
std::byte* data = reinterpret_cast<std::byte*>(intData.data());
std::vector<char> synchronizationBuffer(nBytes);
std::vector<std::byte> synchronizationBuffer(nBytes);
std::copy(data, data + nBytes, synchronizationBuffer.begin());
global::openSpaceEngine.decode(std::move(synchronizationBuffer));
global::openSpaceEngine->decode(std::move(synchronizationBuffer));
}
else {
LERRORC("onVREvent()", std::format("Received an event of unknown type {}", type));
@@ -263,7 +269,7 @@ void Handler::onVRRenderContext(const VRDataIndex& stateData) {
windowingGlobals.framebufferSize.x = stateData.getValue("FramebufferWidth");
windowingGlobals.framebufferSize.y = stateData.getValue("FramebufferHeight");
global::openSpaceEngine.initializeGL();
global::openSpaceEngine->initializeGL();
HasInitializedGL = true;
}
@@ -279,14 +285,14 @@ void Handler::onVRRenderScene(const VRDataIndex& stateData) {
glm::mat4 projectionMatrix = glm::make_mat4(state.getProjectionMatrix());
glm::mat4 viewMatrix = glm::make_mat4(state.getViewMatrix());
try {
openspace::global::openSpaceEngine.render(
openspace::global::openSpaceEngine->render(
// @TODO(abock) we should probably use the user position here?
glm::mat4(1.f),
viewMatrix,
projectionMatrix
);
openspace::global::openSpaceEngine.drawOverlays();
openspace::global::openSpaceEngine.postDraw();
openspace::global::openSpaceEngine->drawOverlays();
openspace::global::openSpaceEngine->postDraw();
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
@@ -301,29 +307,22 @@ void Handler::appendNewInputEventsSinceLastCall(VRDataQueue* queue) {
void setupMinVrDelegateFunctions(VRMain& main) {
// Sets up the OpenSpace WindowDelegate callback functions
WindowDelegate& delegate = global::windowDelegate;
WindowDelegate* delegate = global::windowDelegate;
delegate.nWindows = []() { return windowingGlobals.nWindows; };
delegate.currentWindowSize = []() { return windowingGlobals.windowSize; };
delegate.currentWindowResolution = delegate.currentWindowSize;
delegate.currentDrawBufferResolution = delegate.currentWindowResolution;
delegate.currentViewportSize = delegate.currentWindowResolution;
delegate->nWindows = []() { return windowingGlobals.nWindows; };
delegate->currentWindowSize = []() { return windowingGlobals.windowSize; };
delegate->currentDrawBufferResolution = delegate->currentWindowSize;
delegate->currentViewportSize = delegate->currentWindowSize;
delegate.averageDeltaTime = []() -> double {
delegate->averageDeltaTime = []() -> double {
return windowingGlobals.averageDeltatime;
};
delegate.deltaTime = []() -> double { return windowingGlobals.deltaTime; };
delegate->deltaTime = []() -> double { return windowingGlobals.deltaTime; };
delegate.mousePosition = []() {
return windowingGlobals.mousePosition;
};
delegate.mouseButtons = [](int) {
return windowingGlobals.mouseButtons;
};
delegate.isMaster = []() { return IsMasterNode; };
delegate->isMaster = []() { return IsMasterNode; };
delegate.openGLProcedureAddress = [](const char* func) {
delegate->openGLProcedureAddress = [](const char* func) {
VRWindowToolkit* wtk = engine.getWindowToolkit("VRGLFWWindowToolkit");
VRglproc procAddress = wtk->getProcAddress(func);
return procAddress;
@@ -348,12 +347,13 @@ int main(int argc, char** argv) {
}
ghoul::initialize();
global::create();
// Register the path of the executable,
// to make it possible to find other files in the same directory.
FileSys.registerPathToken(
"${BIN}",
ghoul::filesystem::File(absPath(argv[0])).directoryName(),
absPath(argv[0]).parent_path(),
ghoul::filesystem::FileSystem::Override::Yes
);
@@ -362,22 +362,42 @@ int main(int argc, char** argv) {
try {
// Find configuration
//std::string configurationFilePath = commandlineArguments.configurationName;
//if (commandlineArguments.configurationName.empty()) {
LDEBUG("Finding configuration");
std::string configurationFilePath = configuration::findConfiguration();
//}
std::filesystem::path configurationFilePath = findConfiguration();
configurationFilePath = absPath(configurationFilePath);
if (!FileSys.fileExists(configurationFilePath)) {
LFATALC("main", "Could not find configuration: " + configurationFilePath);
if (!std::filesystem::exists(configurationFilePath)) {
LFATALC(
"main",
std::format("Could not find configuration: {}", configurationFilePath)
);
exit(EXIT_FAILURE);
}
LINFO(std::format("Configuration Path: '{}'", configurationFilePath));
// Register the base path as the directory where the configuration file lives
std::filesystem::path base = configurationFilePath.parent_path();
FileSys.registerPathToken("${BASE}", std::move(base));
#ifdef WIN32
glm::ivec2 size = glm::ivec2(1920, 1080);
DEVMODEW dm = { 0 };
dm.dmSize = sizeof(DEVMODEW);
BOOL success = EnumDisplaySettingsW(nullptr, ENUM_CURRENT_SETTINGS, &dm);
if (success) {
size.x = dm.dmPelsWidth;
size.y = dm.dmPelsHeight;
}
#else // ^^^^ WIN32 // !WIN32 vvvv
const glm::ivec2 size = glm::ivec2(1920, 1080);
#endif // WIN32
// Loading configuration from disk
LDEBUG("Loading configuration from disk");
global::configuration = configuration::loadConfigurationFromFile(
configurationFilePath
*global::configuration = loadConfigurationFromFile(
configurationFilePath,
findSettings(),
size
);
// If the user requested a commandline-based configuation script that should
@@ -393,9 +413,9 @@ int main(int argc, char** argv) {
//}
// Determining MinVR configuration file
LDEBUG("MinVR Configuration file: " + global::configuration.windowConfiguration);
LDEBUG("MinVR Configuration file: " + global::configuration->windowConfiguration);
windowConfiguration = global::configuration.windowConfiguration;
windowConfiguration = global::configuration->windowConfiguration;
}
catch (const documentation::SpecificationError& e) {
LFATALC("main", "Loading of configuration file failed");
@@ -416,12 +436,12 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
global::openSpaceEngine.registerPathTokens();
global::openSpaceEngine.initialize();
global::openSpaceEngine->registerPathTokens();
global::openSpaceEngine->initialize();
engine.addEventHandler(&handler);
engine.addRenderHandler(&handler);
engine.loadConfig(global::configuration.windowConfiguration);
engine.loadConfig(global::configuration->windowConfiguration);
// Yes, this still contains the OpenSpace-specific commandline arguments, but no one
// will ever know if we use the remaining arguments or not; both commandline parsers
// just ignore the arguments they don't understand
@@ -432,7 +452,7 @@ int main(int argc, char** argv) {
const std::string& name = engine.getName();
IsMasterNode = (name == MasterNode);
if (global::windowDelegate.isMaster()) {
if (global::windowDelegate->isMaster()) {
engine.addInputDevice(&handler);
}
@@ -460,10 +480,10 @@ int main(int argc, char** argv) {
global::openSpaceEngine.preSynchronization();
global::openSpaceEngine->preSynchronization();
if (global::windowDelegate.isMaster()) {
std::vector<char> syncBuffer = global::openSpaceEngine.encode();
if (global::windowDelegate->isMaster()) {
std::vector<std::byte> syncBuffer = global::openSpaceEngine->encode();
VRDataIndex e("OpenSpace_Sync");
e.addData("EventType", "OpenSpaceMessage");
@@ -489,7 +509,7 @@ int main(int argc, char** argv) {
engine.updateAllModels();
// @TODO(abock): Not sure if this should be before updateAllModels or here
global::openSpaceEngine.postSynchronizationPreDraw();
global::openSpaceEngine->postSynchronizationPreDraw();
++FrameNumber;
}
@@ -497,12 +517,12 @@ int main(int argc, char** argv) {
engine.renderOnAllDisplays();
} while (!engine.getShutdown());
global::openSpaceEngine.deinitializeGL();
global::openSpaceEngine->deinitializeGL();
// This assumes that `shutdown` destroys the OpenGL state and thus have to happen
// after the deinitializeGL function
engine.shutdown();
global::openSpaceEngine.deinitialize();
global::openSpaceEngine->deinitialize();
exit(EXIT_SUCCESS);
}
@@ -382,9 +382,7 @@ LauncherWindow::LauncherWindow(bool profileEnabled, const Configuration& globalC
{
QLabel* versionLabel = new QLabel(centralWidget);
versionLabel->setVisible(true);
versionLabel->setText(
QString::fromStdString(std::string(OPENSPACE_VERSION_STRING_FULL))
);
versionLabel->setText(QString::fromStdString(std::string(OPENSPACE_VERSION)));
versionLabel->setObjectName("version-info");
versionLabel->setGeometry(geometry::VersionString);
}
@@ -134,7 +134,7 @@ NotificationWindow::NotificationWindow(QWidget* parent)
std::string URL = std::format(
"https://raw.githubusercontent.com/OpenSpace/Notifications/refs/heads/master/"
"{}.txt",
OPENSPACE_IS_RELEASE_BUILD ? OPENSPACE_VERSION_NUMBER : "master"
OPENSPACE_IS_RELEASE_BUILD ? OPENSPACE_VERSION : "master"
);
_request = std::make_unique<HttpMemoryDownload>(
@@ -0,0 +1,83 @@
local LockCurrent = {
Identifier = "os.temporalLayer.LockCurrent",
Name = "Lock Focus Node Temporal Layers",
Command = [[
local j2000 = openspace.time.currentTime()
local dateTime = openspace.time.convertTime(j2000)
local focusName = openspace.propertyValue("NavigationHandler.OrbitalNavigator.Anchor")
openspace.setPropertyValue("Scene." .. focusName .. ".*.FixedTime", dateTime)
openspace.setPropertyValue("Scene." .. focusName .. ".*.UseFixedTime", true)
]],
Documentation = [[Set fixed date for all temporal layers for the currently
focused node.]],
GuiPath = "/Solar System",
IsLocal = false
}
local UnlockCurrent = {
Identifier = "os.temporalLayer.UnlockCurrent",
Name = "Unlock Focus Node Temporal Layers",
Command = [[
local j2000 = openspace.time.currentTime()
local dateTime = openspace.time.convertTime(j2000)
local focusName = openspace.propertyValue("NavigationHandler.OrbitalNavigator.Anchor")
openspace.setPropertyValue("Scene." .. focusName .. ".*.UseFixedTime", false)
openspace.setPropertyValue("Scene." .. focusName .. ".*.FixedTime", "")
]],
Documentation = [[Removes fixed date for all temporal layers for the currently
focused node.]],
GuiPath = "/Solar System",
IsLocal = false
}
local LockAll = {
Identifier = "os.temporalLayer.LockAll",
Name = "Lock All Temporal Layers",
Command = [[
local j2000 = openspace.time.currentTime()
local dateTime = openspace.time.convertTime(j2000)
openspace.setPropertyValue("Scene.*.FixedTime", dateTime)
openspace.setPropertyValue("Scene.*.UseFixedTime", true)
]],
Documentation = "Set fixed date for all temporal layers in the scene.",
GuiPath = "/Solar System",
IsLocal = false
}
local UnlockAll = {
Identifier = "os.temporalLayer.UnlockAll",
Name = "Unlock All Temporal Layers",
Command = [[
openspace.setPropertyValue("Scene.*.UseFixedTime", false)
openspace.setPropertyValue("Scene.*.FixedTime", "")
]],
Documentation = "Removes fixed date for all temporal layers in the scene.",
GuiPath = "/Solar System",
IsLocal = false
}
asset.onInitialize(function()
openspace.action.registerAction(LockCurrent);
openspace.action.registerAction(UnlockCurrent);
openspace.action.registerAction(LockAll);
openspace.action.registerAction(UnlockAll);
end)
asset.onDeinitialize(function()
openspace.action.removeAction(UnlockAll);
openspace.action.removeAction(LockAll);
openspace.action.removeAction(UnlockCurrent);
openspace.action.removeAction(LockCurrent);
end)
asset.meta = {
Name = "Temporal Layers - Lock Date",
Version = "1.0",
Description = [[Provides actions for locking and unlocking temporal layers to the
current date.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
@@ -0,0 +1,51 @@
local earth = asset.require("scene/solarsystem/planets/earth/earth")
-- These two files are downloaded from the servers when the asset gets loaded. Specifying
-- these two URLs in this way will cause them to be downloaded into the same folder on the
-- harddisk. For this example this is important as the points-relative.geojson will ask
-- for the image.png in the same folder by specifying "./image.png"
local data = asset.resource({
Name = "GeoJSON Example Relative Texture Path",
Type = "UrlSynchronization",
Identifier = "geojson_example_points_relative_path",
Url = {
"http://liu-se.cdn.openspaceproject.com/files/examples/geojson/points-relative.geojson",
"http://liu-se.cdn.openspaceproject.com/files/examples/geojson/image.png"
}
})
local ExamplePoints = {
Identifier = "Points-Example-RelativeTexturePath",
File = data .. "points-relative.geojson",
HeightOffset = 20000.0,
DefaultProperties = {
PointSize = 10.0
},
Name = "Example Points (Relative Texture Path)"
}
asset.onInitialize(function()
openspace.globebrowsing.addGeoJson(earth.Earth.Identifier, ExamplePoints)
end)
asset.onDeinitialize(function()
openspace.globebrowsing.deleteGeoJson(earth.Earth.Identifier, ExamplePoints)
end)
asset.export(ExamplePoints)
asset.meta = {
Name = "GeoJson Example - Points (Relative Texture Path)",
Description = [[GeoJson example asset with points that are facing the camera
(default). This example is using a relative path to specify the location of the image
that is to be used.]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license"
}
@@ -15,8 +15,7 @@ local Layer = {
Name = "LAMO [Local]",
Enabled = asset.enabled,
ZIndex = 5,
FilePath = textures .. "ceres_lamo_4096x2048.png",
CacheSettings = { Enabled = false }
FilePath = textures .. "ceres_lamo_4096x2048.png"
}
@@ -51,8 +51,7 @@ local Charon = {
"moon_major_pluto"
},
GUI = {
Path = "/Solar System/Dwarf Planets/Pluto/Charon",
Focusable = false
Path = "/Solar System/Dwarf Planets/Pluto/Charon"
}
}
@@ -43,8 +43,7 @@ asset.onInitialize(function()
Description = "",
FilePath = imagename,
Enabled = false,
ZIndex = 100,
CacheSettings = { Enabled = false }
ZIndex = 100
}
)
end
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 5,
FilePath = texturesPath .. "earth_bluemarble.jpg",
Description = "Earth image from Blue Marble Next Generation",
CacheSettings = { Enabled = false }
Description = "Earth image from Blue Marble Next Generation"
}
@@ -21,8 +21,7 @@ local Layer = {
Settings = {
Multiplier = 40,
Offset = -600
},
CacheSettings = { Enabled = false }
}
}
@@ -17,7 +17,7 @@
<BlockSizeY>512</BlockSizeY>
<BandsCount>1</BandsCount>
<DataType>Float32</DataType>
<DataValues NoData="0" Min="-11000" Max="8500"/>
<DataValues NoData="-3.40282347e+38" Min="-11000" Max="8500"/>
<MaxConnections>5</MaxConnections>
<ZeroBlockHttpCodes>404,400</ZeroBlockHttpCodes>
</GDAL_WMS>
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 5,
FilePath = texturesPath .. "earth_night.png",
Description = "Earth's city lights are clearly visible from space",
CacheSettings = { Enabled = false }
Description = "Earth's city lights are clearly visible from space"
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 5,
FilePath = texturesPath .. "WAC_GLOBAL_E000N0000_032P.png",
Description = "Lower Resolution offline version of WAC layer",
CacheSettings = { Enabled = false }
Description = "Lower Resolution offline version of WAC layer"
}
@@ -31,8 +31,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 100,
FilePath = syncedDirectory .. "4096.jpg",
Description = Description,
CacheSettings = { Enabled = false }
Description = Description
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "ganymede.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "io.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 5,
FilePath = texturesPath .. "mars.png",
Description = "Default jpg texture for Mars",
CacheSettings = { Enabled = false }
Description = "Default jpg texture for Mars"
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 100,
FilePath = texturesPath .. "alsimap_02122015.png",
BlendMode = "Multiply",
CacheSettings = { Enabled = false }
BlendMode = "Multiply"
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 100,
FilePath = texturesPath .. "casimap_02122015.png",
BlendMode = "Multiply",
CacheSettings = { Enabled = false }
BlendMode = "Multiply"
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 100,
FilePath = texturesPath .. "fesimap_02122015.png",
BlendMode = "Multiply",
CacheSettings = { Enabled = false }
BlendMode = "Multiply"
}
@@ -17,8 +17,7 @@ local Layer = {
ZIndex = 5,
Description = [[The Map Projected Basemap RDR (BDR) data set consists of a global
monochrome map of reflectance at a resolution of 256 pixels per degree (~166 m/p).
This is an offline version with lower resoution than the Messenger BDR layer.]],
CacheSettings = { Enabled = false }
This is an offline version with lower resoution than the Messenger BDR layer.]]
}
@@ -20,8 +20,7 @@ local Layer = {
Gamma = 1.33,
Multiplier = 1.15
},
BlendMode = "Multiply",
CacheSettings = { Enabled = false }
BlendMode = "Multiply"
}
@@ -16,8 +16,7 @@ local Layer = {
Enabled = asset.enabled,
ZIndex = 100,
FilePath = texturesPath .. "ssimap_02122015.png",
BlendMode = "Multiply",
CacheSettings = { Enabled = false }
BlendMode = "Multiply"
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "neptune.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -20,8 +20,7 @@ local Layer = {
Triton. This map has a resolution of 1,970 feet (600 meters per pixel [m]). Color was
synthesized by combining high-resolution images taken through orange, violet, and
ultraviolet filters; these images were displayed as red, green, and blue images and
combined to create this color version (Smith et al., 1989).]],
CacheSettings = { Enabled = false }
combined to create this color version (Smith et al., 1989).]]
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "dione.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "enceladus.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local layer = {
Identifier = "Texture",
FilePath = texturesPath .. "iapetus.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "saturn.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "mimas.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "rhea.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -41,7 +41,7 @@ local Saturn = {
TextureUnlit = texturesPath .. "unlit_original_single.png",
TextureColor = texturesPath .. "color_original_single.png",
TextureTransparency = texturesPath .. "trans_original_single.png",
ColorFilter = 0.8,
ColorFilter = 0.9,
NightFactor = 1.0,
Size = 140445000,
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "tethys.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "uranus.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
@@ -22,8 +22,7 @@ local Layer = {
TileProvider = {
Identifier = "Clouds",
Name = "Clouds",
FilePath = texturesPath .. "venus_clouds.jpg",
CacheSettings = { Enabled = false }
FilePath = texturesPath .. "venus_clouds.jpg"
}
},
{
@@ -22,8 +22,7 @@ local Layer = {
TileProvider = {
Identifier = "Clouds",
Name = "Clouds",
FilePath = texturesPath .. "venus_clouds.jpg",
CacheSettings = { Enabled = false }
FilePath = texturesPath .. "venus_clouds.jpg"
}
},
{
@@ -14,8 +14,7 @@ local Clouds = {
Identifier = "Clouds",
FilePath = texturesPath .. "venus_clouds.jpg",
Enabled = asset.enabled,
ZIndex = 20,
CacheSettings = { Enabled = false }
ZIndex = 20
}
local Layer = {
@@ -26,8 +25,7 @@ local Layer = {
Settings = {
Opacity = 0.48,
Gamma = 0.48
},
CacheSettings = { Enabled = false }
}
}
@@ -14,8 +14,7 @@ local Layer = {
Identifier = "Texture",
FilePath = texturesPath .. "sun.jpg",
Enabled = asset.enabled,
ZIndex = 5,
CacheSettings = { Enabled = false }
ZIndex = 5
}
+1 -1
View File
@@ -4,7 +4,7 @@ local guiCustomization = asset.require("customization/gui")
-- Select which commit hashes to use for the UI frontend
local frontendHash = "8e0c43cc406cc56dea3c5e1f0b4c45b1216927a5"
local frontendHash = "baabd171ecbe61b2758970a2cdafb43fbcd1a23b"
-- The name of the file to download from the server
local frontendFile = "frontend.zip"
+8 -2
View File
@@ -4,7 +4,8 @@
"base_keybindings",
"events/toggle_sun",
"scene/solarsystem/planets/earth/earth",
"scene/solarsystem/planets/earth/satellites/satellites"
"scene/solarsystem/planets/earth/satellites/satellites",
"scene/solarsystem/planets/earth/noaa-sos/overlays/latlon_grid-white"
],
"camera": {
"altitude": 17000000.0,
@@ -70,6 +71,11 @@
"name": "{earth_satellites~space_stations}.Renderable.Enabled",
"type": "setPropertyValue",
"value": "false"
},
{
"name": "Scene.Earth.Renderable.Layers.Overlays.noaa-sos-overlays-latlon_grid-white.Enabled",
"type": "setPropertyValueSingle",
"value": "false"
}
],
"time": {
@@ -81,4 +87,4 @@
"major": 1,
"minor": 4
}
}
}
+1 -1
View File
@@ -103,7 +103,7 @@ constexpr KeyModifier operator|(KeyModifier lhs, KeyModifier rhs) {
return static_cast<KeyModifier>(
static_cast<std::underlying_type_t<KeyModifier>>(lhs) |
static_cast<std::underlying_type_t<KeyModifier>>(rhs)
);
);
}
constexpr KeyModifier operator|=(KeyModifier& lhs, KeyModifier rhs) {
@@ -201,8 +201,7 @@ function addExoplanetSystem(data)
Identifier = "StarTexture",
FilePath = openspace.absPath(starTexture),
BlendMode = "Color",
Enabled = true,
CacheSettings = { Enabled = false }
Enabled = true
}
}
else
@@ -211,8 +210,7 @@ function addExoplanetSystem(data)
Identifier = "NoDataStarTexture",
FilePath = openspace.absPath(starNoDataTexture),
BlendMode = "Color",
Enabled = true,
CacheSettings = { Enabled = false }
Enabled = true
}
}
end
@@ -506,8 +504,7 @@ function addExoplanetSystem(data)
Identifier = "PlanetTexture",
Name = "Planet Texture",
FilePath = openspace.absPath(defaultPlanetTexture),
Enabled = true,
CacheSettings = { Enabled = false }
Enabled = true
}
table.insert(planetColorLayers, PlanetTextureLayer)
ambientIntensity = 0.15
@@ -496,8 +496,8 @@ bool GlobeBrowsingModule::hasDefaultGeoPointTexture() const {
return _hasDefaultGeoPointTexture;
}
std::string_view GlobeBrowsingModule::defaultGeoPointTexture() const {
return _defaultGeoPointTexturePath;
std::filesystem::path GlobeBrowsingModule::defaultGeoPointTexture() const {
return _defaultGeoPointTexturePath.value();
}
scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
+1 -1
View File
@@ -90,7 +90,7 @@ public:
std::string mrfCacheLocation() const;
bool hasDefaultGeoPointTexture() const;
std::string_view defaultGeoPointTexture() const;
std::filesystem::path defaultGeoPointTexture() const;
protected:
void internalInitialize(const ghoul::Dictionary&) override;
@@ -34,11 +34,11 @@ in vec4 shadowCoords;
in vec3 vs_normal;
uniform sampler2DShadow shadowMapTexture;
uniform sampler1D ringTextureFwrd;
uniform sampler1D ringTextureBckwrd;
uniform sampler1D ringTextureUnlit;
uniform sampler1D ringTextureColor;
uniform sampler1D ringTextureTransparency;
uniform sampler1D textureForwards;
uniform sampler1D textureBackwards;
uniform sampler1D textureUnlit;
uniform sampler1D textureColor;
uniform sampler1D textureTransparency;
uniform vec2 textureOffset;
uniform float colorFilterValue;
uniform vec3 sunPosition;
@@ -70,19 +70,19 @@ Fragment getFragment() {
discard;
}
vec4 colorBckwrd = texture(ringTextureBckwrd, texCoord);
vec4 colorFwrd = texture(ringTextureFwrd, texCoord);
vec4 colorMult = texture(ringTextureColor, texCoord);
vec4 transparency = texture(ringTextureTransparency, texCoord);
vec4 colorBckwrd = texture(textureBackwards, texCoord);
vec4 colorFwrd = texture(textureForwards, texCoord);
vec4 colorMult = texture(textureColor, texCoord);
float transparency = 1.0 - texture(textureTransparency, texCoord).r;
float lerpFactor = dot(camPositionObj, sunPositionObj);
// Jon Colors:
//vec4 diffuse = mix(colorFwrd * vec4(1, 0.88, 0.82, 1.0), colorBckwrd * vec4(1, 0.88, 0.82, 1.0), lerpFactor);
vec4 diffuse = mix(colorFwrd * colorMult, colorBckwrd * colorMult, lerpFactor);
diffuse.a = colorFilterValue * transparency.a;
vec4 diffuse = mix(colorFwrd, colorBckwrd, lerpFactor) * colorMult;
diffuse.a = colorFilterValue * transparency;
float colorValue = length(diffuse.rgb) / 0.57735026919;
if (colorValue < 0.1) {
if (colorValue < 0.001) {
discard;
}
@@ -103,10 +103,10 @@ Fragment getFragment() {
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, NSSamples - #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, -NSSamples + #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, 0));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, NSSamples - #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(NSSamples - #{i}, NSSamples - #{i}));
#endfor
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0));
shadow = clamp(sum / (8.0 * NSSamples + 1.f), 0.35, 1.0);
shadow = clamp(sum / (8.0 * NSSamples + 1.f), 0.05, 1.0);
}
// The normal for the one plane depends on whether we are dealing
@@ -119,13 +119,13 @@ Fragment getFragment() {
// if we are facing away from the Sun
if (dot(sunPosition, normal) < 0.0) {
diffuse.xyz =
vec3(1.0, 0.97075, 0.952) * texture(ringTextureUnlit, texCoord).xyz * nightFactor;
vec3(1.0, 0.97075, 0.952) * texture(textureUnlit, texCoord).xyz * nightFactor;
}
Fragment frag;
frag.color = diffuse * shadow;
frag.color.a *= opacity;
frag.color.a = frag.color.a * opacity + (1.0 - shadow) * 0.5;
frag.depth = vs_screenSpaceDepth;
frag.gPosition = vec4(1e30, 1e30, 1e30, 1.0);
frag.gNormal = vec4(normal, 1.0);
@@ -37,25 +37,20 @@ out vec2 fs_uv;
out vec3 ellipsoidNormalCameraSpace;
out vec3 levelWeights;
out vec3 positionCameraSpace;
out vec3 posObjSpace;
out vec3 normalObjSpace;
#if USE_ACCURATE_NORMALS
out vec3 ellipsoidTangentThetaCameraSpace;
out vec3 ellipsoidTangentPhiCameraSpace;
#endif // USE_ACCURATE_NORMALS
uniform dmat4 modelTransform;
#if USE_ECLIPSE_SHADOWS
out vec3 positionWorldSpace;
uniform dmat4 modelTransform;
#endif // USE_ECLIPSE_SHADOWS
#if SHADOW_MAPPING_ENABLED
// ShadowMatrix is the matrix defined by:
// textureCoordsMatrix * projectionMatrix * combinedViewMatrix * modelMatrix
// where textureCoordsMatrix is just a scale and bias computation: [-1,1] to [0,1]
uniform dmat4 shadowMatrix;
out vec4 shadowCoords;
#endif // SHADOW_MAPPING_ENABLED
uniform mat4 modelViewProjectionTransform;
uniform mat4 modelViewTransform;
uniform vec3 radiiSquared;
@@ -134,12 +129,10 @@ void main() {
gl_Position = fs_position;
ellipsoidNormalCameraSpace = mat3(modelViewTransform) * pair.normal;
positionCameraSpace = vec3(modelViewTransform * vec4(pair.position, 1.0));
posObjSpace = pair.position;
normalObjSpace = pair.normal;
#if USE_ECLIPSE_SHADOWS
positionWorldSpace = vec3(modelTransform * dvec4(pair.position, 1.0));
#endif // USE_ECLIPSE_SHADOWS
#if SHADOW_MAPPING_ENABLED
shadowCoords = vec4(shadowMatrix * dvec4(pair.position, 1.0));
#endif // SHADOW_MAPPING_ENABLED
}
@@ -37,24 +37,21 @@ out vec4 fs_position;
out vec3 ellipsoidNormalCameraSpace;
out vec3 levelWeights;
out vec3 positionCameraSpace;
out vec3 posObjSpace;
out vec3 normalObjSpace;
#if USE_ACCURATE_NORMALS
out vec3 ellipsoidTangentThetaCameraSpace;
out vec3 ellipsoidTangentPhiCameraSpace;
#endif // USE_ACCURATE_NORMALS
#if USE_ECLIPSE_SHADOWS
out vec3 positionWorldSpace;
uniform dmat4 inverseViewTransform;
#endif // USE_ECLIPSE_SHADOWS
uniform dmat4 modelTransform;
#if SHADOW_MAPPING_ENABLED
// ShadowMatrix is the matrix defined by:
// textureCoordsMatrix * projectionMatrix * combinedViewMatrix * modelMatrix
// where textureCoordsMatrix is just a scale and bias computation: [-1,1] to [0,1]
uniform dmat4 shadowMatrix;
out vec4 shadowCoords;
#endif // SHADOW_MAPPING_ENABLED
#if USE_ECLIPSE_SHADOWS
// Position in world space
out vec3 positionWorldSpace;
#endif // USE_ECLIPSE_SHADOWS
uniform mat4 projectionTransform;
// Input points in camera space
@@ -118,12 +115,9 @@ void main() {
gl_Position = fs_position;
ellipsoidNormalCameraSpace = patchNormalCameraSpace;
positionCameraSpace = p;
posObjSpace = vec3(inverseViewTransform * dvec4(p, 1.0));
#if USE_ECLIPSE_SHADOWS
positionWorldSpace = vec3(inverseViewTransform * dvec4(p, 1.0));
positionWorldSpace = vec3(modelTransform * dvec4(p, 1.0));
#endif // USE_ECLIPSE_SHADOWS
#if SHADOW_MAPPING_ENABLED
shadowCoords = vec4(shadowMatrix * dvec4(p, 1.0));
#endif // SHADOW_MAPPING_ENABLED
}
+71 -28
View File
@@ -52,6 +52,9 @@ uniform vec2 vertexResolution;
#endif // SHOW_HEIGHT_RESOLUTION
uniform vec3 lightDirectionCameraSpace;
uniform vec3 lightDirectionObjSpace;
uniform mat4 modelViewTransform;
uniform float ringSize;
#if PERFORM_SHADING
uniform float orenNayarRoughness;
@@ -59,13 +62,16 @@ uniform float ambientIntensity;
#endif // PERFORM_SHADING
#if SHADOW_MAPPING_ENABLED
#if USE_RING_SHADOWS
// Fragment position in object space
in vec3 posObjSpace;
#define NSSamplesMinusOne #{nShadowSamples}
#define NSSamples (NSSamplesMinusOne + 1)
in vec4 shadowCoords;
uniform sampler2DShadow shadowMapTexture;
uniform float zFightingPercentage;
// Color of the rings
uniform sampler1D ringTextureColor;
// Transparency of the rings
uniform sampler1D ringTextureTransparency;
uniform vec2 textureOffset;
#endif // USE_RING_SHADOWS
#endif // SHADOW_MAPPING_ENABLED
#if USE_ECLIPSE_SHADOWS
@@ -137,11 +143,29 @@ vec4 calcShadow(const ShadowRenderingStruct shadowInfoArray[NSEclipseShadows],
}
#endif
float rayPlaneIntersection(vec3 rayOrigin, vec3 rayDirection, vec3 planePoint,
vec3 planeNormal)
{
float denom = dot(planeNormal, rayDirection);
// Check if ray is parallel to plane (or nearly parallel)
if (abs(denom) < 1e-6) {
return -1.0; // No intersection or ray lies in plane
}
vec3 p0l0 = planePoint - rayOrigin;
float t = dot(p0l0, planeNormal) / denom;
// Return negative if intersection is behind ray origin
return t >= 0.0 ? t : -1.0;
}
in vec4 fs_position;
in vec2 fs_uv;
in vec3 ellipsoidNormalCameraSpace;
in vec3 levelWeights;
in vec3 positionCameraSpace;
in vec3 normalObjSpace;
#if USE_ACCURATE_NORMALS
in vec3 ellipsoidTangentThetaCameraSpace;
@@ -149,7 +173,7 @@ in vec3 positionCameraSpace;
#endif // USE_ACCURATE_NORMALS
#if USE_ECLIPSE_SHADOWS
in vec3 positionWorldSpace;
in vec3 positionWorldSpace;
#endif // USE_ECLIPSE_SHADOWS
uniform float opacity;
@@ -201,6 +225,7 @@ Fragment getFragment() {
#endif // USE_NIGHTTEXTURE
#if PERFORM_SHADING
vec3 preShadedColor = frag.color.rgb;
frag.color = calculateShadedColor(
frag.color,
normal,
@@ -268,29 +293,47 @@ Fragment getFragment() {
#endif // SHOW_CHUNK_EDGES
#if SHADOW_MAPPING_ENABLED
// 0.0 is full shadow, 1.0 is no shadow
float shadow = 1.0;
if (shadowCoords.w > 1) {
vec4 normalizedShadowCoords = shadowCoords;
normalizedShadowCoords.z = normalizeFloat(zFightingPercentage * normalizedShadowCoords.w);
normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w;
normalizedShadowCoords.w = 1.0;
// Light through rings is colored, default full white
vec3 lightColor = vec3(1.0);
#if USE_RING_SHADOWS
// Calculate ring shadow by projecting ring texture directly onto surface
// Assume ring lies in the XZ plane (Y=0) in object space
vec3 surfaceToSun = -normalize(lightDirectionObjSpace); // Use world coordinates
vec3 p = posObjSpace;
vec3 ringPlaneNormal = vec3(0.0, 0.0, 1.0);
if (abs(surfaceToSun.y) > 1e-8 && dot(normalObjSpace, lightDirectionObjSpace) < 0.0) {
float t = rayPlaneIntersection(p, surfaceToSun, vec3(0.0), ringPlaneNormal);
vec3 ringIntersection = p + t * surfaceToSun;
// Calculate distance from ring center
float tx = length(ringIntersection.xy) / ringSize;
// See advanced_rings_fs.glsl for explanation of textureOffset
float texCoord = (tx - textureOffset.x) / (textureOffset.y - textureOffset.x);
float sum = 0;
#for i in 0..#{nShadowSamples}
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-NSSamples + #{i}, -NSSamples + #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-NSSamples + #{i}, 0));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-NSSamples + #{i}, NSSamples - #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, -NSSamples + #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, NSSamples - #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, -NSSamples + #{i}));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, 0));
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( NSSamples - #{i}, NSSamples - #{i}));
#endfor
sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0));
shadow = sum / (8.0 * NSSamples + 1.f);
}
frag.color.xyz *= shadow < 0.99 ? clamp(shadow + 0.3, 0.0, 1.0) : shadow;
#endif
if (texCoord >= 0.0 && texCoord <= 1.0) {
// Sample ring transparency texture
float ringOpacity = texture(ringTextureTransparency, texCoord).r;
// Increase the shadow darkness factor with low angle to simulate the light having
// to pass through more material
float angleFactor = clamp(abs(-dot(ringPlaneNormal, surfaceToSun)) / 2.0, 0.0, 0.3);
// Calculate shadow factor based on ring opacity
shadow = clamp(ringOpacity + angleFactor, 0.05, 1.0);
lightColor = texture(ringTextureColor, texCoord).rgb;
}
}
#endif // USE_RING_SHADOWS
// Blend the light color passing through the rings with the pre-shaded color
frag.color.rgb = mix(preShadedColor * lightColor * ambientIntensity, frag.color.rgb, shadow);
#endif // SHADOW_MAPPING_ENABLED
frag.color.a *= opacity;
frag.color = clamp(frag.color, 0.0, 1.0);
@@ -64,7 +64,11 @@
#define SHOW_CHUNK_EDGES #{showChunkEdges}
#define SHOW_HEIGHT_RESOLUTION #{showHeightResolution}
#define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities}
// Show shadow from globe onto rings
#define SHADOW_MAPPING_ENABLED #{enableShadowMapping}
// Show shadow from rings onto globe
#define USE_RING_SHADOWS #{useRingShadows}
const vec3 DefaultLevelWeights = vec3(1.0, 0.0, 0.0);
@@ -587,7 +587,7 @@ void GeoJsonComponent::update() {
}
void GeoJsonComponent::readFile() {
std::ifstream file(_geoJsonFile);
std::ifstream file = std::ifstream(_geoJsonFile);
if (!file.good()) {
LERROR(std::format("Failed to open GeoJSON file: {}", _geoJsonFile.value()));
@@ -601,6 +601,14 @@ void GeoJsonComponent::readFile() {
std::istreambuf_iterator<char>()
);
// For the loading, we want to assume that the current working directory is where the
// GeoJSON file is located
const std::filesystem::path cwd = std::filesystem::current_path();
std::filesystem::path jsonDir =
std::filesystem::path(_geoJsonFile.value()).parent_path();
std::filesystem::current_path(jsonDir);
defer { std::filesystem::current_path(cwd); };
// Parse GeoJSON string into GeoJSON objects
try {
const geos::io::GeoJSONReader reader;
@@ -26,6 +26,7 @@
#include <modules/globebrowsing/src/renderableglobe.h>
#include <openspace/documentation/documentation.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <geos/io/GeoJSON.h>
#include <scn/scan.h>
@@ -527,7 +528,8 @@ GeoJsonOverrideProperties propsFromGeoJson(const geos::io::GeoJSONFeature& featu
result.pointSize = static_cast<float>(value.getNumber());
}
else if (keyMatches(key, propertykeys::Texture, PointTextureInfo)) {
result.pointTexture = value.getString();
std::string texture = value.getString();
result.pointTexture = absPath(texture);
}
else if (keyMatches(key, propertykeys::PointTextureAnchor, PointAnchorOptionInfo))
{
@@ -628,8 +630,8 @@ float PropertySet::pointSize() const {
return overrideValues.pointSize.value_or(defaultValues.pointSize);
}
std::string PropertySet::pointTexture() const {
return overrideValues.pointTexture.value_or(defaultValues.pointTexture);
std::filesystem::path PropertySet::pointTexture() const {
return overrideValues.pointTexture.value_or(defaultValues.pointTexture.value());
}
GeoJsonProperties::PointTextureAnchor PropertySet::pointTextureAnchor() const {
@@ -107,7 +107,7 @@ struct GeoJsonOverrideProperties {
std::optional<float> lineWidth;
std::optional<float> pointSize;
std::optional<std::string> pointTexture;
std::optional<std::filesystem::path> pointTexture;
std::optional<GeoJsonProperties::PointTextureAnchor> pointTextureAnchor;
std::optional<bool> extrude;
@@ -135,7 +135,7 @@ struct PropertySet {
float lineWidth() const;
float pointSize() const;
std::string pointTexture() const;
std::filesystem::path pointTexture() const;
GeoJsonProperties::PointTextureAnchor pointTextureAnchor() const;
bool extrude() const;
@@ -115,7 +115,7 @@ bool GlobeGeometryFeature::useHeightMap() const {
}
void GlobeGeometryFeature::updateTexture(bool isInitializeStep) {
std::string texture;
std::filesystem::path texture;
GlobeBrowsingModule* m = global::moduleEngine->module<GlobeBrowsingModule>();
if (!isInitializeStep && _properties.hasOverrideTexture()) {
@@ -144,15 +144,14 @@ void GlobeGeometryFeature::updateTexture(bool isInitializeStep) {
_pointTexture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
}
std::filesystem::path texturePath = absPath(texture);
if (std::filesystem::is_regular_file(texturePath)) {
if (std::filesystem::is_regular_file(texture)) {
_hasTexture = true;
_pointTexture->loadFromFile(texture);
_pointTexture->uploadToGpu();
}
else {
LERROR(std::format(
"Trying to use texture file that does not exist: {}", texturePath
"Trying to use texture file that does not exist: {}", texture
));
}
}
@@ -266,7 +266,7 @@ std::optional<std::string> RawTileDataReader::mrfCache() {
// We don't support these formats as they will typically lack
// crucial imformation such as GeoTags. It also makes little sense to
// cache them as they are already local files.
// If it is crucial to cache a dataset of this type, convert it to geotiff.
// If it is crucial to cache a dataset of this type, convert it to GeoTIFF.
constexpr std::array<std::string_view, 11> Unsupported = {
"jpeg", "jpg",
"png",
@@ -281,10 +281,6 @@ std::optional<std::string> RawTileDataReader::mrfCache() {
for (std::string_view fmt : Unsupported) {
if (_datasetFilePath.ends_with(fmt)) {
LWARNING(std::format(
"Unsupported file format for MRF caching: '{}', Dataset: '{}'",
fmt, _datasetFilePath
));
return std::nullopt;
}
}
+95 -90
View File
@@ -773,7 +773,24 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
_ringsComponent = std::make_unique<RingsComponent>(*p.rings);
_ringsComponent->setParentFadeable(this);
_ringsComponent->initialize();
_ringsComponent->onReadinessChange([this]() {
_shadersNeedRecompilation = true;
});
addPropertySubOwner(_ringsComponent.get());
auto* enabledProperty = static_cast<properties::BoolProperty*>(
_ringsComponent->property("Enabled")
);
if (enabledProperty) {
enabledProperty->onChange([this]() {
_shadersNeedRecompilation = true;
});
}
// Set up notification for shader recompilation when rings readiness changes
_ringsComponent->onReadinessChange([this]() {
_shadersNeedRecompilation = true;
});
}
if (p.shadows.has_value()) {
@@ -865,15 +882,8 @@ void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask
glDisable(GL_BLEND);
// Render from light source point of view
// (Rings are skipped because the shadow is drawn directly onto the globe)
renderChunks(lightRenderData, rendererTask, {}, true);
if (_ringsComponent && _ringsComponent->isEnabled() &&
_ringsComponent->isVisible())
{
_ringsComponent->draw(
lightRenderData,
RingsComponent::RenderPass::GeometryOnly
);
}
glEnable(GL_BLEND);
@@ -884,11 +894,7 @@ void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask
if (_ringsComponent && _ringsComponent->isEnabled() &&
_ringsComponent->isVisible())
{
_ringsComponent->draw(
data,
RingsComponent::RenderPass::GeometryAndShading,
_shadowComponent->shadowMapData()
);
_ringsComponent->draw(data, _shadowComponent->shadowMapData());
}
}
else {
@@ -896,10 +902,7 @@ void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask
if (_ringsComponent && _ringsComponent->isEnabled() &&
_ringsComponent->isVisible())
{
_ringsComponent->draw(
data,
RingsComponent::RenderPass::GeometryAndShading
);
_ringsComponent->draw(data);
}
}
}
@@ -1247,24 +1250,14 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
const bool waterLayersActive =
!_layerManager.layerGroup(Group::ID::WaterMasks).activeLayers().empty();
if (nightLayersActive || waterLayersActive || _performShading) {
const glm::dvec3 directionToSunWorldSpace =
directionToLightSource(data.modelTransform.translation, _lightSourceNode);
const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform *
glm::dvec4(directionToSunWorldSpace, 0));
// @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better
// way is to figure out with the uniform is optimized away. I assume that it is
// because the shader doesn't get recompiled when the last layer of the night
// or water is disabled; so the shader thinks it has to do the calculation, but
// there are actually no layers left
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
if (_useAccurateNormals && hasHeightLayer) {
// Apply an extra scaling to the height if the object is scaled
_localRenderer.program->setUniform(
"lightDirectionCameraSpace",
-glm::normalize(directionToSunCameraSpace)
"heightScale",
static_cast<float>(
glm::compMax(data.modelTransform.scale) * data.camera.scaling()
)
);
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
}
// Local shader
@@ -1273,24 +1266,35 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
data.camera.sgctInternal.projectionMatrix()
);
// Light direction uniforms, only used in fragment shader
if (nightLayersActive || waterLayersActive || _performShading) {
const glm::dvec3 directionToSunWorldSpace =
directionToLightSource(data.modelTransform.translation, _lightSourceNode);
const glm::vec3 directionToSunCameraSpace(viewTransform *
glm::dvec4(directionToSunWorldSpace, 0.0));
const glm::vec3 directionToSunObjSpace(_cachedInverseModelTransform *
glm::dvec4(directionToSunWorldSpace, 0.0));
const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform *
glm::dvec4(directionToSunWorldSpace, 0));
// @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better
// way is to figure out with the uniform is optimized away. I assume that it is
// because the shader doesn't get recompiled when the last layer of the night
// or water is disabled; so the shader thinks it has to do the calculation, but
// there are actually no layers left
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
// Set the light direction uniforms for local renderer
_globalRenderer.program->setUniform(
"lightDirectionCameraSpace",
-glm::normalize(directionToSunCameraSpace)
);
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_localRenderer.program->setUniform(
"lightDirectionCameraSpace",
-glm::normalize(directionToSunCameraSpace)
);
if (_ringsComponent) {
_localRenderer.program->setUniform(
"lightDirectionObjSpace",
-glm::normalize(directionToSunObjSpace)
);
_globalRenderer.program->setUniform(
"lightDirectionObjSpace",
-glm::normalize(directionToSunObjSpace)
);
}
}
int globalCount = 0;
@@ -1452,31 +1456,27 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData&
}
// Shadow Mapping
ghoul::opengl::TextureUnit shadowMapUnit;
if (_shadowMappingProperties.shadowMapping && shadowData.shadowDepthTexture != 0) {
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of the
// light position.
program.setUniform(
"shadowMatrix",
shadowData.shadowMatrix * modelTransform()
);
if (_shadowMappingProperties.shadowMapping) {
// Bind ring textures for direct projection when rings component is available
if (_ringsComponent && _ringsComponent->isEnabled()) {
ghoul::opengl::TextureUnit ringTextureColorUnit;
ghoul::opengl::TextureUnit ringTextureTransparencyUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
if (_ringsComponent->textureColor()) {
ringTextureColorUnit.activate();
_ringsComponent->textureColor()->bind();
program.setUniform("ringTextureColor", ringTextureColorUnit);
}
program.setUniform("shadowMapTexture", shadowMapUnit);
program.setUniform(
"zFightingPercentage",
_shadowMappingProperties.zFightingPercentage
);
}
else if (_shadowMappingProperties.shadowMapping && _shadowComponent) {
shadowMapUnit.activate();
// JCC: Avoiding a to recompiling the shaders or having more than one
// set of shaders for this step.
glBindTexture(GL_TEXTURE_2D, _shadowComponent->dDepthTexture());
program.setUniform("shadowMapTexture", shadowMapUnit);
if (_ringsComponent->textureTransparency()) {
ringTextureTransparencyUnit.activate();
_ringsComponent->textureTransparency()->bind();
program.setUniform("ringTextureTransparency", ringTextureTransparencyUnit);
}
program.setUniform("textureOffset", _ringsComponent->textureOffset());
program.setUniform("ringSize", (float)_ringsComponent->size());
}
}
glEnable(GL_DEPTH_TEST);
@@ -1590,33 +1590,29 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d
if (_eclipseShadowsEnabled && !_ellipsoid.shadowConfigurationArray().empty()) {
calculateEclipseShadows(program, data, ShadowCompType::LOCAL_SHADOW);
}
// Shadow Mapping
ghoul::opengl::TextureUnit shadowMapUnit;
if (_shadowMappingProperties.shadowMapping && shadowData.shadowDepthTexture != 0) {
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of the
// light position.
program.setUniform(
"shadowMatrix",
shadowData.shadowMatrix * modelTransform()
);
// Bind ring textures for direct projection when rings component is available
if (_ringsComponent && _ringsComponent->isEnabled()) {
ghoul::opengl::TextureUnit ringTextureColorUnit;
ghoul::opengl::TextureUnit ringTextureTransparencyUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
if (_ringsComponent->textureColor()) {
ringTextureColorUnit.activate();
_ringsComponent->textureColor()->bind();
program.setUniform("ringTextureColor", ringTextureColorUnit);
}
program.setUniform("shadowMapTexture", shadowMapUnit);
program.setUniform(
"zFightingPercentage",
_shadowMappingProperties.zFightingPercentage
);
}
else if (_shadowMappingProperties.shadowMapping) {
shadowMapUnit.activate();
// JCC: Avoiding a to recompiling the shaders or having more than one
// set of shaders for this step.
glBindTexture(GL_TEXTURE_2D, _shadowComponent->dDepthTexture());
program.setUniform("shadowMapTexture", shadowMapUnit);
if (_ringsComponent->textureTransparency()) {
ringTextureTransparencyUnit.activate();
_ringsComponent->textureTransparency()->bind();
program.setUniform("ringTextureTransparency", ringTextureTransparencyUnit);
}
program.setUniform("textureOffset", _ringsComponent->textureOffset());
program.setUniform("ringSize", (float)_ringsComponent->size());
}
}
glEnable(GL_DEPTH_TEST);
@@ -1718,6 +1714,12 @@ void RenderableGlobe::setCommonUniforms(ghoul::opengl::ProgramObject& programObj
programObject.setUniform("deltaPhi1", glm::length(deltaPhi1));
programObject.setUniform("tileDelta", TileDelta);
}
// Used by local and global renderer, as well as geojson
using ghoul::opengl::ProgramObject;
programObject.setIgnoreUniformLocationError(ProgramObject::IgnoreError::Yes);
programObject.setUniform("modelTransform", _cachedModelTransform);
programObject.setIgnoreUniformLocationError(ProgramObject::IgnoreError::No);
}
void RenderableGlobe::recompileShaders() {
@@ -1787,6 +1789,10 @@ void RenderableGlobe::recompileShaders() {
"enableShadowMapping",
std::to_string(_shadowMappingProperties.shadowMapping && _shadowComponent)
);
pairs.emplace_back(
"useRingShadows",
std::to_string(_shadowMappingProperties.shadowMapping && _ringsComponent)
);
pairs.emplace_back("showChunkEdges", std::to_string(_debugProperties.showChunkEdges));
pairs.emplace_back("showHeightResolution", "0");
pairs.emplace_back("showHeightIntensities", "0");
@@ -2492,7 +2498,6 @@ bool RenderableGlobe::isCullableByHorizon(const Chunk& chunk,
);
const glm::dvec3& globeToCamera = cameraPos;
const Geodetic2 camPosOnGlobe = _ellipsoid.cartesianToGeodetic2(globeToCamera);
const Geodetic2 closestPatchPoint = patch.closestPoint(camPosOnGlobe);
glm::dvec3 objectPos = _ellipsoid.cartesianSurfacePosition(closestPatchPoint);
+188 -182
View File
@@ -351,6 +351,9 @@ void RingsComponent::initializeGL() {
glGenBuffers(1, &_vertexPositionBuffer);
createPlane();
// Check if readiness state has changed after shader compilation
checkAndNotifyReadinessChange();
}
void RingsComponent::deinitializeGL() {
@@ -377,15 +380,10 @@ void RingsComponent::deinitializeGL() {
_geometryOnlyShader = nullptr;
}
void RingsComponent::draw(const RenderData& data, RenderPass renderPass,
void RingsComponent::draw(const RenderData& data,
const ShadowComponent::ShadowMapData& shadowData)
{
if (renderPass == RenderPass::GeometryAndShading) {
_shader->activate();
}
else if (renderPass == RenderPass::GeometryOnly) {
_geometryOnlyShader->activate();
}
_shader->activate();
const glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
@@ -402,165 +400,142 @@ void RingsComponent::draw(const RenderData& data, RenderPass renderPass,
ghoul::opengl::TextureUnit ringTextureUnlitUnit;
ghoul::opengl::TextureUnit ringTextureColorUnit;
ghoul::opengl::TextureUnit ringTextureTransparencyUnit;
if (renderPass == RenderPass::GeometryAndShading) {
if (_isAdvancedTextureEnabled) {
_shader->setUniform(
_uniformCacheAdvancedRings.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(_uniformCacheAdvancedRings.textureOffset, _offset);
_shader->setUniform(
_uniformCacheAdvancedRings.colorFilterValue,
_colorFilter
);
_shader->setUniform(_uniformCacheAdvancedRings.nightFactor, _nightFactor);
_shader->setUniform(_uniformCacheAdvancedRings.sunPosition, _sunPosition);
if (_isAdvancedTextureEnabled) {
_shader->setUniform(
_uniformCacheAdvancedRings.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(_uniformCacheAdvancedRings.textureOffset, _offset);
_shader->setUniform(_uniformCacheAdvancedRings.colorFilterValue, _colorFilter);
_shader->setUniform(_uniformCacheAdvancedRings.nightFactor, _nightFactor);
_shader->setUniform(_uniformCacheAdvancedRings.sunPosition, _sunPosition);
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
const glm::vec3 sunPositionObjectSpace = glm::normalize(
glm::vec3(inverseModelTransform * glm::vec4(_sunPosition, 0.f))
);
const glm::vec3 sunPositionObjectSpace = glm::normalize(
glm::vec3(inverseModelTransform * glm::vec4(_sunPosition, 0.f))
);
_shader->setUniform(
_uniformCacheAdvancedRings.sunPositionObj,
sunPositionObjectSpace
);
_shader->setUniform(
_uniformCacheAdvancedRings.zFightingPercentage,
_zFightingPercentage
);
_shader->setUniform(
_uniformCacheAdvancedRings.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(
_uniformCacheAdvancedRings.sunPositionObj,
sunPositionObjectSpace
);
_shader->setUniform(
_uniformCacheAdvancedRings.zFightingPercentage,
_zFightingPercentage
);
_shader->setUniform(
_uniformCacheAdvancedRings.modelViewProjectionMatrix,
modelViewProjectionTransform
);
ringTextureFwrdUnit.activate();
_textureForwards->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.ringTextureFwrd,
ringTextureFwrdUnit
);
ringTextureFwrdUnit.activate();
_textureForwards->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.textureForwards,
ringTextureFwrdUnit
);
ringTextureBckwrdUnit.activate();
_textureBackwards->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.ringTextureBckwrd,
ringTextureBckwrdUnit
);
ringTextureBckwrdUnit.activate();
_textureBackwards->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.textureBackwards,
ringTextureBckwrdUnit
);
ringTextureUnlitUnit.activate();
_textureUnlit->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.ringTextureUnlit,
ringTextureUnlitUnit
);
ringTextureUnlitUnit.activate();
_textureUnlit->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.textureUnlit,
ringTextureUnlitUnit
);
ringTextureColorUnit.activate();
_textureColor->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.ringTextureColor,
ringTextureColorUnit
);
ringTextureColorUnit.activate();
_textureColor->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.textureColor,
ringTextureColorUnit
);
ringTextureTransparencyUnit.activate();
_textureTransparency->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.ringTextureTransparency,
ringTextureTransparencyUnit
);
_shader->setUniform(_uniformCacheAdvancedRings.opacity, opacity());
ringTextureTransparencyUnit.activate();
_textureTransparency->bind();
_shader->setUniform(
_uniformCacheAdvancedRings.textureTransparency,
ringTextureTransparencyUnit
);
_shader->setUniform(_uniformCacheAdvancedRings.opacity, opacity());
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of
// the light position.
_shader->setUniform(
_uniformCacheAdvancedRings.shadowMatrix,
shadowData.shadowMatrix * modelTransform
);
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of
// the light position.
_shader->setUniform(
_uniformCacheAdvancedRings.shadowMatrix,
shadowData.shadowMatrix * modelTransform
);
const glm::dmat4 camToObjectTransform = glm::inverse(
data.camera.combinedViewMatrix()
* modelTransform
);
const glm::dmat4 camToObjectTransform = glm::inverse(
data.camera.combinedViewMatrix() * modelTransform
);
_camPositionObjectSpace = glm::normalize(
glm::vec3(camToObjectTransform * glm::dvec4(0.0, 0.0, 0.0, 1.0))
);
_camPositionObjectSpace = glm::normalize(
glm::vec3(camToObjectTransform * glm::dvec4(0.0, 0.0, 0.0, 1.0))
);
_shader->setUniform(
_uniformCacheAdvancedRings.camPositionObj,
_camPositionObjectSpace
);
_shader->setUniform(
_uniformCacheAdvancedRings.camPositionObj,
_camPositionObjectSpace
);
ghoul::opengl::TextureUnit shadowMapUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
_shader->setUniform(
_uniformCacheAdvancedRings.shadowMapTexture,
shadowMapUnit
);
glEnable(GL_DEPTH_TEST);
glEnablei(GL_BLEND, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else {
_shader->setUniform(
_uniformCache.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(_uniformCache.textureOffset, _offset);
_shader->setUniform(_uniformCache.colorFilterValue, _colorFilter);
_shader->setUniform(_uniformCache.nightFactor, _nightFactor);
_shader->setUniform(_uniformCache.sunPosition, _sunPosition);
_shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage);
_shader->setUniform(
_uniformCache.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(_uniformCache.opacity, opacity());
ringTextureUnit.activate();
_texture->bind();
_shader->setUniform(_uniformCache.ringTexture, ringTextureUnit);
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of
// the light position.
_shader->setUniform(
_uniformCache.shadowMatrix,
shadowData.shadowMatrix * modelTransform
);
ghoul::opengl::TextureUnit shadowMapUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
_shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit);
}
ghoul::opengl::TextureUnit shadowMapUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
_shader->setUniform(
_uniformCacheAdvancedRings.shadowMapTexture,
shadowMapUnit
);
glEnable(GL_DEPTH_TEST);
glEnablei(GL_BLEND, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else if (renderPass == RenderPass::GeometryOnly) {
_geometryOnlyShader->setUniform(
_geomUniformCache.modelViewProjectionMatrix,
else {
_shader->setUniform(
_uniformCache.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_geometryOnlyShader->setUniform(_geomUniformCache.textureOffset, _offset);
_shader->setUniform(_uniformCache.textureOffset, _offset);
_shader->setUniform(_uniformCache.colorFilterValue, _colorFilter);
_shader->setUniform(_uniformCache.nightFactor, _nightFactor);
_shader->setUniform(_uniformCache.sunPosition, _sunPosition);
_shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage);
_shader->setUniform(
_uniformCache.modelViewProjectionMatrix,
modelViewProjectionTransform
);
_shader->setUniform(_uniformCache.opacity, opacity());
ringTextureUnit.activate();
if (_isAdvancedTextureEnabled) {
_textureForwards->bind();
}
else {
_texture->bind();
}
_texture->bind();
_shader->setUniform(_uniformCache.ringTexture, ringTextureUnit);
_geometryOnlyShader->setUniform(_geomUniformCache.ringTexture, ringTextureUnit);
// Adding the model transformation to the final shadow matrix so we have a
// complete transformation from the model coordinates to the clip space of
// the light position.
_shader->setUniform(
_uniformCache.shadowMatrix,
shadowData.shadowMatrix * modelTransform
);
ghoul::opengl::TextureUnit shadowMapUnit;
shadowMapUnit.activate();
glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture);
_shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit);
}
glEnable(GL_DEPTH_TEST);
glEnablei(GL_BLEND, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
@@ -569,13 +544,8 @@ void RingsComponent::draw(const RenderData& data, RenderPass renderPass,
glEnable(GL_CULL_FACE);
if (renderPass == RenderPass::GeometryAndShading) {
_shader->deactivate();
global::renderEngine->openglStateCache().resetBlendState();
}
else if (renderPass == RenderPass::GeometryOnly) {
_geometryOnlyShader->deactivate();
}
_shader->deactivate();
global::renderEngine->openglStateCache().resetBlendState();
}
void RingsComponent::update(const UpdateData& data) {
@@ -645,17 +615,14 @@ void RingsComponent::loadTexture() {
);
if (textureForwards) {
LDEBUG(
std::format(
"Loaded forwards scattering texture from '{}'",
absPath(_textureFwrdPath)
)
);
LDEBUG(std::format(
"Loaded forwards scattering texture from '{}'",
absPath(_textureFwrdPath)
));
_textureForwards = std::move(textureForwards);
_textureForwards->uploadTexture();
_textureForwards->setFilter(
ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
_textureForwards->setFilter(Texture::FilterMode::AnisotropicMipMap);
_textureFileForwards = std::make_unique<ghoul::filesystem::File>(
_textureFwrdPath.value()
@@ -671,17 +638,14 @@ void RingsComponent::loadTexture() {
);
if (textureBackwards) {
LDEBUG(
std::format(
"Loaded backwards scattering texture from '{}'",
absPath(_textureBckwrdPath)
)
);
LDEBUG(std::format(
"Loaded backwards scattering texture from '{}'",
absPath(_textureBckwrdPath)
));
_textureBackwards = std::move(textureBackwards);
_textureBackwards->uploadTexture();
_textureBackwards->setFilter(
ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
_textureBackwards->setFilter(Texture::FilterMode::AnisotropicMipMap);
_textureFileBackwards = std::make_unique<ghoul::filesystem::File>(
_textureBckwrdPath.value()
@@ -697,9 +661,9 @@ void RingsComponent::loadTexture() {
);
if (textureUnlit) {
LDEBUG(
std::format("Loaded unlit texture from '{}'", absPath(_textureUnlitPath))
);
LDEBUG(std::format(
"Loaded unlit texture from '{}'", absPath(_textureUnlitPath)
));
_textureUnlit = std::move(textureUnlit);
_textureUnlit->uploadTexture();
@@ -741,15 +705,13 @@ void RingsComponent::loadTexture() {
);
if (textureTransparency) {
LDEBUG(
std::format("Loaded unlit texture from '{}'", absPath(_textureUnlitPath))
);
LDEBUG(std::format(
"Loaded transparency texture from '{}'", absPath(_textureTransparencyPath)
));
_textureTransparency = std::move(textureTransparency);
_textureTransparency->uploadTexture();
_textureTransparency->setFilter(
ghoul::opengl::Texture::FilterMode::AnisotropicMipMap
);
_textureTransparency->setFilter(Texture::FilterMode::AnisotropicMipMap);
_textureFileTransparency = std::make_unique<ghoul::filesystem::File>(
_textureTransparencyPath.value()
@@ -759,6 +721,9 @@ void RingsComponent::loadTexture() {
}
_isAdvancedTextureEnabled = _textureForwards && _textureBackwards && _textureUnlit;
// Check if readiness state has changed after loading textures
checkAndNotifyReadinessChange();
}
void RingsComponent::createPlane() {
@@ -821,14 +786,6 @@ void RingsComponent::compileShadowShader() {
try {
global::renderEngine->removeRenderProgram(_shader.get());
// _shader = global::renderEngine->buildRenderProgram(
// "RingsProgram",
// absPath("${MODULE_GLOBEBROWSING}/shaders/rings_vs.glsl"),
// absPath("${MODULE_GLOBEBROWSING}/shaders/rings_fs.glsl"),
// dict
// );
// ghoul::opengl::updateUniformLocations(*_shader, _uniformCache);
// Uses multiple textures for the Rings
// See https://bjj.mmedia.is/data/s_rings/index.html for theory behind it
@@ -857,6 +814,9 @@ void RingsComponent::compileShadowShader() {
catch (const ghoul::RuntimeError& e) {
LERROR(e.message);
}
// Check if readiness state has changed after shader compilation
checkAndNotifyReadinessChange();
}
bool RingsComponent::isEnabled() const {
@@ -867,4 +827,50 @@ double RingsComponent::size() const {
return _size;
}
ghoul::opengl::Texture* RingsComponent::textureForwards() const {
return _textureForwards.get();
}
ghoul::opengl::Texture* RingsComponent::textureBackwards() const {
return _textureBackwards.get();
}
ghoul::opengl::Texture* RingsComponent::textureUnlit() const {
return _textureUnlit.get();
}
ghoul::opengl::Texture* RingsComponent::textureColor() const {
return _textureColor.get();
}
ghoul::opengl::Texture* RingsComponent::textureTransparency() const {
return _textureTransparency.get();
}
glm::vec2 RingsComponent::textureOffset() const {
return _offset;
}
glm::vec3 RingsComponent::sunPositionObj() const {
return _sunPosition;
}
glm::vec3 RingsComponent::camPositionObj() const {
return _camPositionObjectSpace;
}
void RingsComponent::onReadinessChange(ReadinessChangeCallback callback) {
_readinessChangeCallback = std::move(callback);
}
void RingsComponent::checkAndNotifyReadinessChange() {
const bool currentlyReady = isReady();
if (currentlyReady != _wasReady) {
_wasReady = currentlyReady;
if (_readinessChangeCallback) {
_readinessChangeCallback();
}
}
}
} // namespace openspace
+24 -9
View File
@@ -51,10 +51,8 @@ namespace documentation { struct Documentation; }
class RingsComponent : public properties::PropertyOwner, public Fadeable {
public:
enum class RenderPass {
GeometryOnly,
GeometryAndShading
};
// Callback for when readiness state changes
using ReadinessChangeCallback = std::function<void()>;
explicit RingsComponent(const ghoul::Dictionary& dictionary);
@@ -64,20 +62,33 @@ public:
bool isReady() const;
void draw(const RenderData& data, RenderPass renderPass,
void draw(const RenderData& data,
const ShadowComponent::ShadowMapData& shadowData = {}
);
void update(const UpdateData& data);
bool isEnabled() const;
static documentation::Documentation Documentation();
bool isEnabled() const;
double size() const;
// Readiness change callback
void onReadinessChange(ReadinessChangeCallback callback);
// Texture access methods for globe rendering
ghoul::opengl::Texture* textureForwards() const;
ghoul::opengl::Texture* textureBackwards() const;
ghoul::opengl::Texture* textureUnlit() const;
ghoul::opengl::Texture* textureColor() const;
ghoul::opengl::Texture* textureTransparency() const;
glm::vec2 textureOffset() const;
glm::vec3 sunPositionObj() const;
glm::vec3 camPositionObj() const;
private:
void loadTexture();
void createPlane();
void compileShadowShader();
void checkAndNotifyReadinessChange();
properties::StringProperty _texturePath;
properties::StringProperty _textureFwrdPath;
@@ -100,8 +111,8 @@ private:
opacity
) _uniformCache;
UniformCache(modelViewProjectionMatrix, textureOffset, colorFilterValue, nightFactor,
sunPosition, sunPositionObj, camPositionObj, ringTextureFwrd, ringTextureBckwrd,
ringTextureUnlit, ringTextureColor, ringTextureTransparency, shadowMatrix,
sunPosition, sunPositionObj, camPositionObj, textureForwards, textureBackwards,
textureUnlit, textureColor, textureTransparency, shadowMatrix,
shadowMapTexture, zFightingPercentage, opacity
) _uniformCacheAdvancedRings;
UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture) _geomUniformCache;
@@ -128,6 +139,10 @@ private:
glm::vec3 _sunPosition = glm::vec3(0.f);
glm::vec3 _camPositionObjectSpace = glm::vec3(0.f);
// Callback for readiness state changes
ReadinessChangeCallback _readinessChangeCallback;
bool _wasReady = false;
};
} // namespace openspace
@@ -77,7 +77,7 @@ void KameleonDocumentationTask::perform(const Task::ProgressCallback & progressC
ghoul::Dictionary dictionary;
dictionary.setValue("kameleon", std::move(kameleonDictionary));
dictionary.setValue("version", std::string(OPENSPACE_VERSION_NUMBER));
dictionary.setValue("version", std::string(OPENSPACE_VERSION));
dictionary.setValue("input", _inputPath.string());
std::string json = ghoul::formatJson(dictionary);
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<!--The compatibility section will be merged from build/win/compatibility.manifest -->
<dependency>
<dependentAssembly>
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
+1 -1
View File
@@ -420,7 +420,7 @@ void OpenSpaceEngine::initialize() {
}
LINFOC("OpenSpace Version", std::string(OPENSPACE_VERSION_STRING_FULL));
LINFOC("OpenSpace Version", std::string(OPENSPACE_VERSION));
LINFOC("Commit", std::string(OPENSPACE_GIT_FULL));
// Register modules
+1 -1
View File
@@ -168,7 +168,7 @@ LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
_labelFile = absPath(p.file.value_or(""));
_labelFile = p.file.has_value() ? absPath(*p.file) : "";
_useCache = p.useCaching.value_or(true);
if (p.unit.has_value()) {
+3 -3
View File
@@ -1238,7 +1238,7 @@ void RenderEngine::renderVersionInformation() {
if (global::versionChecker->hasLatestVersionInfo()) {
VersionChecker::SemanticVersion ver = global::versionChecker->latestVersion();
std::string versionString = std::string(OPENSPACE_VERSION_STRING_FULL);
std::string versionString = std::string(OPENSPACE_VERSION);
const VersionChecker::SemanticVersion current {
OPENSPACE_VERSION_MAJOR,
OPENSPACE_VERSION_MINOR,
@@ -1259,11 +1259,11 @@ void RenderEngine::renderVersionInformation() {
);
}
else {
versionBox = _fontVersionInfo->boundingBox(OPENSPACE_VERSION_STRING_FULL);
versionBox = _fontVersionInfo->boundingBox(OPENSPACE_VERSION);
FR::defaultRenderer().render(
*_fontVersionInfo,
glm::vec2(fontResolution().x - versionBox.x - 10.f, 5.f),
OPENSPACE_VERSION_STRING_FULL,
OPENSPACE_VERSION,
glm::vec4(0.5f, 0.5f, 0.5f, 1.f)
);
}
+5 -11
View File
@@ -94,18 +94,12 @@ void TextureComponent::loadFromFile(const std::filesystem::path& path) {
using namespace ghoul::io;
using namespace ghoul::opengl;
std::filesystem::path absolutePath = absPath(path);
std::unique_ptr<Texture> tex = TextureReader::ref().loadTexture(path, _nDimensions);
if (tex) {
LDEBUG(std::format("Loaded texture from '{}'", path));
_texture = std::move(tex);
std::unique_ptr<Texture> texture = TextureReader::ref().loadTexture(
absolutePath,
_nDimensions
);
if (texture) {
LDEBUG(std::format("Loaded texture from '{}'", absolutePath));
_texture = std::move(texture);
_textureFile = std::make_unique<ghoul::filesystem::File>(absolutePath);
_textureFile = std::make_unique<ghoul::filesystem::File>(path);
if (_shouldWatchFile) {
_textureFile->setCallback([this]() { _fileIsDirty = true; });
}
+1 -1
View File
@@ -65,7 +65,7 @@ void VersionChecker::requestLatestVersion(const std::string& url) {
std::string fullUrl = std::format(
"{}?client_version={}&commit_hash={}&operating_system={}&profile={}",
url, OPENSPACE_VERSION_NUMBER, OPENSPACE_GIT_COMMIT, operatingSystem, profile
url, OPENSPACE_VERSION, OPENSPACE_GIT_COMMIT, operatingSystem, profile
);
if (_request) {
+2 -6
View File
@@ -41,9 +41,7 @@ constexpr uint8_t OPENSPACE_VERSION_MAJOR = @OPENSPACE_VERSION_MAJOR@;
constexpr uint8_t OPENSPACE_VERSION_MINOR = @OPENSPACE_VERSION_MINOR@;
constexpr uint8_t OPENSPACE_VERSION_PATCH = @OPENSPACE_VERSION_PATCH@;
constexpr std::string_view OPENSPACE_VERSION_NUMBER = "@OPENSPACE_VERSION_MAJOR@.@OPENSPACE_VERSION_MINOR@.@OPENSPACE_VERSION_PATCH@";
constexpr std::string_view OPENSPACE_VERSION_STRING = "@OPENSPACE_VERSION_STRING@";
constexpr std::string_view OPENSPACE_VERSION_STRING_FULL = "@OPENSPACE_VERSION_MAJOR@.@OPENSPACE_VERSION_MINOR@.@OPENSPACE_VERSION_PATCH@ (@OPENSPACE_VERSION_STRING@)";
constexpr std::string_view OPENSPACE_VERSION = "@OPENSPACE_VERSION_MAJOR@.@OPENSPACE_VERSION_MINOR@.@OPENSPACE_VERSION_PATCH@";
#else // ^^^^ OPENSPACE_RELEASE_BUILD || !OPENSPACE_RELEASE_BUILD vvvv
@@ -53,9 +51,7 @@ constexpr uint8_t OPENSPACE_VERSION_MAJOR = std::numeric_limits<uint8_t>::max();
constexpr uint8_t OPENSPACE_VERSION_MINOR = std::numeric_limits<uint8_t>::max();
constexpr uint8_t OPENSPACE_VERSION_PATCH = std::numeric_limits<uint8_t>::max();
constexpr std::string_view OPENSPACE_VERSION_NUMBER = "";
constexpr std::string_view OPENSPACE_VERSION_STRING = "";
constexpr std::string_view OPENSPACE_VERSION_STRING_FULL = "";
constexpr std::string_view OPENSPACE_VERSION = "";
#endif // OPENSPACE_RELEASE_BUILD
+3 -3
View File
@@ -37,7 +37,7 @@ set(OPENSPACE_VERSION_NUMBER
)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "OpenSpace ${OPENSPACE_VERSION_NUMBER}")
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME} ${OPENSPACE_VERSION_NUMBER} ${OPENSPACE_VERSION_STRING}"
"${CPACK_PACKAGE_NAME} ${OPENSPACE_VERSION_NUMBER}"
)
set(CPACK_STRIP_FILES 1)
@@ -74,11 +74,11 @@ if (WIN32)
set(CPACK_GENERATOR ZIP)
# Need backslash for correct subdirectory paths
set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}\\\\apps\\\\OpenSpace\\\\openspace.png")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}\\\\${OPENSPACE_VERSION_NUMBER} ${OPENSPACE_VERSION_STRING}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}\\\\${OPENSPACE_VERSION_NUMBER}")
else ()
set(CPACK_GENERATOR TGZ)
set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/apps/OpenSpace/openspace.png")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}/${OPENSPACE_VERSION_NUMBER} ${OPENSPACE_VERSION_STRING}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}/${OPENSPACE_VERSION_NUMBER}")
endif ()
option(OPENSPACE_CREATE_INSTALLER "Create an OpenSpace installer from the package" OFF)
@@ -0,0 +1,39 @@
{
"profile": "empty",
"commands": [
{
"type": "navigationstate",
"value": {
"anchor": "Saturn",
"position": [
208667642.45051652,
54126259.932879746,
57439831.8163157
],
"pitch": -0.017233194146801384,
"up": [
-0.26992564740141767,
0.01898840930203355,
0.9626939208217241
],
"yaw": -0.003697938774824961,
"timestamp": "2025 JUL 13 12:13:12"
}
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/default_layers.asset"
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/saturn.asset"
},
{
"type": "wait",
"value": 10.0
},
{
"type": "screenshot"
}
]
}
@@ -0,0 +1,39 @@
{
"profile": "empty",
"commands": [
{
"type": "navigationstate",
"value": {
"anchor": "Saturn",
"position": [
208667642.45118257,
54126259.93271133,
57439831.8162123
],
"pitch": -0.017233193591973957,
"up": [
-0.26992564738826463,
0.018988409251575723,
0.9626939208264074
],
"yaw": -0.003697934996467431,
"timestamp": "2028 MAY 14 12:13:12"
}
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/default_layers.asset"
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/saturn.asset"
},
{
"type": "wait",
"value": 10.0
},
{
"type": "screenshot"
}
]
}
@@ -0,0 +1,39 @@
{
"profile": "empty",
"commands": [
{
"type": "navigationstate",
"value": {
"anchor": "Saturn",
"position": [
-141360298.68091586,
-166699069.69779366,
-45551858.24393063
],
"pitch": 0.0064781942863547555,
"up": [
-0.14567322634534205,
-0.14393621312449992,
0.9788062513477921
],
"yaw": -0.0046432197348252,
"timestamp": "2020 MAY 14 12:12:49"
}
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/default_layers.asset"
},
{
"type": "asset",
"value": "scene/solarsystem/planets/saturn/saturn.asset"
},
{
"type": "wait",
"value": 10.0
},
{
"type": "screenshot"
}
]
}