Add base for textured cutplanes

This commit is contained in:
Malin E
2024-02-23 11:38:27 +01:00
parent 3967c016d7
commit fced930a22
4 changed files with 369 additions and 88 deletions

View File

@@ -48,13 +48,13 @@ namespace {
constexpr std::string_view _loggerCat = "RenderableTube";
constexpr int8_t CurrentMajorVersion = 0;
constexpr int8_t CurrentMinorVersion = 1;
constexpr std::array<const char*, 23> UniformNames = {
"modelViewTransform", "projectionTransform", "normalTransform", "opacity",
"color", "nanColor", "useNanColor", "aboveRangeColor", "useAboveRangeColor",
"belowRangeColor", "useBelowRangeColor", "useColorMap", "colorMapTexture",
"cmapRangeMin", "cmapRangeMax", "hideOutsideRange", "performShading",
"nLightSources", "lightDirectionsViewSpace", "lightIntensities",
"ambientIntensity", "diffuseIntensity", "specularIntensity"
constexpr int NearestInterpolation = 0;
constexpr int LinearInterpolation = 1;
std::map<std::string, int> InterpolationMapping = {
{ "Nearest Neighbor", NearestInterpolation },
{ "Linear", LinearInterpolation },
};
constexpr openspace::properties::Property::PropertyInfo TransferFunctionInfo = {
@@ -165,6 +165,13 @@ namespace {
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo InterpolationMethodInfo = {
"InterpolationMethod",
"Interpolation Method",
"Which interpolaiton method to use for the cutplane texture",
openspace::properties::Property::Visibility::AdvancedUser
};
struct [[codegen::Dictionary(RenderableTube)]] Parameters {
// The input file with data for the tube
std::string file;
@@ -203,6 +210,9 @@ namespace {
// [[codegen::verbatim(AddEdgesInfo.description)]]
std::optional<bool> addEdges;
// [[codegen::verbatim(InterpolationMethodInfo.description)]]
std::optional<std::string> interpolationMethod;
// [[codegen::verbatim(DrawWireframeInfo.description)]]
std::optional<bool> drawWireframe;
@@ -264,6 +274,10 @@ RenderableTube::RenderableTube(const ghoul::Dictionary& dictionary)
, _lightSourcePropertyOwner({ "LightSources", "Light Sources" })
, _colorSettings(dictionary)
, _addEdges(AddEdgesInfo, true)
, _interpolationMethod(
InterpolationMethodInfo,
properties::OptionProperty::DisplayType::Dropdown
)
, _drawWireframe(DrawWireframeInfo, false)
, _wireLineWidth(WireLineWidthInfo, 1.f, 1.f, 10.f)
, _useSmoothNormals(UseSmoothNormalsInfo, true)
@@ -330,6 +344,14 @@ RenderableTube::RenderableTube(const ghoul::Dictionary& dictionary)
_addEdges = p.addEdges.value_or(_addEdges);
addProperty(_addEdges);
_interpolationMethod.addOption(NearestInterpolation, "Nearest Neighbor");
_interpolationMethod.addOption(LinearInterpolation, "Linear");
addProperty(_interpolationMethod);
if (p.interpolationMethod.has_value()) {
const std::string interpolationMethod = *p.interpolationMethod;
_interpolationMethod = InterpolationMapping[interpolationMethod];
}
_showAllTube = p.showAllTube.value_or(_showAllTube);
addProperty(_showAllTube);
@@ -366,7 +388,12 @@ void RenderableTube::initializeGL() {
absPath("${MODULE_BASE}/shaders/tube_vs.glsl"),
absPath("${MODULE_BASE}/shaders/tube_fs.glsl")
);
ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
_shaderCutplane = global::renderEngine->buildRenderProgram(
"TubeProgram",
absPath("${MODULE_BASE}/shaders/tube_cutplane_vs.glsl"),
absPath("${MODULE_BASE}/shaders/tube_cutplane_fs.glsl")
);
if (_hasColorMapFile) {
_colorSettings.colorMapping->initializeTexture();
@@ -462,6 +489,9 @@ void RenderableTube::deinitializeGL() {
global::renderEngine->removeRenderProgram(_shader.get());
_shader = nullptr;
global::renderEngine->removeRenderProgram(_shaderCutplane.get());
_shaderCutplane = nullptr;
glDeleteVertexArrays(1, &_vaoId);
_vaoId = 0;
@@ -632,6 +662,9 @@ void RenderableTube::readDataFile() {
pt->at("u").get_to(u);
pt->at("v").get_to(v);
timePolygonPoint.tex = glm::vec2(u, v);
//@TODO Move this when the proper reading of textures are added
//_hasInterpolationTextures = true;
}
timePolygon.points.push_back(timePolygonPoint);
@@ -1201,6 +1234,7 @@ void RenderableTube::creteEnding(double now) {
double prevTime = _data[_lastPolygonBeforeNow].timestamp;
double nextTime = _data[_firstPolygonAfterNow].timestamp;
double t = (now - prevTime) / (nextTime - prevTime);
_tValue = t;
// Create a temporary TimePolygon at time t between prev and next using interpolation
const TimePolygon const* prevTimePolygon = &_data[_lastPolygonBeforeNow];
@@ -1224,10 +1258,10 @@ void RenderableTube::creteEnding(double now) {
}
if (_useSmoothNormals) {
createSmoothEnding(t, prevTimePolygon, &currentTimePolygon);
createSmoothEnding(prevTimePolygon, &currentTimePolygon);
}
else {
createLowPolyEnding(t, prevTimePolygon, &currentTimePolygon);
createLowPolyEnding(prevTimePolygon, &currentTimePolygon);
}
// Add cutplane
@@ -1237,8 +1271,7 @@ void RenderableTube::creteEnding(double now) {
}
}
void RenderableTube::createSmoothEnding(double tInterpolation,
const TimePolygon const* prevTimePolygon,
void RenderableTube::createSmoothEnding(const TimePolygon const* prevTimePolygon,
const TimePolygon const* currentTimePolygon)
{
// Add the trianles of the ending
@@ -1258,12 +1291,11 @@ void RenderableTube::createSmoothEnding(double tInterpolation,
true, // The last polygon in this section
vIndex,
true, // This is part of the ending
tInterpolation
_tValue
);
}
void RenderableTube::createLowPolyEnding(double tInterpolation,
const TimePolygon const* prevTimePolygon,
void RenderableTube::createLowPolyEnding(const TimePolygon const* prevTimePolygon,
const TimePolygon const* currentTimePolygon)
{
// Add the trianles of the ending
@@ -1274,45 +1306,23 @@ void RenderableTube::createLowPolyEnding(double tInterpolation,
prevTimePolygon,
currentTimePolygon,
vIndex,
tInterpolation
_tValue
);
}
void RenderableTube::render(const RenderData& data, RendererTasks&) {
if (_nIndiciesToRender == 0) {
return;
}
_shader->activate();
void RenderableTube::setCommonUniforms(ghoul::opengl::ProgramObject* shader, const RenderData& data) {
shader->setUniform("opacity", opacity());
// Model transform and view transform needs to be in double precision
const glm::dmat4 modelViewTransform = calcModelViewTransform(data);
glm::dmat4 normalTransform = glm::transpose(glm::inverse(modelViewTransform));
// Uniforms
_shader->setUniform(_uniformCache.opacity, opacity());
_shader->setUniform(_uniformCache.modelViewTransform, modelViewTransform);
_shader->setUniform(
_uniformCache.projectionTransform,
shader->setUniform("modelViewTransform", modelViewTransform);
shader->setUniform(
"projectionTransform",
glm::dmat4(data.camera.projectionMatrix())
);
_shader->setUniform(_uniformCache.normalTransform, glm::mat3(normalTransform));
// Settings
if (!_enableFaceCulling) {
glDisable(GL_CULL_FACE);
}
if (_drawWireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#ifndef __APPLE__
glLineWidth(_wireLineWidth);
#else
glLineWidth(1.f);
#endif
}
shader->setUniform("normalTransform", glm::mat3(normalTransform));
// Shading and light settings
int nLightSources = 0;
@@ -1329,72 +1339,95 @@ void RenderableTube::render(const RenderData& data, RendererTasks&) {
++nLightSources;
}
if (_uniformCache.performShading != -1) {
_shader->setUniform(_uniformCache.performShading, _shading.enabled);
}
shader->setUniform("performShading", _shading.enabled);
if (_shading.enabled) {
_shader->setUniform(_uniformCache.nLightSources, nLightSources);
_shader->setUniform(_uniformCache.lightIntensities, _lightIntensitiesBuffer);
_shader->setUniform(
_uniformCache.lightDirectionsViewSpace,
shader->setUniform("nLightSources", nLightSources);
shader->setUniform("lightIntensities", _lightIntensitiesBuffer);
shader->setUniform(
"lightDirectionsViewSpace",
_lightDirectionsViewSpaceBuffer
);
_shader->setUniform(_uniformCache.ambientIntensity, _shading.ambientIntensity);
_shader->setUniform(_uniformCache.diffuseIntensity, _shading.diffuseIntensity);
_shader->setUniform(_uniformCache.specularIntensity, _shading.specularIntensity);
shader->setUniform("ambientIntensity", _shading.ambientIntensity);
shader->setUniform("diffuseIntensity", _shading.diffuseIntensity);
shader->setUniform("specularIntensity", _shading.specularIntensity);
}
// Colormap settings
bool useColorMap = _hasColorMapFile && _colorSettings.colorMapping->enabled &&
_colorSettings.colorMapping->texture();
_shader->setUniform(_uniformCache.useColorMap, useColorMap);
shader->setUniform("useColorMap", useColorMap);
_shader->setUniform(_uniformCache.color, _colorSettings.tubeColor);
shader->setUniform("color", _colorSettings.tubeColor);
ghoul::opengl::TextureUnit colorMapTextureUnit;
_shader->setUniform(_uniformCache.colorMapTexture, colorMapTextureUnit);
shader->setUniform("colorMapTexture", colorMapTextureUnit);
if (useColorMap) {
colorMapTextureUnit.activate();
_colorSettings.colorMapping->texture()->bind();
const glm::vec2 range = _colorSettings.colorMapping->valueRange;
_shader->setUniform(_uniformCache.cmapRangeMin, range.x);
_shader->setUniform(_uniformCache.cmapRangeMax, range.y);
_shader->setUniform(
_uniformCache.hideOutsideRange,
shader->setUniform("cmapRangeMin", range.x);
shader->setUniform("cmapRangeMax", range.y);
shader->setUniform(
"hideOutsideRange",
_colorSettings.colorMapping->hideOutsideRange
);
_shader->setUniform(
_uniformCache.nanColor,
shader->setUniform(
"nanColor",
_colorSettings.colorMapping->nanColor
);
_shader->setUniform(
_uniformCache.useNanColor,
shader->setUniform(
"useNanColor",
_colorSettings.colorMapping->useNanColor
);
_shader->setUniform(
_uniformCache.aboveRangeColor,
shader->setUniform(
"aboveRangeColor",
_colorSettings.colorMapping->aboveRangeColor
);
_shader->setUniform(
_uniformCache.useAboveRangeColor,
shader->setUniform(
"useAboveRangeColor",
_colorSettings.colorMapping->useAboveRangeColor
);
_shader->setUniform(
_uniformCache.belowRangeColor,
shader->setUniform(
"belowRangeColor",
_colorSettings.colorMapping->belowRangeColor
);
_shader->setUniform(
_uniformCache.useBelowRangeColor,
shader->setUniform(
"useBelowRangeColor",
_colorSettings.colorMapping->useBelowRangeColor
);
}
}
void RenderableTube::render(const RenderData& data, RendererTasks&) {
if (_nIndiciesToRender == 0) {
return;
}
_shader->activate();
// Uniforms
setCommonUniforms(_shader.get(), data);
// Settings
if (!_enableFaceCulling) {
glDisable(GL_CULL_FACE);
}
if (_drawWireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#ifndef __APPLE__
glLineWidth(_wireLineWidth);
#else
glLineWidth(1.f);
#endif
}
// Render
glBindVertexArray(_vaoId);
@@ -1417,7 +1450,31 @@ void RenderableTube::render(const RenderData& data, RendererTasks&) {
}
// Render the cutplane
if (_addEdges && !_showAllTube && (_interpolationNeeded || _nIndiciesToRender < _indicies.size())) {
if (_addEdges && !_showAllTube &&
(_interpolationNeeded || _nIndiciesToRender < _indicies.size()))
{
// Use the texture based shader instead for the cutplane if textures exist
if (_hasInterpolationTextures) {
// Switch shader
_shaderCutplane->activate();
// Uniforms
setCommonUniforms(_shaderCutplane.get(), data);
_shaderCutplane->setUniform(
"hasInterpolationTexture",
_hasInterpolationTextures
);
_shaderCutplane->setUniform(
"useNearesNeighbor",
_interpolationMethod == NearestInterpolation
);
_shaderCutplane->setUniform("interpolationTime", _tValue);
// @TODO: Find the textures relevant to this cutplane and bind them
_shaderCutplane->setUniform("texture_prev", false);
_shaderCutplane->setUniform("texture_next", false);
}
// Bind the cutplane ibo instead
glBindVertexArray(_vaoIdEnding);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iboIdEnding);
@@ -1435,6 +1492,8 @@ void RenderableTube::render(const RenderData& data, RendererTasks&) {
GL_UNSIGNED_INT,
nullptr
);
_shaderCutplane->deactivate();
}
// Reset
@@ -1449,7 +1508,6 @@ void RenderableTube::render(const RenderData& data, RendererTasks&) {
glBindVertexArray(0);
global::renderEngine->openglStateCache().resetLineState();
_shader->deactivate();
}
@@ -1494,7 +1552,10 @@ void RenderableTube::updateEndingBufferData() {
void RenderableTube::update(const UpdateData& data) {
if (_shader->isDirty()) {
_shader->rebuildFromFile();
ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
}
if (_shaderCutplane->isDirty()) {
_shaderCutplane->rebuildFromFile();
}
if (_hasColorMapFile) {

View File

@@ -112,15 +112,14 @@ private:
void interpolateEnd(double now);
void creteEnding(double now);
void createSmoothEnding(double tInterpolation,
const TimePolygon const* prevTimePolygon,
void createSmoothEnding(const TimePolygon const* prevTimePolygon,
const TimePolygon const* currentTimePolygon);
void createLowPolyEnding(double tInterpolation,
const TimePolygon const* prevTimePolygon,
void createLowPolyEnding(const TimePolygon const* prevTimePolygon,
const TimePolygon const* currentTimePolygon);
void updateBufferData();
void updateEndingBufferData();
void setCommonUniforms(ghoul::opengl::ProgramObject* shader, const RenderData& data);
// Properties
struct ColorSettings : properties::PropertyOwner {
@@ -144,18 +143,12 @@ private:
properties::FloatProperty _wireLineWidth;
properties::BoolProperty _useSmoothNormals;
properties::BoolProperty _addEdges;
properties::OptionProperty _interpolationMethod;
properties::BoolProperty _showAllTube;
properties::BoolProperty _enableFaceCulling;
properties::TriggerProperty _jumpToPrevPolygon;
properties::TriggerProperty _jumpToNextPolygon;
UniformCache(modelViewTransform, projectionTransform, normalTransform, opacity, color,
nanColor, useNanColor, aboveRangeColor, useAboveRangeColor, belowRangeColor,
useBelowRangeColor, useColorMap, colorMapTexture, cmapRangeMin, cmapRangeMax,
hideOutsideRange, performShading, nLightSources, lightDirectionsViewSpace,
lightIntensities, ambientIntensity, diffuseIntensity,
specularIntensity)_uniformCache;
std::vector<float> _lightIntensitiesBuffer;
std::vector<glm::vec3> _lightDirectionsViewSpaceBuffer;
std::vector<std::unique_ptr<LightSource>> _lightSources;
@@ -169,6 +162,7 @@ private:
size_t _lastPolygonBeforeNow = 0;
size_t _firstPolygonAfterNow = 0;
bool _interpolationNeeded = false;
float _tValue = 0.f;
dataloader::Dataset _colorDataset;
bool _hasColorMapFile = false;
@@ -181,6 +175,8 @@ private:
std::vector<unsigned int> _indicies;
// Ending stuff
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderCutplane;
bool _hasInterpolationTextures = false;
GLuint _vaoIdEnding = 0;
GLuint _vboIdEnding = 0;
GLuint _iboIdEnding = 0;

View File

@@ -0,0 +1,168 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* 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 "fragment.glsl"
in float vs_depth;
in vec3 vs_normal;
in vec4 vs_positionViewSpace;
in float vs_value;
in vec2 vs_st;
uniform float opacity;
uniform vec3 color;
uniform vec4 nanColor = vec4(0.5);
uniform bool useNanColor = true;
uniform vec4 aboveRangeColor;
uniform bool useAboveRangeColor;
uniform vec4 belowRangeColor;
uniform bool useBelowRangeColor;
uniform bool useColorMap;
uniform sampler1D colorMapTexture;
uniform float cmapRangeMin;
uniform float cmapRangeMax;
uniform bool hideOutsideRange;
uniform bool performShading = true;
uniform float ambientIntensity;
uniform float diffuseIntensity;
uniform float specularIntensity;
uniform int nLightSources;
uniform vec3 lightDirectionsViewSpace[8];
uniform float lightIntensities[8];
// For interpolation of the value sent into the color map
uniform bool hasInterpolationTexture = false;
uniform bool useNearesNeighbor;
uniform float interpolationTime;
uniform sampler2D texture_prev;
uniform sampler2D texture_next;
// Could be seperated into ambinet, diffuse and specular and passed in as uniforms
const vec3 LightColor = vec3(1.0);
const float SpecularPower = 100.0;
vec4 sampleColorMap(float dataValue) {
if (useNanColor && isnan(dataValue)) {
return nanColor;
}
bool isOutside = dataValue < cmapRangeMin || dataValue > cmapRangeMax;
if (isnan(dataValue) || (hideOutsideRange && isOutside)) {
discard;
}
if (useBelowRangeColor && dataValue < cmapRangeMin) {
return belowRangeColor;
}
if (useAboveRangeColor && dataValue > cmapRangeMax) {
return aboveRangeColor;
}
float v = (dataValue - cmapRangeMin) / (cmapRangeMax - cmapRangeMin);
v = clamp(v, 0.0, 1.0);
return texture(colorMapTexture, v);
}
Fragment getFragment() {
if (opacity == 0.0) {
discard;
}
Fragment frag;
// Color map
vec4 objectColor = vec4(1.0);
if (useColorMap) {
if (hasInterpolationTexture) {
float t = interpolationTime;
if (useNearesNeighbor) {
// If t < 0.5 then t -> 0, which later become 100% prevTexture value
// If instead t >= 0.5 then t -> 1, which later become 100% nextTexture value
t = step(0.5, interpolationTime);
}
// Interpolate with linear interpolation
float valuePrev = texture(texture_prev, vs_st).r;
float valueNext = texture(texture_next, vs_st).r;
float value = t * valueNext + (1.0 - t) * valuePrev;
value = clamp(value, 0.0, 1.0);
objectColor = sampleColorMap(value);
}
else {
objectColor = sampleColorMap(vs_value);
}
}
else {
objectColor.rgb = color;
}
objectColor.a *= opacity;
if (objectColor.a == 0.0) {
discard;
}
if (performShading) {
// Ambient light
vec3 totalLightColor = ambientIntensity * LightColor * objectColor.rgb;
vec3 viewDirection = normalize(vs_positionViewSpace.xyz);
// Light sources
for (int i = 0; i < nLightSources; ++i) {
// Diffuse light
vec3 lightDirection = lightDirectionsViewSpace[i];
float diffuseFactor = max(dot(vs_normal, lightDirection), 0.0);
vec3 diffuseColor = diffuseIntensity * LightColor * diffuseFactor * objectColor.rgb;
// Specular light
vec3 reflectDirection = reflect(lightDirection, vs_normal);
float specularFactor =
pow(max(dot(viewDirection, reflectDirection), 0.0), SpecularPower);
vec3 specularColor = specularIntensity * LightColor * specularFactor;
// Total Light
totalLightColor += lightIntensities[i] * (diffuseColor + specularColor);
}
frag.color.rgb = totalLightColor;
}
else {
frag.color.rgb = objectColor.rgb;
}
frag.depth = vs_depth;
frag.gPosition = vs_positionViewSpace;
frag.gNormal = vec4(vs_normal, 0.0);
frag.disableLDR2HDR = true;
frag.color.a = opacity;
return frag;
}

View File

@@ -0,0 +1,56 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* 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. *
****************************************************************************************/
#version __CONTEXT__
layout (location = 0) in dvec3 in_position;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in float in_value;
layout (location = 3) in vec2 in_st;
out float vs_depth;
out vec3 vs_normal;
out vec4 vs_positionViewSpace;
out float vs_value;
out vec2 vs_st;
uniform dmat4 modelViewTransform;
uniform dmat4 projectionTransform;
uniform mat3 normalTransform;
void main() {
vs_value = in_value;
vs_normal = normalize(normalTransform * in_normal);
dvec4 position = dvec4(in_position, 1.0);
dvec4 positionViewSpace = modelViewTransform * position;
vs_positionViewSpace = vec4(positionViewSpace);
dvec4 positionClipSpace = projectionTransform * positionViewSpace;
dvec4 positionScreenSpace = positionClipSpace;
positionScreenSpace.z = 0.0;
gl_Position = vec4(positionScreenSpace);
vs_depth = float(positionScreenSpace.w);
vs_st = in_st;
}