Files
OpenSpace/modules/multiresvolume/rendering/renderablemultiresvolume.cpp
2018-07-05 14:40:54 -04:00

770 lines
28 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/multiresvolume/rendering/renderablemultiresvolume.h>
#include <openspace/engine/openspaceengine.h>
#include <modules/kameleon/include/kameleonwrapper.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/raycastermanager.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/glm.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/opengl/framebufferobject.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/opengl/texture.h>
#include <modules/multiresvolume/rendering/tsp.h>
#include <modules/multiresvolume/rendering/atlasmanager.h>
#include <modules/multiresvolume/rendering/shenbrickselector.h>
#include <modules/multiresvolume/rendering/tfbrickselector.h>
#include <modules/multiresvolume/rendering/simpletfbrickselector.h>
#include <modules/multiresvolume/rendering/localtfbrickselector.h>
#include <modules/multiresvolume/rendering/histogrammanager.h>
#include <modules/multiresvolume/rendering/errorhistogrammanager.h>
#include <modules/multiresvolume/rendering/localerrorhistogrammanager.h>
#include <openspace/util/time.h>
#include <openspace/util/spicemanager.h>
#include <algorithm>
#include <iterator>
#include <fstream>
#include <algorithm>
#include <chrono>
namespace {
constexpr const char* _loggerCat = "RenderableMultiresVolume";
constexpr const char* KeyDataSource = "Source";
constexpr const char* KeyErrorHistogramsSource = "ErrorHistogramsSource";
constexpr const char* KeyHints = "Hints";
constexpr const char* KeyTransferFunction = "TransferFunction";
constexpr const char* KeyVolumeName = "VolumeName";
constexpr const char* KeyBrickSelector = "BrickSelector";
constexpr const char* KeyStartTime = "StartTime";
constexpr const char* KeyEndTime = "EndTime";
constexpr const char* GlslHelpersPath =
"${MODULES}/multiresvolume/shaders/helpers_fs.glsl";
constexpr const char* GlslHelperPath =
"${MODULES}/multiresvolume/shaders/helper.glsl";
constexpr const char* GlslHeaderPath =
"${MODULES}/multiresvolume/shaders/header.glsl";
constexpr openspace::properties::Property::PropertyInfo StepSizeCoefficientInfo = {
"StepSizeCoefficient",
"Stepsize Coefficient",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo CurrentTimeInfo = {
"CurrentTime",
"Current Time",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo MemoryBudgetInfo = {
"MemoryBudget",
"Memory Budget",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo StreamingBudgetInfo = {
"StreamingBudget",
"Streaming Budget",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo UseGlobalTimeInfo = {
"UseGlobalTime",
"Global Time",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo LoopInfo = {
"Loop",
"Loop",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo SelectorNameInfo = {
"Selector",
"Brick Selector",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo StatsToFileInfo = {
"PrintStats",
"Print Stats",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo StatsToFileNameInfo = {
"PrintStatsFileName",
"Stats Filename",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo ScalingExponentInfo = {
"ScalingExponent",
"Scaling Exponent",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo ScalingInfo = {
"Scaling",
"Scaling",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo TranslationInfo = {
"Translation",
"Translation",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo RotationInfo = {
"Rotation",
"Euler rotation",
"" // @TODO Missing documentation
};
} // namespace
namespace openspace {
RenderableMultiresVolume::RenderableMultiresVolume (const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _useGlobalTime(UseGlobalTimeInfo, false)
, _loop(LoopInfo, false)
, _currentTime(CurrentTimeInfo, 0, 0, 0)
, _memoryBudget(MemoryBudgetInfo, 0, 0, 0)
, _streamingBudget(StreamingBudgetInfo, 0, 0, 0)
, _stepSizeCoefficient(StepSizeCoefficientInfo, 1.f, 0.01f, 10.f)
, _selectorName(SelectorNameInfo)
, _statsToFile(StatsToFileInfo, false)
, _statsToFileName(StatsToFileNameInfo)
, _scalingExponent(ScalingExponentInfo, 1, -10, 20)
, _translation(TranslationInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(10.f))
, _rotation(RotationInfo, glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f), glm::vec3(6.28f))
, _scaling(ScalingInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(10.f))
{
std::string name;
_filename = "";
bool success = dictionary.getValue(KeyDataSource, _filename);
if (!success) {
LERROR(fmt::format(
"Node '{}' did not contain a valid '{}'",
name,
KeyDataSource
));
return;
}
_filename = absPath(_filename);
if (_filename == "") {
return;
}
_errorHistogramsPath = "";
if (dictionary.getValue(KeyErrorHistogramsSource, _errorHistogramsPath)) {
_errorHistogramsPath = absPath(_errorHistogramsPath);
}
float scalingExponent, stepSizeCoefficient;
glm::vec3 scaling, translation, rotation;
if (dictionary.getValue("ScalingExponent", scalingExponent)) {
_scalingExponent = static_cast<int>(scalingExponent);
}
if (dictionary.getValue("Scaling", scaling)) {
_scaling = scaling;
}
if (dictionary.getValue("Translation", translation)) {
_translation = translation;
}
if (dictionary.getValue("Rotation", rotation)) {
_rotation = rotation;
}
if (dictionary.getValue("StepSizeCoefficient", stepSizeCoefficient)) {
_stepSizeCoefficient = stepSizeCoefficient;
}
std::string startTimeString, endTimeString;
bool hasTimeData = true;
hasTimeData &= dictionary.getValue(KeyStartTime, startTimeString);
hasTimeData &= dictionary.getValue(KeyEndTime, endTimeString);
if (hasTimeData) {
_startTime = SpiceManager::ref().ephemerisTimeFromDate(startTimeString);
_endTime = SpiceManager::ref().ephemerisTimeFromDate(endTimeString);
}
if (hasTimeData) {
_loop = false;
} else {
_loop = true;
LWARNING(fmt::format(
"Node '{}' does not provide valid time information. Viewing one image per "
"frame.",
name
));
}
_transferFunction = nullptr;
_transferFunctionPath = "";
success = dictionary.getValue(KeyTransferFunction, _transferFunctionPath);
if (!success) {
LERROR(fmt::format(
"Node '{}' did not contain a valid '{}'",
name,
KeyTransferFunction
));
return;
}
_transferFunctionPath = absPath(_transferFunctionPath);
_transferFunction = std::make_shared<TransferFunction>(_transferFunctionPath);
//_pscOffset = psc(glm::vec4(0.0));
//_boxScaling = glm::vec3(1.0);
/*if (dictionary.hasKey(KeyBoxScaling)) {
glm::vec4 scalingVec4(_boxScaling, _w);
success = dictionary.getValue(KeyBoxScaling, scalingVec4);
if (success) {
_boxScaling = scalingVec4.xyz;
_w = scalingVec4.w;
}
else {
success = dictionary.getValue(KeyBoxScaling, _boxScaling);
if (!success) {
LERROR("Node '" << name << "' did not contain a valid '" <<
KeyBoxScaling << "'");
return;
}
}
}*/
//setBoundingSphere(PowerScaledScalar::CreatePSS(glm::length(_boxScaling)*pow(10,_w)));
_tsp = std::make_shared<TSP>(_filename);
_atlasManager = std::make_shared<AtlasManager>(_tsp.get());
_selectorName = "tf";
std::string brickSelectorType;
if (dictionary.hasKey(KeyBrickSelector)) {
success = dictionary.getValue(KeyBrickSelector, brickSelectorType);
if (success) {
_selectorName = brickSelectorType;
}
}
std::string selectorName = _selectorName;
if (selectorName == "simple") {
_selector = Selector::SIMPLE;
} else if (selectorName == "local") {
_selector = Selector::LOCAL;
} else {
_selector = Selector::TF;
}
addProperty(_selectorName);
_selectorName.onChange([&]() {
Selector s;
std::string newSelectorName = _selectorName;
if (newSelectorName == "simple") {
s = Selector::SIMPLE;
} else if (newSelectorName == "local") {
s = Selector::LOCAL;
} else if (newSelectorName == "tf") {
s = Selector::TF;
} else {
return;
}
setSelectorType(s);
});
addProperty(_stepSizeCoefficient);
addProperty(_useGlobalTime);
addProperty(_loop);
addProperty(_statsToFile);
addProperty(_statsToFileName);
addProperty(_scaling);
addProperty(_scalingExponent);
addProperty(_translation);
addProperty(_rotation);
//_brickSelector = new ShenBrickSelector(_tsp, -1, -1);
}
RenderableMultiresVolume::~RenderableMultiresVolume() {
//OsEng.renderEngine()->aBuffer()->removeVolume(this);
if (_tfBrickSelector)
delete _tfBrickSelector;
if (_simpleTfBrickSelector)
delete _simpleTfBrickSelector;
if (_localTfBrickSelector)
delete _localTfBrickSelector;
if (_errorHistogramManager)
delete _errorHistogramManager;
if (_histogramManager)
delete _histogramManager;
if (_localErrorHistogramManager)
delete _localErrorHistogramManager;
}
bool RenderableMultiresVolume::setSelectorType(Selector selector) {
_selector = selector;
switch (_selector) {
case Selector::TF:
if (!_tfBrickSelector) {
TfBrickSelector* tbs;
_errorHistogramManager = new ErrorHistogramManager(_tsp.get());
_tfBrickSelector = tbs = new TfBrickSelector(
_tsp.get(),
_errorHistogramManager,
_transferFunction.get(),
_memoryBudget,
_streamingBudget
);
_transferFunction->setCallback([tbs](const TransferFunction& /*tf*/) {
tbs->calculateBrickErrors();
});
if (initializeSelector()) {
tbs->calculateBrickErrors();
return true;
}
}
break;
case Selector::SIMPLE:
if (!_simpleTfBrickSelector) {
SimpleTfBrickSelector *stbs;
_histogramManager = new HistogramManager();
_simpleTfBrickSelector = stbs = new SimpleTfBrickSelector(
_tsp.get(),
_histogramManager,
_transferFunction.get(),
_memoryBudget,
_streamingBudget
);
_transferFunction->setCallback([stbs](const TransferFunction& /*tf*/) {
stbs->calculateBrickImportances();
});
if (initializeSelector()) {
stbs->calculateBrickImportances();
return true;
}
}
break;
case Selector::LOCAL:
if (!_localTfBrickSelector) {
LocalTfBrickSelector* ltbs;
_localErrorHistogramManager = new LocalErrorHistogramManager(_tsp.get());
_localTfBrickSelector = ltbs = new LocalTfBrickSelector(
_tsp.get(),
_localErrorHistogramManager,
_transferFunction.get(),
_memoryBudget,
_streamingBudget
);
_transferFunction->setCallback([ltbs](const TransferFunction& /*tf*/) {
ltbs->calculateBrickErrors();
});
if (initializeSelector()) {
ltbs->calculateBrickErrors();
return true;
}
}
break;
}
return false;
}
void RenderableMultiresVolume::initializeGL() {
bool success = _tsp && _tsp->load();
unsigned int maxNumBricks = _tsp->header().xNumBricks_ * _tsp->header().yNumBricks_ * _tsp->header().zNumBricks_;
unsigned int maxInitialBudget = 2048;
int initialBudget = std::min(maxInitialBudget, maxNumBricks);
_currentTime = properties::IntProperty(
CurrentTimeInfo,
0,
0,
_tsp->header().numTimesteps_ - 1
);
_memoryBudget = properties::IntProperty(
MemoryBudgetInfo,
initialBudget,
0,
maxNumBricks
);
_streamingBudget = properties::IntProperty(
StreamingBudgetInfo,
initialBudget,
0,
maxNumBricks
);
addProperty(_currentTime);
addProperty(_memoryBudget);
addProperty(_streamingBudget);
if (success) {
_brickIndices.resize(maxNumBricks, 0);
success &= setSelectorType(_selector);
}
success &= _atlasManager && _atlasManager->initialize();
_transferFunction->update();
success &= isReady();
_raycaster = std::make_unique<MultiresVolumeRaycaster>(_tsp, _atlasManager, _transferFunction);
_raycaster->initialize();
OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get());
std::function<void(bool)> onChange = [&](bool enabled) {
if (enabled) {
OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get());
}
else {
OsEng.renderEngine().raycasterManager().detachRaycaster(*_raycaster.get());
}
};
onEnabledChange(onChange);
if (!success) {
throw ghoul::RuntimeError("Error during initialization");
}
}
void RenderableMultiresVolume::deinitializeGL() {
_tsp = nullptr;
_transferFunction = nullptr;
}
bool RenderableMultiresVolume::isReady() const {
return true;
}
bool RenderableMultiresVolume::initializeSelector() {
int nHistograms = 50;
bool success = true;
switch (_selector) {
case Selector::TF:
if (_errorHistogramManager) {
std::stringstream cacheName;
ghoul::filesystem::File f = _filename;
cacheName << f.baseName() << "_" << nHistograms << "_errorHistograms";
std::string cacheFilename;
cacheFilename = FileSys.cacheManager()->cachedFilename(
cacheName.str(), "", ghoul::filesystem::CacheManager::Persistent::Yes);
std::ifstream cacheFile(cacheFilename, std::ios::in | std::ios::binary);
std::string errorHistogramsPath = _errorHistogramsPath;
if (cacheFile.is_open()) {
// Read histograms from cache.
cacheFile.close();
LINFO(fmt::format(
"Loading histograms from cache: {}",
cacheFilename
));
success &= _errorHistogramManager->loadFromFile(cacheFilename);
} else if (_errorHistogramsPath != "") {
// Read histograms from scene data.
LINFO(fmt::format(
"Loading histograms from scene data: {}",
_errorHistogramsPath
));
success &= _errorHistogramManager->loadFromFile(_errorHistogramsPath);
} else {
// Build histograms from tsp file.
LWARNING(fmt::format("Failed to open {}", cacheFilename));
success &= _errorHistogramManager->buildHistograms(nHistograms);
if (success) {
LINFO(fmt::format("Writing cache to {}", cacheFilename));
_errorHistogramManager->saveToFile(cacheFilename);
}
}
success &= _tfBrickSelector && _tfBrickSelector->initialize();
}
break;
case Selector::SIMPLE:
if (_histogramManager) {
std::stringstream cacheName;
ghoul::filesystem::File f = _filename;
cacheName << f.baseName() << "_" << nHistograms << "_histograms";
std::string cacheFilename;
cacheFilename = FileSys.cacheManager()->cachedFilename(
cacheName.str(), "", ghoul::filesystem::CacheManager::Persistent::Yes);
std::ifstream cacheFile(cacheFilename, std::ios::in | std::ios::binary);
if (cacheFile.is_open()) {
// Read histograms from cache.
cacheFile.close();
LINFO(fmt::format("Loading histograms from {}", cacheFilename));
success &= _histogramManager->loadFromFile(cacheFilename);
} else {
// Build histograms from tsp file.
LWARNING(fmt::format("Failed to open '{}'", cacheFilename));
success &= _histogramManager->buildHistograms(
_tsp.get(),
nHistograms
);
if (success) {
LINFO(fmt::format("Writing cache to {}", cacheFilename));
_histogramManager->saveToFile(cacheFilename);
}
}
success &= _simpleTfBrickSelector && _simpleTfBrickSelector->initialize();
}
break;
case Selector::LOCAL:
if (_localErrorHistogramManager) {
std::stringstream cacheName;
ghoul::filesystem::File f = _filename;
cacheName << f.baseName() << "_" << nHistograms << "_localErrorHistograms";
std::string cacheFilename;
cacheFilename = FileSys.cacheManager()->cachedFilename(
cacheName.str(), "", ghoul::filesystem::CacheManager::Persistent::Yes);
std::ifstream cacheFile(cacheFilename, std::ios::in | std::ios::binary);
if (cacheFile.is_open()) {
// Read histograms from cache.
cacheFile.close();
LINFO(fmt::format("Loading histograms from {}", cacheFilename));
success &= _localErrorHistogramManager->loadFromFile(cacheFilename);
} else {
// Build histograms from tsp file.
LWARNING(fmt::format("Failed to open {}", cacheFilename));
success &= _localErrorHistogramManager->buildHistograms(nHistograms);
if (success) {
LINFO(fmt::format("Writing cache to {}", cacheFilename));
_localErrorHistogramManager->saveToFile(cacheFilename);
}
}
success &= _localTfBrickSelector && _localTfBrickSelector->initialize();
}
break;
}
return success;
}
/*
void RenderableMultiresVolume::preResolve(ghoul::opengl::ProgramObject* program) {
RenderableVolume::preResolve(program);
std::stringstream ss;
ss << "opacity_" << getId();
program->setUniform(ss.str(), visible ? 1.0f : 0.0f);
ss.str(std::string());
ss << "stepSizeCoefficient_" << getId();
program->setUniform(ss.str(), _stepSizeCoefficient);
ss.str(std::string());
ss << "transferFunction_" << getId();
program->setUniform(ss.str(), getTextureUnit(_transferFunction->texture()));
ss.str(std::string());
ss << "textureAtlas_" << getId();
program->setUniform(ss.str(), getTextureUnit(_atlasManager->textureAtlas()));
ss.str(std::string());
ss << "atlasMapBlock_" << getId();
program->setSsboBinding(ss.str(), getSsboBinding(_atlasManager->atlasMapBuffer()));
ss.str(std::string());
ss << "gridType_" << getId();
program->setUniform(ss.str(), static_cast<int>(_tsp->header().gridType_));
ss.str(std::string());
ss << "maxNumBricksPerAxis_" << getId();
program->setUniform(ss.str(), static_cast<unsigned int>(_tsp->header().xNumBricks_));
ss.str(std::string());
ss << "paddedBrickDim_" << getId();
program->setUniform(ss.str(), static_cast<unsigned int>(_tsp->paddedBrickDim()));
ss.str(std::string());
ss << "atlasSize_" << getId();
glm::size3_t size = _atlasManager->textureSize();
glm::ivec3 atlasSize(size.x, size.y, size.z);
program->setUniform(ss.str(), atlasSize);
_timestep++;
}
*/
/*
std::vector<ghoul::opengl::Texture*> RenderableMultiresVolume::getTextures() {
std::vector<ghoul::opengl::Texture*> textures{_transferFunction->texture(), _atlasManager->textureAtlas()};
return textures;
}
std::vector<unsigned int> RenderableMultiresVolume::getBuffers() {
std::vector<unsigned int> buffers{_atlasManager->atlasMapBuffer()};
return buffers;
}*/
void RenderableMultiresVolume::update(const UpdateData& data) {
_timestep++;
_time = data.time.j2000Seconds();
if (_gatheringStats) {
std::chrono::system_clock::time_point frameEnd = std::chrono::system_clock::now();
std::chrono::duration<double> frameDuration = frameEnd - _frameStart;
// Make sure that the directory exists
ghoul::filesystem::File file(_statsFileName);
ghoul::filesystem::Directory directory(file.directoryName());
FileSys.createDirectory(directory, ghoul::filesystem::FileSystem::Recursive::Yes);
std::ofstream ofs(_statsFileName, std::ofstream::out);
ofs << frameDuration.count() << " "
<< _selectionDuration.count() << " "
<< _uploadDuration.count() << " "
<< _nUsedBricks << " "
<< _nStreamedBricks << " "
<< _nDiskReads;
ofs.close();
_gatheringStats = false;
}
if (_statsToFile) {
// Start frame timer
_frameStart = std::chrono::system_clock::now();
_statsFileName = _statsToFileName;
_gatheringStats = true;
_statsToFile = false;
}
int numTimesteps = _tsp->header().numTimesteps_;
int currentTimestep;
bool visible = true;
if (_loop) {
currentTimestep = _timestep % numTimesteps;
}
else if (_useGlobalTime) {
double t = (_time - _startTime) / (_endTime - _startTime);
currentTimestep = static_cast<int>(t * numTimesteps);
visible = currentTimestep >= 0 && currentTimestep < numTimesteps;
}
else {
currentTimestep = _currentTime;
}
if (visible) {
std::chrono::system_clock::time_point selectionStart;
if (_gatheringStats) {
selectionStart = std::chrono::system_clock::now();
}
switch (_selector) {
case Selector::TF:
if (_tfBrickSelector) {
_tfBrickSelector->setMemoryBudget(_memoryBudget);
_tfBrickSelector->setStreamingBudget(_streamingBudget);
_tfBrickSelector->selectBricks(currentTimestep, _brickIndices);
}
break;
case Selector::SIMPLE:
if (_simpleTfBrickSelector) {
_simpleTfBrickSelector->setMemoryBudget(_memoryBudget);
_simpleTfBrickSelector->setStreamingBudget(_streamingBudget);
_simpleTfBrickSelector->selectBricks(currentTimestep, _brickIndices);
}
break;
case Selector::LOCAL:
if (_localTfBrickSelector) {
_localTfBrickSelector->setMemoryBudget(_memoryBudget);
_localTfBrickSelector->setStreamingBudget(_streamingBudget);
_localTfBrickSelector->selectBricks(currentTimestep, _brickIndices);
}
break;
}
std::chrono::system_clock::time_point uploadStart;
if (_gatheringStats) {
std::chrono::system_clock::time_point selectionEnd = std::chrono::system_clock::now();
_selectionDuration = selectionEnd - selectionStart;
uploadStart = selectionEnd;
}
_atlasManager->updateAtlas(AtlasManager::EVEN, _brickIndices);
if (_gatheringStats) {
std::chrono::system_clock::time_point uploadEnd = std::chrono::system_clock::now();
_uploadDuration = uploadEnd - uploadStart;
_nDiskReads = _atlasManager->getNumDiskReads();
_nUsedBricks = _atlasManager->getNumUsedBricks();
_nStreamedBricks = _atlasManager->getNumStreamedBricks();
}
}
if (_raycaster) {
glm::mat4 transform = glm::translate(glm::mat4(1.0), static_cast<glm::vec3>(_translation) * std::pow(10.0f, static_cast<float>(_scalingExponent)));
glm::vec3 eulerRotation = static_cast<glm::vec3>(_rotation);
transform = glm::rotate(transform, eulerRotation.x, glm::vec3(1, 0, 0));
transform = glm::rotate(transform, eulerRotation.y, glm::vec3(0, 1, 0));
transform = glm::rotate(transform, eulerRotation.z, glm::vec3(0, 0, 1));
transform = glm::scale(transform, static_cast<glm::vec3>(_scaling) * std::pow(10.0f, static_cast<float>(_scalingExponent)));
_raycaster->setStepSizeCoefficient(_stepSizeCoefficient);
_raycaster->setModelTransform(transform);
//_raycaster->setTime(data.time);
}
}
void RenderableMultiresVolume::render(const RenderData& data, RendererTasks& tasks) {
RaycasterTask task{ _raycaster.get(), data };
tasks.raycasterTasks.push_back(task);
}
} // namespace openspace