mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 19:19:39 -06:00
Add the ability to load images lazily for RenderablePlanes
Add ability to purge textures from RAM if they are read-only
Make use of both for constellation images to reduce the memory footprint
(cherry picked from commit 7f0c92430f)
This commit is contained in:
Submodule apps/OpenSpace/ext/sgct updated: 95d4237eaf...0d902bbe4f
@@ -1,11 +1,102 @@
|
||||
local constellation_helper = asset.require('./generate_constellations')
|
||||
|
||||
local constellationsCSV = asset.localResource('constellation_data.csv')
|
||||
local transforms = asset.require("scene/solarsystem/sun/transforms")
|
||||
|
||||
local images = asset.syncedResource({
|
||||
Name = "Constellation Images",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "constellation_images",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
-- local image_resolution = "low"
|
||||
-- local image_resolution = "medium"
|
||||
local image_resolution = "high"
|
||||
|
||||
--function that reads the file
|
||||
local createConstellations = function (guiPath, constellationfile)
|
||||
local genConstellations = {};
|
||||
--skip the first line
|
||||
local notFirstLine = false;
|
||||
-- define parsec to meters
|
||||
local PARSEC_CONSTANT = 3.0856776E16;
|
||||
-- how many parsecs away do you want the images to be?
|
||||
-- this setting puts the billboards at the location of the constellation bounds grid from DU.
|
||||
-- but they can really be anywhere since the billboard size will scale with distance.
|
||||
local distanceMultiplier = 3.2;
|
||||
local baseScale = 1e17;
|
||||
for line in io.lines(openspace.absPath(constellationfile)) do
|
||||
if (notFirstLine) then
|
||||
-- describes the data
|
||||
local matchstring = '(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-)$'
|
||||
local group, abbreviation, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar = line:match(matchstring)
|
||||
local magVec = math.sqrt(x*x + y*y + z*z)
|
||||
local normx = x/magVec
|
||||
local normy = y/magVec
|
||||
local normz = z/magVec
|
||||
|
||||
group = (group == '' and globe or group)
|
||||
|
||||
local texture
|
||||
if image_resolution == "low" then
|
||||
texture = images .. "/" .. imageName:sub(1, -5) .. "-512.png"
|
||||
elseif image_resolution == "medium" then
|
||||
texture = images .. "/" .. imageName:sub(1, -5) .. "-1024.png"
|
||||
elseif image_resolution == "high" then
|
||||
texture = images .. "/" .. imageName
|
||||
else
|
||||
openspace.printError("Unknown image resolution: " .. image_resolution)
|
||||
end
|
||||
|
||||
local aconstellation = {
|
||||
Identifier = guiPath .. '-' .. name,
|
||||
Parent = transforms.SolarSystemBarycenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
-- position is in parsecs from the SolarSystemBarycenter, so convert to meters
|
||||
Position = {
|
||||
normx * PARSEC_CONSTANT * distanceMultiplier,
|
||||
normy * PARSEC_CONSTANT * distanceMultiplier,
|
||||
normz * PARSEC_CONSTANT * distanceMultiplier
|
||||
}
|
||||
},
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = { tonumber(rotX), tonumber(rotY), tonumber(rotZ) }
|
||||
}
|
||||
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderablePlaneImageLocal",
|
||||
Size = tonumber(baseScale * scale * distanceMultiplier / 10),
|
||||
Enabled = false,
|
||||
Origin = "Center",
|
||||
Billboard = false,
|
||||
LazyLoading = true,
|
||||
Texture = texture,
|
||||
BlendMode = "Additive",
|
||||
Opacity = 0.1
|
||||
},
|
||||
Tag = { "ConstellationArtImage", group },
|
||||
GUI = {
|
||||
Name = name .. ' Image',
|
||||
Path = '/Milky Way/' .. guiPath
|
||||
}
|
||||
}
|
||||
table.insert(genConstellations, aconstellation);
|
||||
|
||||
else
|
||||
notFirstLine = true
|
||||
end
|
||||
end
|
||||
return genConstellations
|
||||
end
|
||||
|
||||
|
||||
local nodes = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
nodes = constellation_helper.createConstellations('Constellation Art', constellationsCSV)
|
||||
nodes = createConstellations('Constellation Art', constellationsCSV)
|
||||
for _, n in ipairs(nodes) do
|
||||
openspace.addSceneGraphNode(n);
|
||||
end
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local transforms = asset.require("scene/solarsystem/sun/transforms")
|
||||
|
||||
local images = asset.syncedResource({
|
||||
Name = "Constellation Images",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "constellation_images",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
--function that reads the file
|
||||
local createConstellations = function (guiPath, constellationfile)
|
||||
local genConstellations = {};
|
||||
--skip the first line
|
||||
local notFirstLine = false;
|
||||
-- define parsec to meters
|
||||
local PARSEC_CONSTANT = 3.0856776E16;
|
||||
-- how many parsecs away do you want the images to be?
|
||||
-- this setting puts the billboards at the location of the constellation bounds grid from DU.
|
||||
-- but they can really be anywhere since the billboard size will scale with distance.
|
||||
local distanceMultiplier = 3.2;
|
||||
local baseScale = 1e17;
|
||||
for line in io.lines(openspace.absPath(constellationfile)) do
|
||||
if (notFirstLine) then
|
||||
-- describes the data
|
||||
local matchstring = '(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-)$'
|
||||
local group, abbreviation, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar = line:match(matchstring)
|
||||
local magVec = math.sqrt(x*x + y*y + z*z)
|
||||
local normx = x/magVec
|
||||
local normy = y/magVec
|
||||
local normz = z/magVec
|
||||
|
||||
group = (group == '' and globe or group)
|
||||
|
||||
local aconstellation = {
|
||||
Identifier = guiPath .. '-' .. name,
|
||||
Parent = transforms.SolarSystemBarycenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
-- position is in parsecs from the SolarSystemBarycenter, so convert to meters
|
||||
Position = {
|
||||
normx * PARSEC_CONSTANT * distanceMultiplier,
|
||||
normy * PARSEC_CONSTANT * distanceMultiplier,
|
||||
normz * PARSEC_CONSTANT * distanceMultiplier
|
||||
}
|
||||
},
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = { tonumber(rotX), tonumber(rotY), tonumber(rotZ) }
|
||||
}
|
||||
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderablePlaneImageLocal",
|
||||
Size = tonumber(baseScale*scale*distanceMultiplier/10),
|
||||
Enabled = false,
|
||||
Origin = "Center",
|
||||
Billboard = false,
|
||||
Texture = images .. "/" .. imageName,
|
||||
BlendMode = "Additive",
|
||||
Opacity = 0.1
|
||||
},
|
||||
Tag = { "ConstellationArtImage", group },
|
||||
GUI = {
|
||||
Name = name .. ' Image',
|
||||
Path = '/Milky Way/' .. guiPath
|
||||
}
|
||||
}
|
||||
table.insert(genConstellations, aconstellation);
|
||||
|
||||
else
|
||||
notFirstLine = true
|
||||
end
|
||||
end
|
||||
return genConstellations
|
||||
end
|
||||
|
||||
asset.export('createConstellations', createConstellations)
|
||||
Submodule ext/ghoul updated: a634fc1515...19f324db68
@@ -36,6 +36,8 @@
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyLazyLoading = "LazyLoading";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo TextureInfo = {
|
||||
"Texture",
|
||||
"Texture",
|
||||
@@ -70,6 +72,15 @@ documentation::Documentation RenderablePlaneImageLocal::Documentation() {
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
RenderableTypeInfo.description
|
||||
},
|
||||
{
|
||||
KeyLazyLoading,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If this value is set to 'true', the image for this plane will not be "
|
||||
"loaded at startup but rather when image is shown for the first time. "
|
||||
"Additionally, if the plane is hidden, the image will automatically be "
|
||||
"unloaded"
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -116,16 +127,34 @@ RenderablePlaneImageLocal::RenderablePlaneImageLocal(const ghoul::Dictionary& di
|
||||
else {
|
||||
setRenderBin(Renderable::RenderBin::Opaque);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyLazyLoading)) {
|
||||
_isLoadingLazily = dictionary.value<bool>(KeyLazyLoading);
|
||||
|
||||
if (_isLoadingLazily) {
|
||||
_enabled.onChange([this]() {
|
||||
if (!_enabled) {
|
||||
BaseModule::TextureManager.release(_texture);
|
||||
_texture = nullptr;
|
||||
}
|
||||
if (_enabled) {
|
||||
_textureIsDirty = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderablePlaneImageLocal::isReady() const {
|
||||
return RenderablePlane::isReady() && (_texture != nullptr);
|
||||
return RenderablePlane::isReady();
|
||||
}
|
||||
|
||||
void RenderablePlaneImageLocal::initializeGL() {
|
||||
RenderablePlane::initializeGL();
|
||||
|
||||
loadTexture();
|
||||
if (!_isLoadingLazily) {
|
||||
loadTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePlaneImageLocal::deinitializeGL() {
|
||||
@@ -165,8 +194,8 @@ void RenderablePlaneImageLocal::loadTexture() {
|
||||
fmt::format("Loaded texture from '{}'", absPath(path))
|
||||
);
|
||||
texture->uploadTexture();
|
||||
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
||||
texture->purgeFromRAM();
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ private:
|
||||
ghoul::opengl::Texture* _texture = nullptr;
|
||||
std::unique_ptr<ghoul::filesystem::File> _textureFile;
|
||||
|
||||
bool _isLoadingLazily = false;
|
||||
bool _textureIsDirty = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -133,10 +133,8 @@ void RenderablePlaneImageOnline::update(const UpdateData&) {
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
texture->uploadTexture();
|
||||
|
||||
// Textures of planets looks much smoother with AnisotropicMipMap rather
|
||||
// than linear
|
||||
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
||||
texture->purgeFromRAM();
|
||||
|
||||
_texture = std::move(texture);
|
||||
_textureIsDirty = false;
|
||||
|
||||
Reference in New Issue
Block a user