mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 11:09:37 -06:00
Work on volume generation and rendering
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
local fn =
|
||||
"return function (x, y, z) " ..
|
||||
" if math.sqrt(x^2 + y^2 + z^2) < 0.4 then " ..
|
||||
" return 0.8 " ..
|
||||
" end " ..
|
||||
" return 0.0 " ..
|
||||
"end"
|
||||
|
||||
return {{
|
||||
Type = "GenerateRawVolumeTask",
|
||||
Dimensions = {32, 32, 32},
|
||||
LowerDomainBound = {-0.5, -0.5, -0.5},
|
||||
UpperDomainBound = {0.5, 0.5, 0.5},
|
||||
ValueFunction = "return function (x, y, z) return math.sqrt((x + 0.5)^2 + (y + 0.5)^2 + (z + 0.5)^2) end",
|
||||
ValueFunction = fn,
|
||||
Time = "2018-05-04T00:00:00",
|
||||
RawVolumeOutput = "${DATA}/assets/examples/generatedvolume.raw",
|
||||
DictionaryOutput = "${DATA}/assets/examples/generatedvolume.dictionary"
|
||||
RawVolumeOutput = "${DATA}/assets/examples/generatedvolume/generatedvolume.rawvolume",
|
||||
DictionaryOutput = "${DATA}/assets/examples/generatedvolume/generatedvolume.dictionary"
|
||||
}}
|
||||
@@ -24,18 +24,21 @@
|
||||
|
||||
#include <modules/toyvolume/rendering/toyvolumeraycaster.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <sstream>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <openspace/util/powerscaledcoordinate.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
const char* GlslRaycastPath = "${MODULES}/toyvolume/shaders/raycast.glsl";
|
||||
const char* GlslBoundsVsPath = "${MODULES}/toyvolume/shaders/boundsvs.glsl";
|
||||
const char* GlslBoundsFsPath = "${MODULES}/toyvolume/shaders/boundsfs.glsl";
|
||||
const char* GlslRaycastPath = "${MODULE_TOYVOLUME}/shaders/raycast.glsl";
|
||||
const char* GlslBoundsVsPath = "${MODULE_TOYVOLUME}/shaders/boundsvs.glsl";
|
||||
const char* GlslBoundsFsPath = "${MODULE_TOYVOLUME}/shaders/boundsfs.glsl";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -125,15 +128,15 @@ bool ToyVolumeRaycaster::cameraIsInside(const RenderData& data,
|
||||
}
|
||||
|
||||
std::string ToyVolumeRaycaster::getBoundsVsPath() const {
|
||||
return GlslBoundsVsPath;
|
||||
return absPath(GlslBoundsVsPath);
|
||||
}
|
||||
|
||||
std::string ToyVolumeRaycaster::getBoundsFsPath() const {
|
||||
return GlslBoundsFsPath;
|
||||
return absPath(GlslBoundsFsPath);
|
||||
}
|
||||
|
||||
std::string ToyVolumeRaycaster::getRaycastPath() const {
|
||||
return GlslRaycastPath;
|
||||
return absPath(GlslRaycastPath);
|
||||
}
|
||||
|
||||
std::string ToyVolumeRaycaster::getHelperPath() const {
|
||||
|
||||
@@ -27,11 +27,9 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/envelope.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolume.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolume.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumemetadata.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumereader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumereader.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumewriter.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumewriter.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/textureslicevolumereader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/textureslicevolumereader.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/transferfunction.h
|
||||
@@ -54,6 +52,7 @@ source_group("Header Files" FILES ${HEADER_FILES})
|
||||
set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/envelope.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolume.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumemetadata.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumereader.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rawvolumewriter.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/textureslicevolumereader.inl
|
||||
|
||||
182
modules/volume/rawvolumemetadata.cpp
Normal file
182
modules/volume/rawvolumemetadata.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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/volume/rawvolumemetadata.h>
|
||||
|
||||
#include <openspace/properties/vectorproperty.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace {
|
||||
const constexpr char* KeyDimensions = "Dimensions";
|
||||
const constexpr char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
const constexpr char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
|
||||
const constexpr char* KeyMinValue = "MinValue";
|
||||
const constexpr char* KeyMaxValue = "MaxValue";
|
||||
|
||||
const constexpr char* KeyTime = "Time";
|
||||
const constexpr char* KeyDomainUnit = "DomainUnit";
|
||||
const constexpr char* KeyValueUnit = "ValueUnit";
|
||||
|
||||
const constexpr char* KeyGridType = "GridType";
|
||||
}
|
||||
|
||||
namespace openspace::volume {
|
||||
|
||||
RawVolumeMetadata RawVolumeMetadata::CreateFromDictionary(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RawVolumeMetadata"
|
||||
);
|
||||
|
||||
RawVolumeMetadata metadata;
|
||||
metadata.dimensions = dictionary.value<glm::vec3>(KeyDimensions);
|
||||
|
||||
metadata.hasDomainBounds = dictionary.hasValue<glm::vec3>(KeyLowerDomainBound) &&
|
||||
dictionary.hasValue<glm::vec3>(KeyUpperDomainBound);
|
||||
|
||||
if (metadata.hasDomainBounds) {
|
||||
metadata.lowerDomainBound = dictionary.value<glm::vec3>(KeyLowerDomainBound);
|
||||
metadata.upperDomainBound = dictionary.value<glm::vec3>(KeyUpperDomainBound);
|
||||
}
|
||||
metadata.hasDomainUnit = dictionary.hasValue<float>(KeyDomainUnit);
|
||||
if (metadata.hasDomainUnit) {
|
||||
metadata.domainUnit = dictionary.value<std::string>(KeyDomainUnit);
|
||||
}
|
||||
|
||||
metadata.hasValueRange = dictionary.hasValue<float>(KeyMinValue) &&
|
||||
dictionary.hasValue<float>(KeyMaxValue);
|
||||
|
||||
if (metadata.hasValueRange) {
|
||||
metadata.minValue = dictionary.value<float>(KeyMinValue);
|
||||
metadata.maxValue = dictionary.value<float>(KeyMaxValue);
|
||||
}
|
||||
metadata.hasValueUnit = dictionary.hasValue<float>(KeyValueUnit);
|
||||
if (metadata.hasValueUnit) {
|
||||
metadata.valueUnit = dictionary.value<std::string>(KeyValueUnit);
|
||||
}
|
||||
|
||||
metadata.hasTime = dictionary.hasValue<std::string>(KeyTime);
|
||||
if (metadata.hasTime) {
|
||||
std::string timeString = dictionary.value<std::string>(KeyTime);
|
||||
metadata.time = Time::convertTime(timeString);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
ghoul::Dictionary RawVolumeMetadata::dictionary() {
|
||||
ghoul::Dictionary dict;
|
||||
dict.setValue<glm::vec3>(KeyDimensions, dimensions);
|
||||
dict.setValue<std::string>(KeyGridType, gridTypeToString(gridType));
|
||||
|
||||
if (hasDomainUnit) {
|
||||
dict.setValue<std::string>(KeyDomainUnit, domainUnit);
|
||||
}
|
||||
if (hasDomainBounds) {
|
||||
dict.setValue<glm::vec3>(KeyLowerDomainBound, lowerDomainBound);
|
||||
dict.setValue<glm::vec3>(KeyUpperDomainBound, upperDomainBound);
|
||||
}
|
||||
|
||||
if (hasValueRange) {
|
||||
dict.setValue<double>(KeyMinValue, static_cast<float>(minValue));
|
||||
dict.setValue<double>(KeyMaxValue, static_cast<float>(maxValue));
|
||||
}
|
||||
if (hasDomainUnit) {
|
||||
dict.setValue<std::string>(KeyValueUnit, valueUnit);
|
||||
}
|
||||
|
||||
if (hasTime) {
|
||||
std::string timeString = Time(time).ISO8601();
|
||||
// Do not include time offset in time string
|
||||
if (timeString.back() == 'Z') {
|
||||
timeString.pop_back();
|
||||
}
|
||||
dict.setValue<std::string>(KeyTime, timeString);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
documentation::Documentation RawVolumeMetadata::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RawVolumeMetadata",
|
||||
"volume_rawvolumemetadata",
|
||||
{
|
||||
{
|
||||
KeyDimensions,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::No,
|
||||
"Specifies the number of grid cells in each dimension",
|
||||
},
|
||||
{
|
||||
KeyDomainUnit,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the unit used to specity the domain",
|
||||
},
|
||||
{
|
||||
KeyLowerDomainBound,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::Yes,
|
||||
"Specifies the lower domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyUpperDomainBound,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::Yes,
|
||||
"Specifies the upper domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyTime,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z",
|
||||
},
|
||||
{
|
||||
KeyValueUnit,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the unit used to specity the value",
|
||||
},
|
||||
{
|
||||
KeyMinValue,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the minimum value stored in the volume"
|
||||
},
|
||||
{
|
||||
KeyMaxValue,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the maximum value stored in the volume"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace::volume
|
||||
62
modules/volume/rawvolumemetadata.h
Normal file
62
modules/volume/rawvolumemetadata.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_VOLUME___RAWVOLUMEMETADATA___H__
|
||||
#define __OPENSPACE_MODULE_VOLUME___RAWVOLUMEMETADATA___H__
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <modules/volume/volumegridtype.h>
|
||||
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
|
||||
namespace openspace::volume {
|
||||
|
||||
struct RawVolumeMetadata {
|
||||
static RawVolumeMetadata CreateFromDictionary(const ghoul::Dictionary& dictionary);
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
ghoul::Dictionary dictionary();
|
||||
|
||||
glm::uvec3 dimensions;
|
||||
VolumeGridType gridType;
|
||||
|
||||
bool hasTime;
|
||||
double time;
|
||||
|
||||
bool hasValueRange;
|
||||
float minValue;
|
||||
float maxValue;
|
||||
bool hasValueUnit;
|
||||
std::string valueUnit;
|
||||
|
||||
bool hasDomainBounds;
|
||||
glm::vec3 lowerDomainBound;
|
||||
glm::vec3 upperDomainBound;
|
||||
bool hasDomainUnit;
|
||||
std::string domainUnit;
|
||||
};
|
||||
|
||||
} // namespace openspace::volume
|
||||
|
||||
#endif // __OPENSPACE_MODULE_VOLUME___RAWVOLUMEMETADATA___H__
|
||||
@@ -86,6 +86,11 @@ std::unique_ptr<RawVolume<VoxelType>> RawVolumeReader<VoxelType>::read() {
|
||||
std::make_unique<RawVolume<VoxelType>>(dims);
|
||||
|
||||
std::ifstream file(_path, std::ios::binary);
|
||||
|
||||
if (file.fail()) {
|
||||
throw ghoul::FileNotFoundError("Volume file not found");
|
||||
}
|
||||
|
||||
char *buffer = reinterpret_cast<char*>(volume->data());
|
||||
size_t length = static_cast<size_t>(dims.x) *
|
||||
static_cast<size_t>(dims.y) *
|
||||
@@ -93,6 +98,11 @@ std::unique_ptr<RawVolume<VoxelType>> RawVolumeReader<VoxelType>::read() {
|
||||
sizeof(VoxelType);
|
||||
|
||||
file.read(buffer, length);
|
||||
|
||||
if (file.fail()) {
|
||||
throw ghoul::RuntimeError("Error reading volume file");
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,11 @@ void RawVolumeWriter<VoxelType>::write(const RawVolume<VoxelType>& volume) {
|
||||
size_t length = volume.nCells() * sizeof(VoxelType);
|
||||
|
||||
std::ofstream file(_path, std::ios::binary);
|
||||
|
||||
if (!file.good()) {
|
||||
throw ghoul::RuntimeError("Could not create file '" + _path + "'");
|
||||
}
|
||||
|
||||
file.write(buffer, length);
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ namespace openspace::volume {
|
||||
|
||||
BasicVolumeRaycaster::BasicVolumeRaycaster(
|
||||
std::shared_ptr<ghoul::opengl::Texture> volumeTexture,
|
||||
std::shared_ptr<TransferFunctionHandler> transferFunctionHandler,
|
||||
std::shared_ptr<openspace::TransferFunction> transferFunction,
|
||||
std::shared_ptr<VolumeClipPlanes> clipPlanes)
|
||||
: _volumeTexture(volumeTexture)
|
||||
, _transferFunctionHandler(transferFunctionHandler)
|
||||
, _transferFunction(transferFunction)
|
||||
, _clipPlanes(clipPlanes)
|
||||
, _boundingBox(glm::vec3(1.0))
|
||||
, _opacity(20.0)
|
||||
@@ -112,7 +112,7 @@ void BasicVolumeRaycaster::preRaycast(
|
||||
const RaycastData& data,
|
||||
ghoul::opengl::ProgramObject& program)
|
||||
{
|
||||
if (!_volumeTexture || !_transferFunctionHandler) {
|
||||
if (!_volumeTexture || !_transferFunction) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,9 +121,10 @@ void BasicVolumeRaycaster::preRaycast(
|
||||
|
||||
std::string id = std::to_string(data.id);
|
||||
|
||||
_transferFunction->update();
|
||||
_tfUnit = std::make_unique<ghoul::opengl::TextureUnit>();
|
||||
_tfUnit->activate();
|
||||
_transferFunctionHandler->getTexture().bind();
|
||||
_transferFunction->getTexture().bind();
|
||||
program.setUniform("transferFunction_" + id, _tfUnit->unitNumber());
|
||||
|
||||
_textureUnit = std::make_unique<ghoul::opengl::TextureUnit>();
|
||||
@@ -182,10 +183,10 @@ std::string BasicVolumeRaycaster::getHelperPath() const {
|
||||
}
|
||||
|
||||
|
||||
void BasicVolumeRaycaster::setTransferFunctionHandler(
|
||||
std::shared_ptr<TransferFunctionHandler> transferFunctionHandler)
|
||||
void BasicVolumeRaycaster::setTransferFunction(
|
||||
std::shared_ptr<openspace::TransferFunction> transferFunction)
|
||||
{
|
||||
_transferFunctionHandler = transferFunctionHandler;
|
||||
_transferFunction = transferFunction;
|
||||
}
|
||||
|
||||
void BasicVolumeRaycaster::setVolumeTexture(
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include <ghoul/opengl/texture.h>
|
||||
|
||||
#include <openspace/rendering/volumeraycaster.h>
|
||||
#include <openspace/rendering/transferfunction.h>
|
||||
#include <openspace/util/boxgeometry.h>
|
||||
#include <modules/volume/transferfunctionhandler.h>
|
||||
#include <modules/volume/rendering/volumeclipplanes.h>
|
||||
|
||||
#include <modules/volume/volumegridtype.h>
|
||||
@@ -56,7 +56,7 @@ class BasicVolumeRaycaster : public VolumeRaycaster {
|
||||
public:
|
||||
BasicVolumeRaycaster(
|
||||
std::shared_ptr<ghoul::opengl::Texture> texture,
|
||||
std::shared_ptr<TransferFunctionHandler> transferFunctionHandler,
|
||||
std::shared_ptr<openspace::TransferFunction> transferFunction,
|
||||
std::shared_ptr<VolumeClipPlanes> clipPlanes);
|
||||
virtual ~BasicVolumeRaycaster();
|
||||
void initialize();
|
||||
@@ -80,8 +80,8 @@ public:
|
||||
|
||||
void setVolumeTexture(std::shared_ptr<ghoul::opengl::Texture> texture);
|
||||
std::shared_ptr<ghoul::opengl::Texture> volumeTexture() const;
|
||||
void setTransferFunctionHandler(
|
||||
std::shared_ptr<TransferFunctionHandler> transferFunctionHandler);
|
||||
void setTransferFunction(
|
||||
std::shared_ptr<openspace::TransferFunction> transferFunction);
|
||||
|
||||
void setStepSize(float stepSize);
|
||||
float opacity() const;
|
||||
@@ -99,7 +99,7 @@ private:
|
||||
|
||||
std::shared_ptr<VolumeClipPlanes> _clipPlanes;
|
||||
std::shared_ptr<ghoul::opengl::Texture> _volumeTexture;
|
||||
std::shared_ptr<TransferFunctionHandler> _transferFunctionHandler;
|
||||
std::shared_ptr<openspace::TransferFunction> _transferFunction;
|
||||
BoxGeometry _boundingBox;
|
||||
VolumeGridType _gridType;
|
||||
glm::mat4 _modelTransform;
|
||||
|
||||
@@ -47,20 +47,14 @@ namespace {
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* KeyDimensions = "Dimensions";
|
||||
const char* KeyStepSize = "StepSize";
|
||||
const char* KeyTransferFunction = "TransferFunction";
|
||||
const char* KeySourceDirectory = "SourceDirectory";
|
||||
const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
|
||||
const char* KeyClipPlanes = "ClipPlanes";
|
||||
const char* KeySecondsBefore = "SecondsBefore";
|
||||
const char* KeySecondsAfter = "SecondsAfter";
|
||||
const char* KeyGridType = "GridType";
|
||||
const char* KeyMinValue = "MinValue";
|
||||
const char* KeyMaxValue = "MaxValue";
|
||||
const char* KeyTime = "Time";
|
||||
const char* KeyUnit = "VisUnit";
|
||||
|
||||
const float SecondsInOneDay = 60 * 60 * 24;
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo StepSizeInfo = {
|
||||
@@ -168,8 +162,6 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
, _jumpToTimestep(JumpToTimestepInfo, 0, 0, 256)
|
||||
, _currentTimestep(CurrentTimeStepInfo, 0, 0, 256)
|
||||
, _raycaster(nullptr)
|
||||
, _transferFunctionHandler(nullptr)
|
||||
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
@@ -179,8 +171,10 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
|
||||
_sourceDirectory = absPath(dictionary.value<std::string>(KeySourceDirectory));
|
||||
_transferFunctionPath = absPath(dictionary.value<std::string>(KeyTransferFunction));
|
||||
_transferFunctionHandler = std::make_shared<TransferFunctionHandler>(_transferFunctionPath);
|
||||
|
||||
_transferFunction = std::make_shared<openspace::TransferFunction>(
|
||||
_transferFunctionPath,
|
||||
[](const openspace::TransferFunction&) {}
|
||||
);
|
||||
|
||||
_gridType.addOptions({
|
||||
{ static_cast<int>(volume::VolumeGridType::Cartesian), "Cartesian grid" },
|
||||
@@ -203,12 +197,12 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
|
||||
_clipPlanes->setIdentifier("clipPlanes");
|
||||
_clipPlanes->setGuiName("Clip Planes");
|
||||
|
||||
if (dictionary.hasValue<std::string>(KeyGridType)) {
|
||||
/*if (dictionary.hasValue<std::string>(KeyGridType)) {
|
||||
VolumeGridType gridType = volume::parseGridType(
|
||||
dictionary.value<std::string>(KeyGridType)
|
||||
);
|
||||
_gridType = (gridType == VolumeGridType::Spherical) ? 1 : 0;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
RenderableTimeVaryingVolume::~RenderableTimeVaryingVolume() {}
|
||||
@@ -233,9 +227,6 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
if (extension == "dictionary") {
|
||||
loadTimestepMetadata(path);
|
||||
}
|
||||
if (extension == "tf") {
|
||||
_transferFunctionHandler->setFilepath(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,11 +236,11 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
std::string path = FileSys.pathByAppendingComponent(
|
||||
_sourceDirectory, t.baseName
|
||||
) + ".rawvolume";
|
||||
RawVolumeReader<float> reader(path, t.dimensions);
|
||||
RawVolumeReader<float> reader(path, t.metadata.dimensions);
|
||||
t.rawVolume = reader.read();
|
||||
|
||||
float min = t.minValue;
|
||||
float diff = t.maxValue - t.minValue;
|
||||
float min = t.metadata.minValue;
|
||||
float diff = t.metadata.maxValue - t.metadata.minValue;
|
||||
float *data = t.rawVolume->data();
|
||||
for (size_t i = 0; i < t.rawVolume->nCells(); ++i) {
|
||||
data[i] = glm::clamp((data[i] - min) / diff, 0.0f, 1.0f);
|
||||
@@ -263,7 +254,7 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
// TODO: handle normalization properly for different timesteps + transfer function
|
||||
|
||||
t.texture = std::make_shared<ghoul::opengl::Texture>(
|
||||
t.dimensions,
|
||||
t.metadata.dimensions,
|
||||
ghoul::opengl::Texture::Format::Red,
|
||||
GL_RED,
|
||||
GL_FLOAT,
|
||||
@@ -278,10 +269,10 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
t.texture->uploadTexture();
|
||||
}
|
||||
|
||||
_transferFunctionHandler->initialize();
|
||||
//_transferFunction->initialize();
|
||||
_clipPlanes->initialize();
|
||||
|
||||
_raycaster = std::make_unique<volume::BasicVolumeRaycaster>(nullptr, _transferFunctionHandler, _clipPlanes);
|
||||
_raycaster = std::make_unique<volume::BasicVolumeRaycaster>(nullptr, _transferFunction, _clipPlanes);
|
||||
|
||||
_raycaster->initialize();
|
||||
OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get());
|
||||
@@ -312,7 +303,6 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
addProperty(_transferFunctionPath);
|
||||
addProperty(_sourceDirectory);
|
||||
addPropertySubOwner(_clipPlanes.get());
|
||||
addPropertySubOwner(_transferFunctionHandler.get());
|
||||
|
||||
addProperty(_triggerTimeJump);
|
||||
addProperty(_jumpToTimestep);
|
||||
@@ -335,35 +325,30 @@ void RenderableTimeVaryingVolume::initializeGL() {
|
||||
});
|
||||
|
||||
_transferFunctionPath.onChange([this] {
|
||||
_transferFunctionHandler =
|
||||
std::make_shared<TransferFunctionHandler>(_transferFunctionPath);
|
||||
_raycaster->setTransferFunctionHandler(_transferFunctionHandler);
|
||||
_transferFunction =
|
||||
std::make_shared<TransferFunction>(_transferFunctionPath);
|
||||
_raycaster->setTransferFunction(_transferFunction);
|
||||
});
|
||||
}
|
||||
|
||||
void RenderableTimeVaryingVolume::loadTimestepMetadata(const std::string& path) {
|
||||
ghoul::Dictionary dictionary = ghoul::lua::loadDictionaryFromFile(path);
|
||||
documentation::testSpecificationAndThrow(
|
||||
TimestepDocumentation(),
|
||||
dictionary,
|
||||
"TimeVaryingVolumeTimestep"
|
||||
);
|
||||
RawVolumeMetadata metadata;
|
||||
|
||||
try {
|
||||
ghoul::Dictionary dictionary = ghoul::lua::loadDictionaryFromFile(path);
|
||||
metadata = RawVolumeMetadata::CreateFromDictionary(dictionary);
|
||||
} catch (...) {
|
||||
return;
|
||||
}
|
||||
|
||||
Timestep t;
|
||||
t.metadata = metadata;
|
||||
t.baseName = ghoul::filesystem::File(path).baseName();
|
||||
t.dimensions = dictionary.value<glm::vec3>(KeyDimensions);
|
||||
t.lowerDomainBound = dictionary.value<glm::vec3>(KeyLowerDomainBound);
|
||||
t.upperDomainBound = dictionary.value<glm::vec3>(KeyUpperDomainBound);
|
||||
t.minValue = dictionary.value<float>(KeyMinValue);
|
||||
t.maxValue = dictionary.value<float>(KeyMaxValue);
|
||||
t.unit = dictionary.value<std::string>(KeyUnit);
|
||||
|
||||
std::string timeString = dictionary.value<std::string>(KeyTime);
|
||||
t.time = Time::convertTime(timeString);
|
||||
t.inRam = false;
|
||||
t.onGpu = false;
|
||||
|
||||
_volumeTimesteps[t.time] = std::move(t);
|
||||
_volumeTimesteps[t.metadata.time] = std::move(t);
|
||||
}
|
||||
|
||||
RenderableTimeVaryingVolume::Timestep* RenderableTimeVaryingVolume::currentTimestep() {
|
||||
@@ -377,14 +362,16 @@ RenderableTimeVaryingVolume::Timestep* RenderableTimeVaryingVolume::currentTimes
|
||||
if (currentTimestepIt == _volumeTimesteps.end()) {
|
||||
// No such timestep was found: show last timestep if it is within the time margin.
|
||||
Timestep* lastTimestep = &(_volumeTimesteps.rbegin()->second);
|
||||
double threshold = lastTimestep->time + static_cast<double>(_secondsAfter);
|
||||
double threshold = lastTimestep->metadata.time +
|
||||
static_cast<double>(_secondsAfter);
|
||||
return currentTime < threshold ? lastTimestep : nullptr;
|
||||
}
|
||||
|
||||
if (currentTimestepIt == _volumeTimesteps.begin()) {
|
||||
// No such timestep was found: show first timestep if it is within the time margin
|
||||
Timestep* firstTimestep = &(_volumeTimesteps.begin()->second);
|
||||
double threshold = firstTimestep->time - static_cast<double>(_secondsBefore);
|
||||
double threshold = firstTimestep->metadata.time -
|
||||
static_cast<double>(_secondsBefore);
|
||||
return currentTime >= threshold ? firstTimestep : nullptr;
|
||||
}
|
||||
|
||||
@@ -430,7 +417,7 @@ void RenderableTimeVaryingVolume::jumpToTimestep(int target) {
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
OsEng.timeManager().setTimeNextFrame(t->time);
|
||||
OsEng.timeManager().setTimeNextFrame(t->metadata.time);
|
||||
}
|
||||
|
||||
void RenderableTimeVaryingVolume::update(const UpdateData&) {
|
||||
@@ -439,9 +426,10 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
|
||||
_currentTimestep = timestepIndex(t);
|
||||
if (t && t->texture) {
|
||||
if (_raycaster->gridType() == volume::VolumeGridType::Cartesian) {
|
||||
glm::dvec3 scale = t->upperDomainBound - t->lowerDomainBound;
|
||||
glm::dvec3 scale = t->metadata.upperDomainBound -
|
||||
t->metadata.lowerDomainBound;
|
||||
glm::dvec3 translation =
|
||||
(t->lowerDomainBound + t->upperDomainBound) * 0.5f;
|
||||
(t->metadata.lowerDomainBound + t->metadata.upperDomainBound) * 0.5f;
|
||||
|
||||
glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), translation);
|
||||
glm::dmat4 scaleMatrix = glm::scale(glm::dmat4(1.0), scale);
|
||||
@@ -451,14 +439,16 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
|
||||
_raycaster->setModelTransform(
|
||||
glm::scale(
|
||||
glm::dmat4(1.0),
|
||||
glm::dvec3(t->upperDomainBound[0])
|
||||
glm::dvec3(t->metadata.upperDomainBound[0])
|
||||
)
|
||||
);
|
||||
}
|
||||
_raycaster->setVolumeTexture(t->texture);
|
||||
_transferFunctionHandler->setUnit(t->unit);
|
||||
_transferFunctionHandler->setMinAndMaxValue(t->minValue, t->maxValue);
|
||||
_transferFunctionHandler->setHistogramProperty(t->histogram);
|
||||
//_transferFunctionHandler->setUnit(t->metadata.valueUnit);
|
||||
//_transferFunctionHandler->setMinAndMaxValue(
|
||||
// t->metadata.minValue, t->metadata.maxValue);
|
||||
|
||||
//_transferFunctionHandler->setHistogramProperty(t->histogram);
|
||||
} else {
|
||||
_raycaster->setVolumeTexture(nullptr);
|
||||
}
|
||||
@@ -504,12 +494,6 @@ documentation::Documentation RenderableTimeVaryingVolume::Documentation() {
|
||||
Optional::No,
|
||||
"Specifies the transfer function file path"
|
||||
},
|
||||
{
|
||||
KeyGridType,
|
||||
new StringInListVerifier({"Cartesian", "Spherical"}),
|
||||
Optional::Yes,
|
||||
"Specifies the grid type"
|
||||
},
|
||||
{
|
||||
KeySecondsBefore,
|
||||
new DoubleVerifier,
|
||||
@@ -529,51 +513,5 @@ documentation::Documentation RenderableTimeVaryingVolume::Documentation() {
|
||||
}
|
||||
|
||||
|
||||
documentation::Documentation RenderableTimeVaryingVolume::TimestepDocumentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"TimevaryingVolumeTimestep",
|
||||
"volume_timevaryingvolumetimestep",
|
||||
{
|
||||
{
|
||||
KeyLowerDomainBound,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::No,
|
||||
"Specifies the lower domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyUpperDomainBound,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::No,
|
||||
"Specifies the upper domain bounds in the model coordinate system",
|
||||
},
|
||||
{
|
||||
KeyDimensions,
|
||||
new Vector3Verifier<float>,
|
||||
Optional::No,
|
||||
"Specifies the number of grid cells in each dimension",
|
||||
},
|
||||
{
|
||||
KeyTime,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z",
|
||||
},
|
||||
{
|
||||
KeyMinValue,
|
||||
new DoubleVerifier,
|
||||
Optional::No,
|
||||
"Specifies the minimum value stored in the volume"
|
||||
},
|
||||
{
|
||||
KeyMaxValue,
|
||||
new DoubleVerifier,
|
||||
Optional::No,
|
||||
"Specifies the maximum value stored in the volume"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace volume
|
||||
} // namespace openspace
|
||||
|
||||
@@ -28,16 +28,16 @@
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <modules/volume/rawvolume.h>
|
||||
#include <modules/volume/rawvolumemetadata.h>
|
||||
#include <modules/volume/rendering/basicvolumeraycaster.h>
|
||||
#include <modules/volume/rendering/volumeclipplanes.h>
|
||||
#include <modules/volume/transferfunctionhandler.h>
|
||||
|
||||
|
||||
#include <openspace/properties/vectorproperty.h>
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/util/boxgeometry.h>
|
||||
#include <openspace/util/histogram.h>
|
||||
#include <openspace/rendering/transferfunction.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
@@ -57,21 +57,14 @@ public:
|
||||
void update(const UpdateData& data) override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
static documentation::Documentation TimestepDocumentation();
|
||||
|
||||
private:
|
||||
struct Timestep {
|
||||
std::string baseName;
|
||||
double time;
|
||||
float minValue;
|
||||
float maxValue;
|
||||
glm::uvec3 dimensions;
|
||||
glm::vec3 lowerDomainBound;
|
||||
glm::vec3 upperDomainBound;
|
||||
std::string unit;
|
||||
bool inRam;
|
||||
bool onGpu;
|
||||
std::unique_ptr<RawVolume<float>> rawVolume;
|
||||
RawVolumeMetadata metadata;
|
||||
std::shared_ptr<RawVolume<float>> rawVolume;
|
||||
std::shared_ptr<ghoul::opengl::Texture> texture;
|
||||
std::shared_ptr<openspace::Histogram> histogram;
|
||||
};
|
||||
@@ -102,7 +95,7 @@ private:
|
||||
std::map<double, Timestep> _volumeTimesteps;
|
||||
std::unique_ptr<BasicVolumeRaycaster> _raycaster;
|
||||
|
||||
std::shared_ptr<TransferFunctionHandler> _transferFunctionHandler;
|
||||
std::shared_ptr<TransferFunction> _transferFunction;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ void sample#{id}(vec3 samplePos, vec3 dir, inout vec3 accumulatedColor,
|
||||
}
|
||||
|
||||
vec4 color = texture(transferFunction_#{id}, val);
|
||||
|
||||
vec3 backColor = color.rgb;
|
||||
vec3 backAlpha = color.aaa;
|
||||
|
||||
|
||||
@@ -25,17 +25,19 @@
|
||||
#include <modules/volume/tasks/generaterawvolumetask.h>
|
||||
|
||||
#include <modules/volume/rawvolume.h>
|
||||
#include <modules/volume/rawvolumemetadata.h>
|
||||
#include <modules/volume/rawvolumewriter.h>
|
||||
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
|
||||
#include <ghoul/misc/dictionaryjsonformatter.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <ghoul/lua/luastate.h>
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <ghoul/misc/defer.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@@ -48,8 +50,8 @@ namespace {
|
||||
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
|
||||
// constexpr const char* KeyMinValue = "MinValue";
|
||||
// constexpr const char* KeyMaxValue = "MaxValue";
|
||||
constexpr const char* KeyMinValue = "MinValue";
|
||||
constexpr const char* KeyMaxValue = "MaxValue";
|
||||
// constexpr const char* KeyVisUnit = "VisUnit";
|
||||
} // namespace
|
||||
|
||||
@@ -91,6 +93,15 @@ std::string GenerateRawVolumeTask::description() {
|
||||
}
|
||||
|
||||
void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
// Spice kernel is required for time conversions.
|
||||
// Todo: Make this dependency less hard coded.
|
||||
SpiceManager::KernelHandle kernel =
|
||||
SpiceManager::ref().loadKernel(absPath("${DATA}/assets/spice/naif0012.tls"));
|
||||
|
||||
defer {
|
||||
SpiceManager::ref().unloadKernel(kernel);
|
||||
};
|
||||
|
||||
volume::RawVolume<float> rawVolume(_dimensions);
|
||||
progressCallback(0.1f);
|
||||
|
||||
@@ -105,9 +116,13 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
|
||||
|
||||
glm::vec3 domainSize = _upperDomainBound - _lowerDomainBound;
|
||||
|
||||
|
||||
float minVal = std::numeric_limits<float>::max();
|
||||
float maxVal = std::numeric_limits<float>::min();
|
||||
|
||||
rawVolume.forEachVoxel([&](glm::uvec3 cell, float) {
|
||||
glm::vec3 coord = _lowerDomainBound +
|
||||
glm::vec3(cell) * glm::vec3(_dimensions) * domainSize;
|
||||
glm::vec3(cell) / glm::vec3(_dimensions) * domainSize;
|
||||
|
||||
ghoul::lua::verifyStackSize(state, 0);
|
||||
lua_rawgeti(state, LUA_REGISTRYINDEX, functionReference);
|
||||
@@ -125,6 +140,9 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
|
||||
float value = luaL_checknumber(state, 1);
|
||||
lua_pop(state, 1);
|
||||
rawVolume.set(cell, value);
|
||||
|
||||
minVal = std::min(minVal, value);
|
||||
maxVal = std::max(maxVal, value);
|
||||
});
|
||||
|
||||
luaL_unref(state, LUA_REGISTRYINDEX, functionReference);
|
||||
@@ -134,35 +152,24 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba
|
||||
|
||||
progressCallback(0.9f);
|
||||
|
||||
ghoul::Dictionary outputMetadata;
|
||||
|
||||
std::string time = _time;
|
||||
|
||||
// Do not include time offset in time string
|
||||
if (time.back() == 'Z') {
|
||||
time.pop_back();
|
||||
}
|
||||
|
||||
outputMetadata.setValue<std::string>(KeyTime, time);
|
||||
outputMetadata.setValue<glm::vec3>(KeyDimensions, _dimensions);
|
||||
outputMetadata.setValue<glm::vec3>(KeyLowerDomainBound, _lowerDomainBound);
|
||||
outputMetadata.setValue<glm::vec3>(KeyUpperDomainBound, _upperDomainBound);
|
||||
|
||||
/*outputMetadata.setValue<float>(
|
||||
KeyMinValue,
|
||||
static_cast<float>(reader.minValue(_variable))
|
||||
);
|
||||
outputMetadata.setValue<float>(
|
||||
KeyMaxValue,
|
||||
static_cast<float>(reader.maxValue(_variable))
|
||||
);
|
||||
outputMetadata.setValue<std::string>(
|
||||
KeyVisUnit,
|
||||
static_cast<std::string>(reader.getVisUnit(_variable))
|
||||
);*/
|
||||
RawVolumeMetadata metadata;
|
||||
metadata.time = Time::convertTime(_time);
|
||||
metadata.dimensions = _dimensions;
|
||||
metadata.hasDomainUnit = true;
|
||||
metadata.domainUnit = "m";
|
||||
metadata.hasValueUnit = true;
|
||||
metadata.valueUnit = "kg/m^3";
|
||||
metadata.gridType = VolumeGridType::Cartesian;
|
||||
metadata.hasDomainBounds = true;
|
||||
metadata.lowerDomainBound = _lowerDomainBound;
|
||||
metadata.upperDomainBound = _upperDomainBound;
|
||||
metadata.hasValueRange = true;
|
||||
metadata.minValue = minVal;
|
||||
metadata.maxValue = maxVal;
|
||||
|
||||
ghoul::Dictionary outputDictionary = metadata.dictionary();
|
||||
ghoul::DictionaryLuaFormatter formatter;
|
||||
std::string metadataString = formatter.format(outputMetadata);
|
||||
std::string metadataString = formatter.format(outputDictionary);
|
||||
|
||||
std::fstream f(_dictionaryOutputPath, std::ios::out);
|
||||
f << "return " << metadataString;
|
||||
|
||||
@@ -38,6 +38,14 @@ VolumeGridType parseGridType(const std::string& gridType) {
|
||||
throw InvalidGridTypeError(gridType);
|
||||
}
|
||||
|
||||
std::string gridTypeToString(VolumeGridType gridType) {
|
||||
switch (gridType) {
|
||||
case VolumeGridType::Cartesian: return "Cartesian";
|
||||
case VolumeGridType::Spherical: return "Spherical";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
InvalidGridTypeError::InvalidGridTypeError(std::string gt)
|
||||
: RuntimeError("Invalid grid type: '" + gt + "'")
|
||||
, gridType(std::move(gt))
|
||||
|
||||
@@ -40,6 +40,7 @@ struct InvalidGridTypeError : public ghoul::RuntimeError {
|
||||
};
|
||||
|
||||
VolumeGridType parseGridType(const std::string& gridType);
|
||||
std::string gridTypeToString(VolumeGridType);
|
||||
|
||||
} // namespace openspace::volume
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ ghoul::opengl::Texture& TransferFunction::getTexture() {
|
||||
}
|
||||
|
||||
void TransferFunction::update() {
|
||||
/* if (_needsUpdate) {
|
||||
if (_needsUpdate) {
|
||||
if (hasExtension(_filepath, "txt")) {
|
||||
setTextureFromTxt();
|
||||
} else {
|
||||
@@ -103,7 +103,7 @@ void TransferFunction::update() {
|
||||
if (_tfChangedCallback) {
|
||||
_tfChangedCallback(*this);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void TransferFunction::setCallback(TfChangedCallback callback) {
|
||||
|
||||
Reference in New Issue
Block a user