mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-24 13:08:49 -05:00
Feature/arrow renderable (#2219)
* Create a RenderableNodeLine example asset * First version of node direction hint renderable (arrow) * Add possibility to set length as a multiplier of the bounding sphere * Draw arrow cylinder using index array * Update exponents and min max values for lengths * Draw arrow head * Only update arrow geometry when positions change * Add some properties to control visuals of arrow * Implement invert option * Add normals and shading * Set arrow head size by length percentage instead of angle * Add bottom circle to cone * Cleanup and update examples * Remove non-existing property from example asset * Fix vertices not updating if anchor node was changed And some missing updates on property change * Start cleaning up some shape rendering helper functions * Cleanup code and move cylinder function to helper class * Refactor cylinder creation code (fewer loops over same vector) * Update transformations to correctly scale and place arrow * Add the cone to make the arrowhead * Update faulty triangle normals * Add property visibilities * Rename NodeDirectionHint to NodeArrow * Apply suggestions from code review Co-authored-by: Alexander Bock <alexander.bock@liu.se> --------- Co-authored-by: Alexander Bock <alexander.bock@liu.se>
This commit is contained in:
@@ -0,0 +1,515 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <modules/base/rendering/renderablenodearrow.h>
|
||||
|
||||
#include <modules/base/basemodule.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/navigation/orbitalnavigator.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/helper.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scene/translation.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/opengl/openglstatecache.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
#include <glm/gtx/projection.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view _loggerCat = "RenderableNodeArrow";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo StartNodeInfo = {
|
||||
"StartNode",
|
||||
"Start Node",
|
||||
"The identifier of the node the arrow starts from",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EndNodeInfo = {
|
||||
"EndNode",
|
||||
"End Node",
|
||||
"The identifier of the node the arrow should point towards",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ColorInfo = {
|
||||
"Color",
|
||||
"Color",
|
||||
"This value determines the RGB color for the arrow",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SegmentsInfo = {
|
||||
"Segments",
|
||||
"Number of Segments",
|
||||
"This value specifies the number of segments that the shapes for the arrow are "
|
||||
"separated in. A higher number leads to a higher resolution",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo InvertInfo = {
|
||||
"Invert",
|
||||
"Invert Direction",
|
||||
"If set to true, the arrow direction is inverted so that it points to the "
|
||||
"start node instead of the end node",
|
||||
openspace::properties::Property::Visibility::NoviceUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ArrowHeadSizeInfo = {
|
||||
"ArrowHeadSize",
|
||||
"Arrow Head Size",
|
||||
"This size of the arrow head, given in relative value of the entire length of "
|
||||
"the arrow. For example, 0.1 makes the arrow head length be 10% of the full "
|
||||
"arrow length",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ArrowHeadWidthInfo = {
|
||||
"ArrowHeadWidthFactor",
|
||||
"Arrow Head Width Factor",
|
||||
"A factor that is multiplied with the width, or the arrow itself, to determine "
|
||||
"the width of the base of the arrow head",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo OffsetDistanceInfo = {
|
||||
"Offset",
|
||||
"Offset Distance",
|
||||
"The distance from the center of the start node where the arrow starts. "
|
||||
"If 'UseRelativeOffset' is true, the value should be given as a factor to "
|
||||
"multiply with the bounding sphere of the node. Otherwise, the value is "
|
||||
"specified in meters",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RelativeOffsetInfo = {
|
||||
"UseRelativeOffset",
|
||||
"Use Relative Offset Distance",
|
||||
"Decide whether to use relative distances (in units of start node bounding "
|
||||
"sphere) for the offset distance. If false, meters is used",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LengthInfo = {
|
||||
"Length",
|
||||
"Length",
|
||||
"The length of the arrow, given either in meters or as a factor to be "
|
||||
"multiplied with the bounding sphere of the start node (if "
|
||||
"'UseRelativeLength' is true)",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo RelativeLengthInfo = {
|
||||
"UseRelativeLength",
|
||||
"Use Relative Length",
|
||||
"Decide whether to use relative size (in units of start node bounding "
|
||||
"sphere) for the length of the arrow. If false, meters is used",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo WidthInfo = {
|
||||
"Width",
|
||||
"Width",
|
||||
"This value specifies the width of the arrow shape",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo AmbientIntensityInfo = {
|
||||
"AmbientIntensity",
|
||||
"Ambient Intensity",
|
||||
"A multiplier for ambient lighting for the shading of the arrow",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DiffuseIntensityInfo = {
|
||||
"DiffuseIntensity",
|
||||
"Diffuse Intensity",
|
||||
"A multiplier for diffuse lighting for the shading of the arrow",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SpecularIntensityInfo = {
|
||||
"SpecularIntensity",
|
||||
"Specular Intensity",
|
||||
"A multiplier for specular lighting for the shading of the arrow",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ShadingEnabledInfo = {
|
||||
"PerformShading",
|
||||
"Perform Shading",
|
||||
"This value determines whether shading should be applied to the arrow model",
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(RenderableNodeArrow)]] Parameters {
|
||||
// [[codegen::verbatim(StartNodeInfo.description)]]
|
||||
std::string startNode [[codegen::notempty]];
|
||||
|
||||
// [[codegen::verbatim(EndNodeInfo.description)]]
|
||||
std::string endNode [[codegen::notempty]];
|
||||
|
||||
// [[codegen::verbatim(ColorInfo.description)]]
|
||||
std::optional<glm::vec3> color [[codegen::color()]];
|
||||
|
||||
// [[codegen::verbatim(SegmentsInfo.description)]]
|
||||
std::optional<int> segments [[codegen::greaterequal(3)]];
|
||||
|
||||
// [[codegen::verbatim(InvertInfo.description)]]
|
||||
std::optional<bool> invert;
|
||||
|
||||
// [[codegen::verbatim(ArrowHeadSizeInfo.description)]]
|
||||
std::optional<float> arrowHeadSize [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(ArrowHeadWidthInfo.description)]]
|
||||
std::optional<float> arrowHeadWidthFactor [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(OffsetDistanceInfo.description)]]
|
||||
std::optional<float> offset;
|
||||
|
||||
// [[codegen::verbatim(RelativeOffsetInfo.description)]]
|
||||
std::optional<bool> useRelativeOffset;
|
||||
|
||||
// [[codegen::verbatim(LengthInfo.description)]]
|
||||
std::optional<float> length [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(RelativeLengthInfo.description)]]
|
||||
std::optional<bool> useRelativeLength;
|
||||
|
||||
// [[codegen::verbatim(WidthInfo.description)]]
|
||||
std::optional<float> width [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(ShadingEnabledInfo.description)]]
|
||||
std::optional<float> performShading;
|
||||
|
||||
// [[codegen::verbatim(AmbientIntensityInfo.description)]]
|
||||
std::optional<float> ambientIntensity [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(DiffuseIntensityInfo.description)]]
|
||||
std::optional<float> diffuseIntensity [[codegen::greaterequal(0.f)]];
|
||||
|
||||
// [[codegen::verbatim(SpecularIntensityInfo.description)]]
|
||||
std::optional<float> specularIntensity [[codegen::greaterequal(0.f)]];
|
||||
};
|
||||
#include "renderablenodearrow_codegen.cpp"
|
||||
|
||||
void updateDistanceBasedOnRelativeValues(const std::string& nodeName,
|
||||
bool useRelative,
|
||||
openspace::properties::FloatProperty& prop)
|
||||
{
|
||||
using namespace::openspace;
|
||||
|
||||
SceneGraphNode* startNode = sceneGraphNode(nodeName);
|
||||
if (!startNode) {
|
||||
LERROR(fmt::format("Could not find start node '{}'", nodeName));
|
||||
return;
|
||||
}
|
||||
const double boundingSphere = startNode->boundingSphere();
|
||||
|
||||
if (!useRelative) {
|
||||
// Recompute distance (previous value was relative)
|
||||
prop = static_cast<float>(prop * boundingSphere);
|
||||
prop.setExponent(11.f);
|
||||
prop.setMaxValue(1e20f);
|
||||
}
|
||||
else {
|
||||
// Recompute distance (previous value was in meters)
|
||||
if (boundingSphere < std::numeric_limits<double>::epsilon()) {
|
||||
LERROR(fmt::format(
|
||||
"Start node '{}' has invalid bounding sphere", nodeName
|
||||
));
|
||||
return;
|
||||
}
|
||||
prop = static_cast<float>(prop / boundingSphere);
|
||||
prop.setExponent(3.f);
|
||||
prop.setMaxValue(1000.f);
|
||||
}
|
||||
// @TODO (emmbr, 2022-08-22): make GUI update when min/max value is updated
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableNodeArrow::Documentation() {
|
||||
return codegen::doc<Parameters>("base_renderable_renderablenodearrow");
|
||||
}
|
||||
|
||||
RenderableNodeArrow::Shading::Shading()
|
||||
: properties::PropertyOwner({ "Shading" })
|
||||
, enabled(ShadingEnabledInfo, true)
|
||||
, ambientIntensity(AmbientIntensityInfo, 0.2f, 0.f, 1.f)
|
||||
, diffuseIntensity(DiffuseIntensityInfo, 0.7f, 0.f, 1.f)
|
||||
, specularIntensity(SpecularIntensityInfo, 0.f, 0.f, 1.f)
|
||||
{
|
||||
addProperty(enabled);
|
||||
addProperty(ambientIntensity);
|
||||
addProperty(diffuseIntensity);
|
||||
addProperty(specularIntensity);
|
||||
}
|
||||
|
||||
RenderableNodeArrow::RenderableNodeArrow(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _start(StartNodeInfo)
|
||||
, _end(EndNodeInfo)
|
||||
, _color(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
, _segments(SegmentsInfo, 10, 3, 100)
|
||||
, _invertArrowDirection(InvertInfo, false)
|
||||
, _arrowHeadSize(ArrowHeadSizeInfo, 0.1f, 0.f, 1.f)
|
||||
, _arrowHeadWidthFactor(ArrowHeadWidthInfo, 2.f, 1.f, 100.f)
|
||||
, _offsetDistance(OffsetDistanceInfo, 0.f, 0.f, 1e20f)
|
||||
, _useRelativeOffset(RelativeOffsetInfo, false)
|
||||
, _length(LengthInfo, 100.f, 0.f, 1e20f)
|
||||
, _useRelativeLength(RelativeLengthInfo, false)
|
||||
, _width(WidthInfo, 10.f, 0.f, 1e11f)
|
||||
{
|
||||
const Parameters p = codegen::bake<Parameters>(dictionary);
|
||||
|
||||
_shading.enabled = p.performShading.value_or(_shading.enabled);
|
||||
_shading.ambientIntensity = p.ambientIntensity.value_or(_shading.ambientIntensity);
|
||||
_shading.diffuseIntensity = p.diffuseIntensity.value_or(_shading.diffuseIntensity);
|
||||
_shading.specularIntensity = p.specularIntensity.value_or(_shading.specularIntensity);
|
||||
addPropertySubOwner(_shading);
|
||||
|
||||
addProperty(Fadeable::_opacity);
|
||||
|
||||
_color = p.color.value_or(_color);
|
||||
_color.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_color);
|
||||
|
||||
_start = p.startNode;
|
||||
addProperty(_start);
|
||||
|
||||
_end = p.endNode;
|
||||
addProperty(_end);
|
||||
|
||||
_segments = p.segments.value_or(_segments);
|
||||
addProperty(_segments);
|
||||
|
||||
_invertArrowDirection = p.invert.value_or(_invertArrowDirection);
|
||||
addProperty(_invertArrowDirection);
|
||||
|
||||
_arrowHeadSize = p.arrowHeadSize.value_or(_arrowHeadSize);
|
||||
addProperty(_arrowHeadSize);
|
||||
|
||||
_arrowHeadWidthFactor = p.arrowHeadWidthFactor.value_or(_arrowHeadWidthFactor);
|
||||
addProperty(_arrowHeadWidthFactor);
|
||||
|
||||
_width = p.width.value_or(_width);
|
||||
_width.setExponent(10.f);
|
||||
addProperty(_width);
|
||||
|
||||
_useRelativeLength.onChange([this]() {
|
||||
updateDistanceBasedOnRelativeValues(_start, _useRelativeLength, _length);
|
||||
});
|
||||
_useRelativeLength = p.useRelativeLength.value_or(_useRelativeLength);
|
||||
|
||||
_length = p.length.value_or(_length);
|
||||
if (!_useRelativeLength) {
|
||||
_length.setExponent(11.f);
|
||||
}
|
||||
addProperty(_length);
|
||||
|
||||
_useRelativeOffset.onChange([this]() {
|
||||
updateDistanceBasedOnRelativeValues(_start, _useRelativeOffset, _offsetDistance);
|
||||
});
|
||||
_useRelativeOffset = p.useRelativeOffset.value_or(_useRelativeOffset);
|
||||
|
||||
_offsetDistance = p.offset.value_or(_offsetDistance);
|
||||
if (!_useRelativeOffset) {
|
||||
_offsetDistance.setExponent(11.f);
|
||||
}
|
||||
addProperty(_offsetDistance);
|
||||
|
||||
addProperty(_useRelativeLength);
|
||||
addProperty(_useRelativeOffset);
|
||||
}
|
||||
|
||||
void RenderableNodeArrow::initializeGL() {
|
||||
_shaderProgram = BaseModule::ProgramObjectManager.request(
|
||||
"NodeDirectionLineProgram",
|
||||
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
||||
return global::renderEngine->buildRenderProgram(
|
||||
"NodeDirectionLineProgram",
|
||||
absPath("${MODULE_BASE}/shaders/arrow_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/arrow_fs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void RenderableNodeArrow::deinitializeGL() {
|
||||
BaseModule::ProgramObjectManager.release(
|
||||
"NodeDirectionLineProgram",
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
global::renderEngine->removeRenderProgram(p);
|
||||
}
|
||||
);
|
||||
_shaderProgram = nullptr;
|
||||
}
|
||||
|
||||
bool RenderableNodeArrow::isReady() const {
|
||||
return _shaderProgram;
|
||||
}
|
||||
|
||||
void RenderableNodeArrow::updateShapeTransforms(const RenderData& data) {
|
||||
SceneGraphNode* startNode = sceneGraphNode(_start);
|
||||
SceneGraphNode* endNode = sceneGraphNode(_end);
|
||||
|
||||
if (!startNode) {
|
||||
LERROR(fmt::format("Could not find start node '{}'", _start.value()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!endNode) {
|
||||
LERROR(fmt::format("Could not find end node '{}'", _end.value()));
|
||||
return;
|
||||
}
|
||||
|
||||
const double boundingSphere = startNode->boundingSphere();
|
||||
bool hasNoBoundingSphere = boundingSphere < std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (hasNoBoundingSphere && (_useRelativeLength || _useRelativeOffset)) {
|
||||
LERROR(fmt::format(
|
||||
"Node '{}' has no valid bounding sphere. Can not use relative values",
|
||||
_end.value()
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = static_cast<double>(_offsetDistance);
|
||||
if (_useRelativeOffset) {
|
||||
offset *= boundingSphere;
|
||||
}
|
||||
|
||||
double length = static_cast<double>(_length);
|
||||
if (_useRelativeLength) {
|
||||
length *= boundingSphere;
|
||||
}
|
||||
|
||||
// Take additional transformation scale into account
|
||||
const glm::dmat4 s = glm::scale(
|
||||
glm::dmat4(1.0),
|
||||
glm::dvec3(data.modelTransform.scale)
|
||||
);
|
||||
|
||||
// Update the position based on the arrowDirection of the nodes
|
||||
glm::dvec3 startNodePos = startNode->worldPosition();
|
||||
glm::dvec3 endNodePos = endNode->worldPosition();
|
||||
|
||||
glm::dvec3 arrowDirection = glm::normalize(endNodePos - startNodePos);
|
||||
glm::dvec3 startPos = glm::dvec3(startNodePos + offset * arrowDirection);
|
||||
glm::dvec3 endPos = glm::dvec3(startPos + length * arrowDirection);
|
||||
|
||||
if (_invertArrowDirection) {
|
||||
std::swap(startPos, endPos);
|
||||
arrowDirection *= -1.0;
|
||||
}
|
||||
|
||||
double coneLength = _arrowHeadSize * length;
|
||||
double cylinderLength = length - coneLength;
|
||||
double arrowHeadWidth = _width * _arrowHeadWidthFactor;
|
||||
|
||||
// Create transformation matrices to reshape to size and position
|
||||
_cylinderTranslation = glm::translate(glm::dmat4(1.0), startPos);
|
||||
glm::dvec3 cylinderScale = glm::dvec3(s * glm::dvec4(_width, _width, cylinderLength, 0.0));
|
||||
_cylinderScale = glm::scale(glm::dmat4(1.0), cylinderScale);
|
||||
|
||||
// Adapt arrow head start to scaled size
|
||||
glm::dvec3 arrowHeadStartPos = startPos + cylinderScale.z * arrowDirection;
|
||||
|
||||
_coneTranslation = glm::translate(glm::dmat4(1.0), arrowHeadStartPos);
|
||||
glm::dvec3 coneScale = glm::dvec3(arrowHeadWidth, arrowHeadWidth, coneLength);
|
||||
_coneScale = s * glm::scale(glm::dmat4(1.0), coneScale);
|
||||
|
||||
// Rotation to point at the end node
|
||||
glm::quat rotQuat = glm::rotation(glm::dvec3(0.0, 0.0, 1.0), arrowDirection);
|
||||
_pointDirectionRotation = glm::dmat4(glm::toMat4(rotQuat));
|
||||
}
|
||||
|
||||
void RenderableNodeArrow::render(const RenderData& data, RendererTasks&) {
|
||||
updateShapeTransforms(data);
|
||||
|
||||
// Cylinder transforms
|
||||
glm::dmat4 modelTransform =
|
||||
_cylinderTranslation * _pointDirectionRotation * _cylinderScale;
|
||||
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
|
||||
glm::dmat4 normalTransform = glm::transpose(glm::inverse(modelViewTransform));
|
||||
|
||||
_shaderProgram->activate();
|
||||
|
||||
_shaderProgram->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
|
||||
_shaderProgram->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
_shaderProgram->setUniform("normalTransform", glm::mat3(normalTransform));
|
||||
|
||||
_shaderProgram->setUniform("color", _color);
|
||||
_shaderProgram->setUniform("opacity", opacity());
|
||||
|
||||
_shaderProgram->setUniform("ambientIntensity", _shading.ambientIntensity);
|
||||
_shaderProgram->setUniform("diffuseIntensity", _shading.diffuseIntensity);
|
||||
_shaderProgram->setUniform("specularIntensity", _shading.specularIntensity);
|
||||
_shaderProgram->setUniform("performShading", _shading.enabled);
|
||||
|
||||
// Change GL state:
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnablei(GL_BLEND, 0);
|
||||
|
||||
// Draw cylinder
|
||||
glBindVertexArray(rendering::helper::vertexObjects.cylinder.vao);
|
||||
glDrawElements(
|
||||
GL_TRIANGLES,
|
||||
rendering::helper::vertexObjects.cylinder.nElements,
|
||||
GL_UNSIGNED_SHORT,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// Update transforms and render cone
|
||||
modelTransform = _coneTranslation * _pointDirectionRotation * _coneScale;
|
||||
modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
|
||||
normalTransform = glm::transpose(glm::inverse(modelViewTransform));
|
||||
|
||||
_shaderProgram->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
|
||||
_shaderProgram->setUniform("normalTransform", glm::mat3(normalTransform));
|
||||
|
||||
glBindVertexArray(rendering::helper::vertexObjects.cone.vao);
|
||||
glDrawElements(
|
||||
GL_TRIANGLES,
|
||||
rendering::helper::vertexObjects.cone.nElements,
|
||||
GL_UNSIGNED_SHORT,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// Restore GL State
|
||||
glBindVertexArray(0);
|
||||
global::renderEngine->openglStateCache().resetBlendState();
|
||||
|
||||
_shaderProgram->deactivate();
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_BASE___RENDERABLENODEARROW___H__
|
||||
#define __OPENSPACE_MODULE_BASE___RENDERABLENODEARROW___H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/uintproperty.h>
|
||||
#include <openspace/properties/vector/vec3property.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace ghoul::opengl { class ProgramObject; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
class Translation;
|
||||
|
||||
/**
|
||||
* Generates an arrow shape that points from the start node to the
|
||||
* end node
|
||||
*/
|
||||
class RenderableNodeArrow : public Renderable {
|
||||
public:
|
||||
RenderableNodeArrow(const ghoul::Dictionary& dictionary);
|
||||
~RenderableNodeArrow() override = default;
|
||||
|
||||
void initializeGL() override;
|
||||
void deinitializeGL() override;
|
||||
|
||||
bool isReady() const override;
|
||||
void render(const RenderData& data, RendererTasks& rendererTask) override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
struct Shading : properties::PropertyOwner {
|
||||
Shading();
|
||||
properties::BoolProperty enabled;
|
||||
properties::FloatProperty ambientIntensity;
|
||||
properties::FloatProperty diffuseIntensity;
|
||||
properties::FloatProperty specularIntensity;
|
||||
};
|
||||
|
||||
void updateShapeTransforms(const RenderData& data);
|
||||
|
||||
Shading _shading;
|
||||
|
||||
ghoul::opengl::ProgramObject* _shaderProgram;
|
||||
|
||||
properties::StringProperty _start;
|
||||
properties::StringProperty _end;
|
||||
properties::Vec3Property _color;
|
||||
|
||||
properties::UIntProperty _segments;
|
||||
properties::BoolProperty _invertArrowDirection;
|
||||
|
||||
properties::FloatProperty _arrowHeadSize;
|
||||
properties::FloatProperty _arrowHeadWidthFactor;
|
||||
|
||||
properties::FloatProperty _offsetDistance;
|
||||
properties::BoolProperty _useRelativeOffset;
|
||||
properties::FloatProperty _length;
|
||||
properties::BoolProperty _useRelativeLength;
|
||||
properties::FloatProperty _width;
|
||||
|
||||
glm::dmat4 _cylinderTranslation = glm::dmat4(1.0);
|
||||
glm::dmat4 _cylinderScale = glm::dmat4(1.0);
|
||||
|
||||
glm::dmat4 _coneTranslation = glm::dmat4(1.0);
|
||||
glm::dmat4 _coneScale = glm::dmat4(1.0);
|
||||
|
||||
glm::dmat4 _pointDirectionRotation = glm::dmat4(1.0);
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_BASE___RENDERABLENODEARROW___H__
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/rendering/helper.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
@@ -98,20 +99,6 @@ namespace {
|
||||
openspace::properties::Property::Visibility::User
|
||||
};
|
||||
|
||||
// Generate vertices around the unit circle on the XY-plane
|
||||
std::vector<float> unitCircleVertices(int sectorCount) {
|
||||
std::vector<float> vertices;
|
||||
vertices.reserve(2 * sectorCount);
|
||||
float sectorStep = glm::two_pi<float>() / sectorCount;
|
||||
|
||||
for (int i = 0; i < sectorCount; ++i) {
|
||||
float sectorAngle = i * sectorStep;
|
||||
vertices.push_back(cos(sectorAngle)); // x
|
||||
vertices.push_back(sin(sectorAngle)); // y
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
|
||||
struct [[codegen::Dictionary(RenderablePrism)]] Parameters {
|
||||
// [[codegen::verbatim(SegmentsInfo.description)]]
|
||||
int segments;
|
||||
@@ -236,17 +223,16 @@ void RenderablePrism::updateVertexData() {
|
||||
_vertexArray.clear();
|
||||
_indexArray.clear();
|
||||
|
||||
using namespace rendering::helper;
|
||||
|
||||
// Get unit circle vertices on the XY-plane
|
||||
std::vector<float> unitVertices = unitCircleVertices(_nShapeSegments);
|
||||
std::vector<float> unitVerticesLines = unitCircleVertices(_nLines);
|
||||
std::vector<VertexXYZ> unitVertices = createRingXYZ(_nShapeSegments.value(), 1.f);
|
||||
std::vector<VertexXYZ> unitVerticesLines = createRingXYZ(_nLines.value(), 1.f);
|
||||
|
||||
// Put base vertices into array
|
||||
for (int j = 0, k = 0;
|
||||
j < _nShapeSegments && k < static_cast<int>(unitVertices.size());
|
||||
++j, k += 2)
|
||||
{
|
||||
float ux = unitVertices[k];
|
||||
float uy = unitVertices[k + 1];
|
||||
for (int j = 0; j < _nShapeSegments; ++j) {
|
||||
float ux = unitVertices[j].xyz[0];
|
||||
float uy = unitVertices[j].xyz[1];
|
||||
|
||||
_vertexArray.push_back(ux * _baseRadius); // x
|
||||
_vertexArray.push_back(uy * _baseRadius); // y
|
||||
@@ -254,12 +240,9 @@ void RenderablePrism::updateVertexData() {
|
||||
}
|
||||
|
||||
// Put top shape vertices into array
|
||||
for (int j = 0, k = 0;
|
||||
j < _nShapeSegments && k < static_cast<int>(unitVertices.size());
|
||||
++j, k += 2)
|
||||
{
|
||||
float ux = unitVertices[k];
|
||||
float uy = unitVertices[k + 1];
|
||||
for (int j = 0; j < _nShapeSegments; ++j) {
|
||||
float ux = unitVertices[j].xyz[0];
|
||||
float uy = unitVertices[j].xyz[1];
|
||||
|
||||
_vertexArray.push_back(ux * _radius); // x
|
||||
_vertexArray.push_back(uy * _radius); // y
|
||||
@@ -280,12 +263,9 @@ void RenderablePrism::updateVertexData() {
|
||||
_vertexArray.push_back(_length);
|
||||
}
|
||||
else {
|
||||
for (int j = 0, k = 0;
|
||||
j < _nLines && k < static_cast<int>(unitVerticesLines.size());
|
||||
++j, k += 2)
|
||||
{
|
||||
float ux = unitVerticesLines[k];
|
||||
float uy = unitVerticesLines[k + 1];
|
||||
for (int j = 0; j < _nLines; ++j) {
|
||||
float ux = unitVerticesLines[j].xyz[0];
|
||||
float uy = unitVerticesLines[j].xyz[1];
|
||||
|
||||
// Base
|
||||
_vertexArray.push_back(ux * _baseRadius); // x
|
||||
|
||||
Reference in New Issue
Block a user