mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-01 09:10:18 -06:00
405 lines
15 KiB
C++
405 lines
15 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/galaxy/rendering/renderablegalaxy.h>
|
|
|
|
#include <modules/galaxy/rendering/galaxyraycaster.h>
|
|
|
|
#include <ghoul/io/texture/texturereader.h>
|
|
|
|
#include <modules/galaxy/rendering/galaxyraycaster.h>
|
|
#include <openspace/util/boxgeometry.h>
|
|
#include <modules/volume/rawvolume.h>
|
|
#include <openspace/util/updatestructures.h>
|
|
|
|
#include <openspace/rendering/renderable.h>
|
|
#include <openspace/engine/openspaceengine.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/rendering/raycastermanager.h>
|
|
#include <ghoul/glm.h>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <ghoul/opengl/ghoul_gl.h>
|
|
|
|
#include <modules/volume/rawvolumereader.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <ghoul/opengl/texture.h>
|
|
#include <ghoul/opengl/textureunit.h>
|
|
|
|
#include <ghoul/opengl/programobject.h>
|
|
|
|
#include <fstream>
|
|
|
|
|
|
namespace {
|
|
constexpr const char* GlslRayCastPath = "${MODULES}/toyvolume/shaders/rayCast.glsl";
|
|
constexpr const char* GlslBoundsVsPath = "${MODULES}/toyvolume/shaders/boundsVs.glsl";
|
|
constexpr const char* GlslBoundsFsPath = "${MODULES}/toyvolume/shaders/boundsFs.glsl";
|
|
constexpr const char* _loggerCat = "Renderable Galaxy";
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo StepSizeInfo = {
|
|
"StepSize",
|
|
"Step Size",
|
|
"" // @TODO Missing documentation
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo PointStepSizeInfo = {
|
|
"PointStepSize",
|
|
"Point Step Size",
|
|
"" // @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
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo EnabledPointsRatioInfo = {
|
|
"NEnabledPointsRatio",
|
|
"Enabled points",
|
|
"" // @TODO Missing documentation
|
|
};
|
|
} // namespace
|
|
|
|
namespace openspace {
|
|
|
|
RenderableGalaxy::RenderableGalaxy(const ghoul::Dictionary& dictionary)
|
|
: Renderable(dictionary)
|
|
, _stepSize(StepSizeInfo, 0.012f, 0.0005f, 0.05f)
|
|
, _pointStepSize(PointStepSizeInfo, 0.01f, 0.01f, 0.1f)
|
|
, _translation(TranslationInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(10.f))
|
|
, _rotation(RotationInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(6.28f))
|
|
, _enabledPointsRatio(EnabledPointsRatioInfo, 0.2f, 0.f, 1.f)
|
|
{
|
|
dictionary.getValue("Translation", _translation);
|
|
dictionary.getValue("Rotation", _rotation);
|
|
dictionary.getValue("StepSize", _stepSize);
|
|
|
|
if (!dictionary.hasKeyAndValue<ghoul::Dictionary>("Volume")) {
|
|
LERROR("No volume dictionary specified.");
|
|
}
|
|
|
|
ghoul::Dictionary volumeDictionary = dictionary.value<ghoul::Dictionary>("Volume");
|
|
|
|
std::string volumeFilename;
|
|
if (volumeDictionary.getValue("Filename", volumeFilename)) {
|
|
_volumeFilename = absPath(volumeFilename);
|
|
} else {
|
|
LERROR("No volume filename specified.");
|
|
}
|
|
glm::vec3 volumeDimensions;
|
|
if (volumeDictionary.getValue("Dimensions", volumeDimensions)) {
|
|
_volumeDimensions = static_cast<glm::ivec3>(volumeDimensions);
|
|
} else {
|
|
LERROR("No volume dimensions specified.");
|
|
}
|
|
glm::vec3 volumeSize;
|
|
if (volumeDictionary.getValue("Size", volumeSize)) {
|
|
_volumeSize = static_cast<glm::vec3>(volumeSize);
|
|
}
|
|
else {
|
|
LERROR("No volume dimensions specified.");
|
|
}
|
|
|
|
if (!dictionary.hasKeyAndValue<ghoul::Dictionary>("Points")) {
|
|
LERROR("No points dictionary specified.");
|
|
}
|
|
|
|
ghoul::Dictionary pointsDictionary = dictionary.value<ghoul::Dictionary>("Points");
|
|
std::string pointsFilename;
|
|
if (pointsDictionary.getValue("Filename", pointsFilename)) {
|
|
_pointsFilename = absPath(pointsFilename);
|
|
} else {
|
|
LERROR("No points filename specified.");
|
|
}
|
|
pointsDictionary.getValue("Scaling", _pointScaling);
|
|
}
|
|
|
|
RenderableGalaxy::~RenderableGalaxy() {}
|
|
|
|
void RenderableGalaxy::initializeGL() {
|
|
// Aspect is currently hardcoded to cubic voxels.
|
|
_aspect = static_cast<glm::vec3>(_volumeDimensions);
|
|
_aspect /= std::max(std::max(_aspect.x, _aspect.y), _aspect.z);
|
|
|
|
volume::RawVolumeReader<glm::tvec4<GLfloat>> reader(
|
|
_volumeFilename,
|
|
_volumeDimensions
|
|
);
|
|
_volume = reader.read();
|
|
|
|
_texture = std::make_unique<ghoul::opengl::Texture>(
|
|
_volumeDimensions,
|
|
ghoul::opengl::Texture::Format::RGBA,
|
|
GL_RGBA32F,
|
|
GL_FLOAT,
|
|
ghoul::opengl::Texture::FilterMode::Linear,
|
|
ghoul::opengl::Texture::WrappingMode::Clamp);
|
|
|
|
_texture->setPixelData(reinterpret_cast<char*>(
|
|
_volume->data()),
|
|
ghoul::opengl::Texture::TakeOwnership::No
|
|
);
|
|
|
|
_texture->setDimensions(_volume->dimensions());
|
|
_texture->uploadTexture();
|
|
|
|
_raycaster = std::make_unique<GalaxyRaycaster>(*_texture);
|
|
_raycaster->initialize();
|
|
|
|
OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get());
|
|
|
|
auto onChange = [&](bool enabled) {
|
|
if (enabled) {
|
|
OsEng.renderEngine().raycasterManager().attachRaycaster(*_raycaster.get());
|
|
}
|
|
else {
|
|
OsEng.renderEngine().raycasterManager().detachRaycaster(*_raycaster.get());
|
|
}
|
|
};
|
|
|
|
onEnabledChange(onChange);
|
|
|
|
addProperty(_stepSize);
|
|
addProperty(_pointStepSize);
|
|
addProperty(_translation);
|
|
addProperty(_rotation);
|
|
addProperty(_enabledPointsRatio);
|
|
|
|
// initialize points.
|
|
std::ifstream pointFile(_pointsFilename, std::ios::in | std::ios::binary);
|
|
|
|
std::vector<glm::vec3> pointPositions;
|
|
std::vector<glm::vec3> pointColors;
|
|
|
|
int64_t nPoints;
|
|
pointFile.seekg(0, std::ios::beg); // read heder.
|
|
pointFile.read(reinterpret_cast<char*>(&nPoints), sizeof(int64_t));
|
|
|
|
_nPoints = static_cast<size_t>(nPoints);
|
|
|
|
size_t nFloats = _nPoints * 7;
|
|
|
|
std::vector<float> pointData(nFloats);
|
|
pointFile.seekg(sizeof(int64_t), std::ios::beg); // read past heder.
|
|
pointFile.read(reinterpret_cast<char*>(pointData.data()), nFloats * sizeof(float));
|
|
pointFile.close();
|
|
|
|
float maxdist = 0;
|
|
|
|
for (size_t i = 0; i < _nPoints; ++i) {
|
|
float x = pointData[i * 7 + 0];
|
|
float y = pointData[i * 7 + 1];
|
|
float z = pointData[i * 7 + 2];
|
|
float r = pointData[i * 7 + 3];
|
|
float g = pointData[i * 7 + 4];
|
|
float b = pointData[i * 7 + 5];
|
|
maxdist = std::max(maxdist, glm::length(glm::vec3(x, y, z)));
|
|
//float a = pointData[i * 7 + 6]; alpha is not used.
|
|
|
|
pointPositions.push_back(glm::vec3(x, y, z));
|
|
pointColors.push_back(glm::vec3(r, g, b));
|
|
}
|
|
|
|
std::cout << maxdist << std::endl;
|
|
|
|
glGenVertexArrays(1, &_pointsVao);
|
|
glGenBuffers(1, &_positionVbo);
|
|
glGenBuffers(1, &_colorVbo);
|
|
|
|
glBindVertexArray(_pointsVao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, _positionVbo);
|
|
glBufferData(GL_ARRAY_BUFFER,
|
|
pointPositions.size() * sizeof(glm::vec3),
|
|
pointPositions.data(),
|
|
GL_STATIC_DRAW
|
|
);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _colorVbo);
|
|
glBufferData(GL_ARRAY_BUFFER,
|
|
pointColors.size() * sizeof(glm::vec3),
|
|
pointColors.data(),
|
|
GL_STATIC_DRAW
|
|
);
|
|
|
|
RenderEngine& renderEngine = OsEng.renderEngine();
|
|
_pointsProgram = renderEngine.buildRenderProgram(
|
|
"Galaxy points",
|
|
absPath("${MODULE_GALAXY}/shaders/points.vs"),
|
|
absPath("${MODULE_GALAXY}/shaders/points.fs")
|
|
);
|
|
|
|
_pointsProgram->setIgnoreUniformLocationError(
|
|
ghoul::opengl::ProgramObject::IgnoreError::Yes
|
|
);
|
|
|
|
GLint positionAttrib = _pointsProgram->attributeLocation("inPosition");
|
|
GLint colorAttrib = _pointsProgram->attributeLocation("inColor");
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _positionVbo);
|
|
glEnableVertexAttribArray(positionAttrib);
|
|
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _colorVbo);
|
|
glEnableVertexAttribArray(colorAttrib);
|
|
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
void RenderableGalaxy::deinitializeGL() {
|
|
if (_raycaster) {
|
|
OsEng.renderEngine().raycasterManager().detachRaycaster(*_raycaster.get());
|
|
_raycaster = nullptr;
|
|
}
|
|
}
|
|
|
|
bool RenderableGalaxy::isReady() const {
|
|
return true;
|
|
}
|
|
|
|
void RenderableGalaxy::update(const UpdateData& data) {
|
|
if (_raycaster) {
|
|
//glm::mat4 transform = glm::translate(, static_cast<glm::vec3>(_translation));
|
|
const glm::vec3 eulerRotation = static_cast<glm::vec3>(_rotation);
|
|
glm::mat4 transform = glm::rotate(
|
|
glm::mat4(1.0),
|
|
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));
|
|
|
|
glm::mat4 volumeTransform = glm::scale(
|
|
transform,
|
|
static_cast<glm::vec3>(_volumeSize)
|
|
);
|
|
_pointTransform = glm::scale(transform, static_cast<glm::vec3>(_pointScaling));
|
|
|
|
const glm::vec4 translation = glm::vec4(_translation.value(), 0.0);
|
|
|
|
// Todo: handle floating point overflow, to actually support translation.
|
|
|
|
volumeTransform[3] += translation;
|
|
_pointTransform[3] += translation;
|
|
|
|
_raycaster->setStepSize(_stepSize);
|
|
_raycaster->setAspect(_aspect);
|
|
_raycaster->setModelTransform(volumeTransform);
|
|
// @EMIL: is this correct? ---abock
|
|
_raycaster->setTime(data.time.j2000Seconds());
|
|
}
|
|
}
|
|
|
|
void RenderableGalaxy::render(const RenderData& data, RendererTasks& tasks) {
|
|
RaycasterTask task { _raycaster.get(), data };
|
|
|
|
const glm::vec3 position = data.camera.position().vec3();
|
|
const float length = safeLength(position);
|
|
const glm::vec3 galaxySize = static_cast<glm::vec3>(_volumeSize);
|
|
|
|
const float maxDim = std::max(std::max(galaxySize.x, galaxySize.y), galaxySize.z);
|
|
|
|
const float lowerRampStart = maxDim * 0.02f;
|
|
const float lowerRampEnd = maxDim * 0.5f;
|
|
|
|
const float upperRampStart = maxDim * 2.f;
|
|
const float upperRampEnd = maxDim * 10.f;
|
|
|
|
float opacityCoefficient = 1.f;
|
|
|
|
if (length < lowerRampStart) {
|
|
opacityCoefficient = 0.f; // camera really close
|
|
} else if (length < lowerRampEnd) {
|
|
opacityCoefficient = (length - lowerRampStart) / (lowerRampEnd - lowerRampStart);
|
|
} else if (length < upperRampStart) {
|
|
opacityCoefficient = 1.f; // sweet spot (max)
|
|
} else if (length < upperRampEnd) {
|
|
opacityCoefficient = 1.f - (length - upperRampStart) /
|
|
(upperRampEnd - upperRampStart); //fade out
|
|
} else {
|
|
opacityCoefficient = 0;
|
|
}
|
|
|
|
_opacityCoefficient = opacityCoefficient;
|
|
ghoul_assert(
|
|
_opacityCoefficient >= 0.f && _opacityCoefficient <= 1.f,
|
|
"Opacity coefficient was not between 0 and 1"
|
|
);
|
|
if (opacityCoefficient > 0) {
|
|
_raycaster->setOpacityCoefficient(_opacityCoefficient);
|
|
tasks.raycasterTasks.push_back(task);
|
|
}
|
|
}
|
|
|
|
float RenderableGalaxy::safeLength(const glm::vec3& vector) const {
|
|
const float maxComponent = std::max(
|
|
std::max(std::abs(vector.x), std::abs(vector.y)), std::abs(vector.z)
|
|
);
|
|
return glm::length(vector / maxComponent) * maxComponent;
|
|
}
|
|
|
|
/*void RenderableGalaxy::postRender(const RenderData& data) {
|
|
|
|
_raycaster->setStepSize(_pointStepSize);
|
|
|
|
_pointsProgram->activate();
|
|
setPscUniforms(*_pointsProgram.get(), data.camera, data.position);
|
|
|
|
OsEng.ref().renderEngine().preRaycast(*_pointsProgram);
|
|
|
|
glm::mat4 modelMatrix = _pointTransform;
|
|
glm::mat4 viewMatrix = data.camera.viewMatrix();
|
|
glm::mat4 projectionMatrix = data.camera.projectionMatrix();
|
|
|
|
_pointsProgram->setUniform("model", modelMatrix);
|
|
_pointsProgram->setUniform("view", viewMatrix);
|
|
_pointsProgram->setUniform("projection", projectionMatrix);
|
|
|
|
float emittanceFactor = _opacityCoefficient * static_cast<glm::vec3>(_volumeSize).x;
|
|
_pointsProgram->setUniform("emittanceFactor", emittanceFactor);
|
|
|
|
glBindVertexArray(_pointsVao);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDepthMask(false);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
glDrawArrays(GL_POINTS, 0, _nPoints * _enabledPointsRatio);
|
|
glBindVertexArray(0);
|
|
glDepthMask(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
OsEng.ref().renderEngine().postRaycast(*_pointsProgram);
|
|
}*/
|
|
|
|
} // namespace openspace
|