Feature/interactionsphere (#1561)

* Add ability to render the bounding sphere as a debug option
* Separate boundingsphere and interactionspheres
* Correctly compute BoundingSpheres for more renderables (RenderablePlanesCloud, RenderableOrbitalKepler)
This commit is contained in:
Alexander Bock
2021-04-26 13:13:36 +02:00
committed by GitHub
parent 32b6a69900
commit 2aa540a112
30 changed files with 566 additions and 210 deletions
@@ -24,7 +24,7 @@ local initializeAndAddNodes = function()
local iss = {
Identifier = "ISS",
Parent = transforms.EarthInertial.Identifier,
BoundingSphere = 30,
InteractionSphere = 30,
Transform = {
Translation = {
Type = "TLETranslation",
@@ -19,7 +19,7 @@ asset.onInitialize(function ()
local Aqua = {
Identifier = "Aqua",
Parent = transforms.EarthInertial.Identifier,
BoundingSphere = 30,
InteractionSphere = 30,
Transform = {
Translation = {
Type = "TLETranslation",
@@ -19,7 +19,7 @@ asset.onInitialize(function ()
local SNPP = {
Identifier = "SNPP",
Parent = transforms.EarthInertial.Identifier,
BoundingSphere = 30,
InteractionSphere = 30,
Transform = {
Translation = {
Type = "TLETranslation",
@@ -19,7 +19,7 @@ asset.onInitialize(function ()
local Terra = {
Identifier = "Terra",
Parent = transforms.EarthInertial.Identifier,
BoundingSphere = 30,
InteractionSphere = 30,
Transform = {
Translation = {
Type = "TLETranslation",
+13 -2
View File
@@ -61,12 +61,12 @@ void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4
struct Shaders {
struct {
std::unique_ptr<ghoul::opengl::ProgramObject> program;
UniformCache(tex, hasTexture, shouldFlipTexture, ortho, color) cache;
UniformCache(tex, hasTexture, shouldFlipTexture, proj, color) cache;
} xyuvrgba;
struct {
std::unique_ptr<ghoul::opengl::ProgramObject> program;
UniformCache(tex, hasTexture, shouldFlipTexture, ortho, color) cache;
UniformCache(tex, hasTexture, shouldFlipTexture, proj, color) cache;
} screenfilling;
};
@@ -76,6 +76,14 @@ struct VertexObjects {
GLuint vbo;
} square;
struct {
GLuint vao;
GLuint vbo;
GLuint ibo;
int nElements = 64;
} sphere;
struct {
GLuint vao;
} empty;
@@ -108,6 +116,9 @@ std::vector<VertexXYZ> convert(std::vector<Vertex> v);
std::vector<Vertex> createRing(int nSegments, float radius,
glm::vec4 colors = glm::vec4(1.f));
std::pair<std::vector<Vertex>, std::vector<GLushort>>
createSphere(int nSegments, glm::vec3 radii, glm::vec4 colors = glm::vec4(1.f));
} // namespace openspace::rendering::helper
#endif // __OPENSPACE_CORE___HELPER___H__
+20 -3
View File
@@ -31,6 +31,7 @@
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
namespace ghoul { class Dictionary; }
@@ -75,11 +76,17 @@ public:
bool isEnabled() const;
bool shouldUpdateIfDisabled() const;
void setBoundingSphere(double boundingSphere);
double boundingSphere() const;
double interactionSphere() const;
virtual void render(const RenderData& data, RendererTasks& rendererTask);
virtual void update(const UpdateData& data);
// The 'surface' in this case is the interaction sphere of this renderable. In some
// cases (i.e., planets) this corresponds directly to the physical surface, but in
// many cases, models, volumetric data, this will not. Regardless of what the physical
// representation is, the 'surface' is always the sphere around which interaction is
// handled
virtual SurfacePositionHandle calculateSurfacePositionHandle(
const glm::dvec3& targetModelSpace) const;
@@ -98,15 +105,25 @@ public:
protected:
properties::BoolProperty _enabled;
properties::FloatProperty _opacity;
properties::DoubleProperty _boundingSphere;
properties::StringProperty _renderableType;
bool _shouldUpdateIfDisabled = false;
void setBoundingSphere(double boundingSphere);
void setRenderBinFromOpacity();
void registerUpdateRenderBinFromOpacity();
double _boundingSphere = 0.0;
double _interactionSphere = 0.0;
SceneGraphNode* _parent = nullptr;
bool _shouldUpdateIfDisabled = false;
private:
// We only want the SceneGraphNode to be able manipulate the parent, so we don't want
// to provide a set method for this. Otherwise, anyone might mess around with our
// parentage and that's no bueno
friend ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
const ghoul::Dictionary&);
RenderBin _renderBin = RenderBin::Opaque;
};
+12 -1
View File
@@ -36,14 +36,16 @@
#include <ghoul/misc/boolean.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <vector>
#include <chrono>
//#define Debugging_Core_SceneGraphNode_Indices
namespace ghoul { class Dictionary; }
namespace ghoul::opengl { class ProgramObject; }
namespace openspace {
@@ -127,6 +129,7 @@ public:
std::vector<SceneGraphNode*> children() const;
double boundingSphere() const;
double interactionSphere() const;
SceneGraphNode* childNode(const std::string& identifier);
@@ -143,6 +146,7 @@ private:
glm::dmat3 calculateWorldRotation() const;
glm::dvec3 calculateWorldScale() const;
void computeScreenSpaceData(RenderData& newData);
void renderDebugSphere(const Camera& camera, double size, glm::vec4 color);
std::atomic<State> _state = State::Loaded;
std::vector<ghoul::mm_unique_ptr<SceneGraphNode>> _children;
@@ -178,6 +182,7 @@ private:
glm::dmat4 _modelTransformCached = glm::dmat4(1.0);
properties::DoubleProperty _boundingSphere;
properties::DoubleProperty _interactionSphere;
properties::BoolProperty _computeScreenSpaceValues;
properties::IVec2Property _screenSpacePosition;
properties::BoolProperty _screenVisibility;
@@ -189,6 +194,12 @@ private:
// are calculated when _computeScreenSpaceValues is true)
std::chrono::high_resolution_clock::time_point _lastScreenSpaceUpdateTime;
properties::BoolProperty _showDebugSphere;
static ghoul::opengl::ProgramObject* _debugSphereProgram;
std::optional<double> _overrideBoundingSphere;
std::optional<double> _overrideInteractionSphere;
#ifdef Debugging_Core_SceneGraphNode_Indices
int index = 0;
static int nextIndex;
+1 -1
View File
@@ -50,7 +50,7 @@ struct UpdateData {
struct RenderData {
const Camera& camera;
const Time time;
int renderBinMask = -1;
int8_t renderBinMask = -1;
TransformData modelTransform;
};
@@ -381,6 +381,8 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary)
_hardShadowsEnabled.onChange(updateWithoutCalculation);
addProperty(_hardShadowsEnabled);
}
setBoundingSphere(_planetRadius * 1000.0);
}
void RenderableAtmosphere::deinitializeGL() {
+5 -1
View File
@@ -215,8 +215,11 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary)
}
addProperty(_orientation);
_size.onChange([this]() {
setBoundingSphere(_size);
_sphereIsDirty = true;
});
addProperty(_size);
_size.onChange([this]() { _sphereIsDirty = true; });
addProperty(_segments);
_segments.onChange([this]() { _sphereIsDirty = true; });
@@ -257,6 +260,7 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary)
setRenderBin(Renderable::RenderBin::Background);
}
setBoundingSphere(_size);
setRenderBinFromOpacity();
}
@@ -767,31 +767,6 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data,
const glm::dvec3& orthoUp,
float fadeInVariable)
{
float scale = 0.f;
switch (_unit) {
case Meter:
scale = 1.f;
break;
case Kilometer:
scale = 1e3f;
break;
case Parsec:
scale = static_cast<float>(PARSEC);
break;
case Kiloparsec:
scale = static_cast<float>(1e3 * PARSEC);
break;
case Megaparsec:
scale = static_cast<float>(1e6 * PARSEC);
break;
case Gigaparsec:
scale = static_cast<float>(1e9 * PARSEC);
break;
case GigalightYears:
scale = static_cast<float>(306391534.73091 * PARSEC);
break;
}
glm::vec4 textColor = glm::vec4(
glm::vec3(_textColor),
_textOpacity * fadeInVariable
@@ -813,7 +788,7 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data,
for (const std::pair<glm::vec3, std::string>& pair : _labelData) {
//glm::vec3 scaledPos(_transformationMatrix * glm::dvec4(pair.first, 1.0));
glm::vec3 scaledPos(pair.first);
scaledPos *= scale;
scaledPos *= unitToMeter(_unit);
ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render(
*_font,
scaledPos,
@@ -825,36 +800,11 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data,
}
void RenderableBillboardsCloud::render(const RenderData& data, RendererTasks&) {
float scale = 0.f;
switch (_unit) {
case Meter:
scale = 1.f;
break;
case Kilometer:
scale = 1e3f;
break;
case Parsec:
scale = static_cast<float>(PARSEC);
break;
case Kiloparsec:
scale = static_cast<float>(1e3 * PARSEC);
break;
case Megaparsec:
scale = static_cast<float>(1e6 * PARSEC);
break;
case Gigaparsec:
scale = static_cast<float>(1e9 * PARSEC);
break;
case GigalightYears:
scale = static_cast<float>(306391534.73091 * PARSEC);
break;
}
float fadeInVariable = 1.f;
if (!_disableFadeInDistance) {
float distCamera = static_cast<float>(glm::length(data.camera.positionVec3()));
const glm::vec2 fadeRange = _fadeInDistance;
const float a = 1.f / ((fadeRange.y - fadeRange.x) * scale);
const float a = 1.f / ((fadeRange.y - fadeRange.x) * unitToMeter(_unit));
const float b = -(fadeRange.x / (fadeRange.y - fadeRange.x));
const float funcValue = a * distCamera + b;
fadeInVariable *= funcValue > 1.f ? 1.f : funcValue;
@@ -1488,6 +1438,19 @@ bool RenderableBillboardsCloud::saveCachedFile(const std::string& file) const {
return fileStream.good();
}
double RenderableBillboardsCloud::unitToMeter(Unit unit) const {
switch (_unit) {
case Meter: return 1.0;
case Kilometer: return 1e3;
case Parsec: return PARSEC;
case Kiloparsec: return 1000 * PARSEC;
case Megaparsec: return 1e6 * PARSEC;
case Gigaparsec: return 1e9 * PARSEC;
case GigalightYears: return 306391534.73091 * PARSEC;
default: throw ghoul::MissingCaseException();
}
}
void RenderableBillboardsCloud::createDataSlice() {
ZoneScoped
@@ -1516,7 +1479,7 @@ void RenderableBillboardsCloud::createDataSlice() {
_slicedData.push_back(_fullData[i + 3 + datavarInUse]);
};
auto addPosition = [&](const glm::vec4 &pos) {
auto addPosition = [&](const glm::vec4& pos) {
for (int j = 0; j < 4; ++j) {
_slicedData.push_back(pos[j]);
}
@@ -1531,17 +1494,24 @@ void RenderableBillboardsCloud::createDataSlice() {
minColorIdx = colorIdx < minColorIdx ? colorIdx : minColorIdx;
}
double maxRadius = 0.0;
float biggestCoord = -1.f;
for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) {
glm::dvec4 transformedPos = _transformationMatrix * glm::dvec4(
glm::vec3 transformedPos = glm::vec3(_transformationMatrix * glm::vec4(
_fullData[i + 0],
_fullData[i + 1],
_fullData[i + 2],
1.0
);
// W-normalization
transformedPos /= transformedPos.w;
glm::vec4 position(glm::vec3(transformedPos), static_cast<float>(_unit));
));
glm::vec4 position(transformedPos, static_cast<float>(_unit));
const double unitMeter = unitToMeter(_unit);
glm::dvec3 p = glm::dvec3(position) * unitMeter;
const double r = glm::length(p);
if (r > maxRadius) {
maxRadius = r;
}
if (_hasColorMapFile) {
for (int j = 0; j < 4; ++j) {
@@ -1623,6 +1593,7 @@ void RenderableBillboardsCloud::createDataSlice() {
addPosition(position);
}
}
setBoundingSphere(maxRadius);
_fadeInDistance.setMaxValue(glm::vec2(10.f * biggestCoord));
}
@@ -76,6 +76,7 @@ private:
Gigaparsec = 5,
GigalightYears = 6
};
double unitToMeter(Unit unit) const;
void createDataSlice();
void createPolygonTexture();
@@ -572,35 +572,12 @@ void RenderablePlanesCloud::renderLabels(const RenderData& data,
}
void RenderablePlanesCloud::render(const RenderData& data, RendererTasks&) {
float scale = 0.f;
switch (_unit) {
case Meter:
scale = 1.f;
break;
case Kilometer:
scale = 1e3f;
break;
case Parsec:
scale = static_cast<float>(PARSEC);
break;
case Kiloparsec:
scale = static_cast<float>(1e3 * PARSEC);
break;
case Megaparsec:
scale = static_cast<float>(1e6 * PARSEC);
break;
case Gigaparsec:
scale = static_cast<float>(1e9 * PARSEC);
break;
case GigalightYears:
scale = static_cast<float>(306391534.73091 * PARSEC);
break;
}
const double scale = unitToMeter(_unit);
float fadeInVariable = 1.f;
if (!_disableFadeInDistance) {
float distCamera = static_cast<float>(glm::length(data.camera.positionVec3()));
distCamera /= scale;
distCamera = static_cast<float>(distCamera / scale);
const glm::vec2 fadeRange = _fadeInDistance;
//const float a = 1.f / ((fadeRange.y - fadeRange.x) * scale);
const float a = 1.f / ((fadeRange.y - fadeRange.x));
@@ -1095,16 +1072,37 @@ bool RenderablePlanesCloud::saveCachedFile(const std::string& file) const {
}
}
double RenderablePlanesCloud::unitToMeter(Unit unit) const {
switch (_unit) {
case Meter: return 1.0;
case Kilometer: return 1e3;
case Parsec: return PARSEC;
case Kiloparsec: return 1000 * PARSEC;
case Megaparsec: return 1e6 * PARSEC;
case Gigaparsec: return 1e9 * PARSEC;
case GigalightYears: return 306391534.73091 * PARSEC;
default: throw ghoul::MissingCaseException();
}
}
void RenderablePlanesCloud::createPlanes() {
if (_dataIsDirty && _hasSpeckFile) {
const double scale = unitToMeter(_unit);
LDEBUG("Creating planes...");
float maxSize = 0.f;
double maxRadius = 0.0;
for (size_t p = 0; p < _fullData.size(); p += _nValuesPerAstronomicalObject) {
const glm::vec4 transformedPos = glm::vec4(
_transformationMatrix *
glm::dvec4(_fullData[p + 0], _fullData[p + 1], _fullData[p + 2], 1.0)
);
const double r = glm::length(glm::dvec3(transformedPos) * scale);
if (r > maxRadius) {
maxRadius = r;
}
// Plane vectors u and v
glm::vec4 u = glm::vec4(
_transformationMatrix *
@@ -1145,31 +1143,6 @@ void RenderablePlanesCloud::createPlanes() {
glm::vec4 vertex2 = transformedPos - u + v;
glm::vec4 vertex4 = transformedPos + u - v;
float scale = 0.f;
switch (_unit) {
case Meter:
scale = 1.f;
break;
case Kilometer:
scale = 1e3f;
break;
case Parsec:
scale = static_cast<float>(PARSEC);
break;
case Kiloparsec:
scale = static_cast<float>(1e3 * PARSEC);
break;
case Megaparsec:
scale = static_cast<float>(1e6 * PARSEC);
break;
case Gigaparsec:
scale = static_cast<float>(1e9 * PARSEC);
break;
case GigalightYears:
scale = static_cast<float>(306391534.73091 * PARSEC);
break;
}
for (int i = 0; i < 3; ++i) {
maxSize = std::max(maxSize, vertex0[i]);
maxSize = std::max(maxSize, vertex1[i]);
@@ -1252,6 +1225,7 @@ void RenderablePlanesCloud::createPlanes() {
_dataIsDirty = false;
setBoundingSphere(maxRadius * _scaleFactor);
_fadeInDistance.setMaxValue(glm::vec2(10.f * maxSize));
}
@@ -80,6 +80,7 @@ private:
Gigaparsec = 5,
GigalightYears = 6
};
double unitToMeter(Unit unit) const;
struct PlaneAggregate {
int textureIndex;
+11 -6
View File
@@ -544,12 +544,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
if (p.radii.has_value()) {
if (std::holds_alternative<glm::dvec3>(*p.radii)) {
_ellipsoid = Ellipsoid(std::get<glm::dvec3>(*p.radii));
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
setBoundingSphere(_ellipsoid.maximumRadius());
}
else if (std::holds_alternative<double>(*p.radii)) {
const double radius = std::get<double>(*p.radii);
_ellipsoid = Ellipsoid({ radius, radius, radius });
setBoundingSphere(static_cast<float>(_ellipsoid.maximumRadius()));
setBoundingSphere(_ellipsoid.maximumRadius());
}
else {
throw ghoul::MissingCaseException();
@@ -843,9 +843,14 @@ void RenderableGlobe::update(const UpdateData& data) {
);
}
setBoundingSphere(static_cast<float>(
_ellipsoid.maximumRadius() * glm::compMax(data.modelTransform.scale)
));
double bs = _ellipsoid.maximumRadius() * glm::compMax(data.modelTransform.scale);
if (_hasRings) {
const double ringSize = _ringsComponent.size();
if (ringSize > bs) {
bs = ringSize;
}
}
setBoundingSphere(bs);
glm::dmat4 translation =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation);
@@ -1831,7 +1836,7 @@ SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle(
double heightToSurface = getHeight(targetModelSpace);
heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface;
centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ?
(glm::dvec3(0.0, 1.0, 0.0) * static_cast<double>(boundingSphere())) :
(glm::dvec3(0.0, 1.0, 0.0) * interactionSphere()) :
centerToEllipsoidSurface;
ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ?
glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection;
@@ -866,4 +866,8 @@ bool RingsComponent::isEnabled() const {
return _enabled;
}
double RingsComponent::size() const {
return _size;
}
} // namespace openspace
@@ -71,6 +71,7 @@ public:
static documentation::Documentation Documentation();
bool isEnabled() const;
double size() const;
private:
void loadTexture();
@@ -143,6 +143,7 @@ RenderableHabitableZone::RenderableHabitableZone(const ghoul::Dictionary& dictio
_width.setReadOnly(true);
computeZone();
setBoundingSphere(_size);
}
void RenderableHabitableZone::render(const RenderData& data, RendererTasks&) {
@@ -476,6 +476,14 @@ void RenderableOrbitalKepler::initializeGL() {
_uniformCache.opacity = _programObject->uniformLocation("opacity");
updateBuffers();
double maxSemiMajorAxis = 0.0;
for (const KeplerParameters& kp : _data) {
if (kp.semiMajorAxis > maxSemiMajorAxis) {
maxSemiMajorAxis = kp.semiMajorAxis;
}
}
setBoundingSphere(maxSemiMajorAxis * 1000);
}
void RenderableOrbitalKepler::deinitializeGL() {
+30 -5
View File
@@ -1486,14 +1486,21 @@ void RenderableStars::createDataSlice(ColorOption option) {
-std::numeric_limits<float>::max()
);
double maxRadius = 0.0;
for (size_t i = 0; i < _fullData.size(); i += _nValuesPerStar) {
glm::vec3 position = glm::vec3(
glm::dvec3 position = glm::dvec3(
_fullData[i + 0],
_fullData[i + 1],
_fullData[i + 2]
);
position *= openspace::distanceconstants::Parsec;
const double r = glm::length(position);
if (r > maxRadius) {
maxRadius = r;
}
switch (option) {
case ColorOption::Color:
case ColorOption::FixedColor:
@@ -1503,7 +1510,11 @@ void RenderableStars::createDataSlice(ColorOption option) {
std::array<float, sizeof(ColorVBOLayout) / sizeof(float)> data;
} layout;
layout.value.position = { { position[0], position[1], position[2] } };
layout.value.position = { {
static_cast<float>(position[0]),
static_cast<float>(position[1]),
static_cast<float>(position[2])
}};
if (_enableTestGrid) {
float sunColor = 0.650f;
@@ -1531,7 +1542,11 @@ void RenderableStars::createDataSlice(ColorOption option) {
std::array<float, sizeof(VelocityVBOLayout) / sizeof(float)> data;
} layout;
layout.value.position = { { position[0], position[1], position[2] } };
layout.value.position = {{
static_cast<float>(position[0]),
static_cast<float>(position[1]),
static_cast<float>(position[2])
}};
layout.value.value = _fullData[i + _bvColorArrayPos];
layout.value.luminance = _fullData[i + _lumArrayPos];
@@ -1556,7 +1571,11 @@ void RenderableStars::createDataSlice(ColorOption option) {
std::array<float, sizeof(SpeedVBOLayout) / sizeof(float)> data;
} layout;
layout.value.position = { { position[0], position[1], position[2] } };
layout.value.position = {{
static_cast<float>(position[0]),
static_cast<float>(position[1]),
static_cast<float>(position[2])
}};
layout.value.value = _fullData[i + _bvColorArrayPos];
layout.value.luminance = _fullData[i + _lumArrayPos];
@@ -1579,7 +1598,11 @@ void RenderableStars::createDataSlice(ColorOption option) {
std::array<float, sizeof(OtherDataLayout)> data;
} layout = {};
layout.value.position = { { position[0], position[1], position[2] } };
layout.value.position = {{
static_cast<float>(position[0]),
static_cast<float>(position[1]),
static_cast<float>(position[2])
}};
int index = _otherDataOption.value();
// plus 3 because of the position
@@ -1612,6 +1635,8 @@ void RenderableStars::createDataSlice(ColorOption option) {
}
}
}
setBoundingSphere(maxRadius);
}
} // namespace openspace
+1 -1
View File
@@ -146,7 +146,7 @@ void gradient(double* g, double* par, int x, void* fdata, LMstat* lmstat) {
FunctionData* ptr = reinterpret_cast<FunctionData*>(fdata);
double f0 = distToMinimize(par, x, fdata, lmstat);
// scale value to find minimum step size h, dependant on planet size
double scale = log10(ptr->node->boundingSphere());
double scale = log10(ptr->node->interactionSphere());
std::vector<double> dPar(ptr->nDOF, 0.0);
dPar.assign(par, par + ptr->nDOF);
+9 -9
View File
@@ -507,15 +507,15 @@ void TouchInteraction::findSelectedNode(const std::vector<TouchInputHolder>& lis
size_t id = inputHolder.fingerId();
for (SceneGraphNode* node : selectableNodes) {
double boundingSphereSquared = static_cast<double>(node->boundingSphere()) *
static_cast<double>(node->boundingSphere());
double interactionSphereSquared =
node->interactionSphere() * node->interactionSphere();
glm::dvec3 camToSelectable = node->worldPosition() - camPos;
double intersectionDist = 0.0;
const bool intersected = glm::intersectRaySphere(
camPos,
raytrace,
node->worldPosition(),
boundingSphereSquared,
interactionSphereSquared,
intersectionDist
);
if (intersected) {
@@ -921,7 +921,7 @@ double TouchInteraction::computeTapZoomDistance(double zoomGain) {
global::navigationHandler->orbitalNavigator().anchorNode()->worldPosition()
);
dist -= anchor->boundingSphere();
dist -= anchor->interactionSphere();
double newVelocity = dist * _tapZoomFactor;
newVelocity *= std::max(_touchScreenSize.value() * 0.1, 1.0);
@@ -962,9 +962,9 @@ void TouchInteraction::step(double dt, bool directTouch) {
dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat)));
dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion();
const double boundingSphere = anchor->boundingSphere();
const double distance = std::max(length(centerToCamera) - boundingSphere, 0.0);
_currentRadius = boundingSphere /
const double interactionSphere = anchor->interactionSphere();
const double distance = std::max(length(centerToCamera) - interactionSphere, 0.0);
_currentRadius = interactionSphere /
std::max(distance * _projectionScaleFactor, 1.0);
{
@@ -1010,7 +1010,7 @@ void TouchInteraction::step(double dt, bool directTouch) {
// This is a rough estimate of the node surface
// If nobody has set another zoom in limit, use this as default zoom in bounds
double zoomInBounds = boundingSphere * _zoomBoundarySphereMultiplier;
double zoomInBounds = interactionSphere * _zoomBoundarySphereMultiplier;
bool isZoomInLimitSet = (_zoomInLimit.value() >= 0.0);
if (isZoomInLimitSet && _zoomInLimit.value() < zoomInBounds) {
@@ -1049,7 +1049,7 @@ void TouchInteraction::step(double dt, bool directTouch) {
double zoomVelocity = _vel.zoom;
if (!directTouch) {
const double distanceFromSurface =
length(currentPosDistance) - anchor->boundingSphere();
length(currentPosDistance) - anchor->interactionSphere();
if (distanceFromSurface > 0.1) {
const double ratioOfDistanceToNodeVsSurf =
length(currentPosDistance) / distanceFromSurface;
+54
View File
@@ -0,0 +1,54 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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"
uniform bool hasTexture = false;
uniform bvec2 shouldFlipTexture = bvec2(false, false);
uniform sampler2D tex;
uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
in float depth;
in vec2 out_uv;
in vec4 out_color;
Fragment getFragment() {
Fragment frag;
if (hasTexture) {
vec2 uv = out_uv;
if (shouldFlipTexture.x) {
uv.x = 1.0 - uv.x;
}
if (shouldFlipTexture.y) {
uv.y = 1.0 - uv.y;
}
frag.color = out_color * color * texture(tex, uv);
}
else {
frag.color = out_color * color;
}
frag.depth = depth;
return frag;
}
+43
View File
@@ -0,0 +1,43 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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 vec3 in_position;
layout(location = 1) in vec2 in_uv;
layout(location = 2) in vec4 in_color;
out float depth;
out vec2 out_uv;
out vec4 out_color;
uniform mat4 proj;
void main() {
out_uv = in_uv;
out_color = in_color;
vec4 p = proj * vec4(in_position, 1.0);
gl_Position = p;
depth = p.w;
}
+2 -3
View File
@@ -416,8 +416,6 @@ void OpenSpaceEngine::initializeGL() {
glbinding::Binding::initialize(global::windowDelegate->openGLProcedureAddress);
//glbinding::Binding::useCurrentContext();
rendering::helper::initialize();
LDEBUG("Adding system components");
// Detect and log OpenCL and OpenGL versions and available devices
SysCap.addComponent(
@@ -427,7 +425,6 @@ void OpenSpaceEngine::initializeGL() {
std::make_unique<ghoul::systemcapabilities::OpenGLCapabilitiesComponent>()
);
// @BUG: This will call OpenGL functions, should it should be in the initializeGL
LDEBUG("Detecting capabilities");
SysCap.detectCapabilities();
@@ -467,6 +464,8 @@ void OpenSpaceEngine::initializeGL() {
}
}
rendering::helper::initialize();
loadFonts();
_loadingScreen = std::make_unique<LoadingScreen>(
+2 -2
View File
@@ -459,8 +459,8 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
if (_applyLinearFlight) {
// Calculate a position handle based on the camera position in world space
glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos;
// Use the boundingsphere to get an approximate distance to the node surface
double nodeRadius = static_cast<double>(_anchorNode->boundingSphere());
// Use the interaction sphere to get an approximate distance to the node surface
double nodeRadius = static_cast<double>(_anchorNode->interactionSphere());
double distFromCameraToFocus =
glm::distance(prevCameraPosition, anchorPos) - nodeRadius;
+130 -15
View File
@@ -53,17 +53,20 @@ layout(location = 0) in vec2 in_position;
layout(location = 1) in vec2 in_uv;
layout(location = 2) in vec4 in_color;
out float depth;
out vec2 out_position;
out vec2 out_uv;
out vec4 out_color;
uniform mat4 ortho;
uniform mat4 proj;
void main() {
out_position = in_position;
out_uv = in_uv;
out_color = in_color;
gl_Position = ortho * vec4(in_position, 0.0, 1.0);
vec4 p = proj * vec4(in_position, 0.0, 1.0);
gl_Position = p;
depth = p.w;
}
)";
@@ -90,11 +93,14 @@ void main() {
constexpr const char* XyuvrgbaFragmentCode = R"(
#version __CONTEXT__
#include "fragment.glsl"
uniform bool hasTexture = false;
uniform bvec2 shouldFlipTexture = bvec2(false, false);
uniform sampler2D tex;
uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
in float depth;
in vec2 out_uv;
in vec4 out_color;
@@ -119,6 +125,7 @@ void main() {
} // namespace
#pragma optimize ("", off)
namespace openspace::rendering::helper {
namespace detail {
@@ -150,7 +157,6 @@ void initialize() {
vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
vertexFile.open(xyuvrgbaVertexFile, std::fstream::out);
vertexFile << XyuvrgbaVertexCode;
vertexFile.close();
}
xyuvrgbaFragmentFile = absPath("${TEMPORARY}/xyuvrgba.frag");
@@ -159,13 +165,17 @@ void initialize() {
fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fragmentFile.open(xyuvrgbaFragmentFile, std::fstream::out);
fragmentFile << XyuvrgbaFragmentCode;
fragmentFile.close();
}
shaders.xyuvrgba.program = ghoul::opengl::ProgramObject::Build(
"xyuvrgba", xyuvrgbaVertexFile, xyuvrgbaFragmentFile);
ghoul::opengl::updateUniformLocations(*shaders.xyuvrgba.program,
"xyuvrgba",
xyuvrgbaVertexFile,
xyuvrgbaFragmentFile
);
ghoul::opengl::updateUniformLocations(
*shaders.xyuvrgba.program,
shaders.xyuvrgba.cache,
{ "tex", "hasTexture", "shouldFlipTexture", "ortho", "color" });
{ "tex", "hasTexture", "shouldFlipTexture", "proj", "color" }
);
//
// Screenfilling shader
@@ -176,7 +186,6 @@ void initialize() {
vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
vertexFile.open(screenFillingVertexFile, std::fstream::out);
vertexFile << ScreenFillingQuadVertexCode;
vertexFile.close();
}
screenFillingFragmentFile = absPath("${TEMPORARY}/screenfilling.frag");
@@ -185,14 +194,18 @@ void initialize() {
fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fragmentFile.open(screenFillingFragmentFile, std::fstream::out);
fragmentFile << XyuvrgbaFragmentCode;
fragmentFile.close();
}
shaders.screenfilling.program = ghoul::opengl::ProgramObject::Build(
"screenfilling", xyuvrgbaVertexFile, xyuvrgbaFragmentFile);
ghoul::opengl::updateUniformLocations(*shaders.screenfilling.program,
"screenfilling",
xyuvrgbaVertexFile,
xyuvrgbaFragmentFile
);
ghoul::opengl::updateUniformLocations(
*shaders.screenfilling.program,
shaders.screenfilling.cache,
{ "tex", "hasTexture", "shouldFlipTexture", "ortho", "color" });
{ "tex", "hasTexture", "shouldFlipTexture", "proj", "color" }
);
//
@@ -231,6 +244,45 @@ void initialize() {
reinterpret_cast<GLvoid*>(offsetof(VertexXYUVRGBA, rgba)));
glBindVertexArray(0);
//
// Sphere vertex array object
//
std::pair<std::vector<Vertex>, std::vector<GLushort>> sphereData = createSphere(
64, glm::vec3(1.f, 1.f, 1.f), glm::vec4(1.f, 1.f, 1.f, 1.f)
);
glGenVertexArrays(1, &vertexObjects.sphere.vao);
glGenBuffers(1, &vertexObjects.sphere.vbo);
glGenBuffers(1, &vertexObjects.sphere.ibo);
glBindVertexArray(vertexObjects.sphere.vao);
glBindBuffer(GL_ARRAY_BUFFER, vertexObjects.sphere.vbo);
glBufferData(
GL_ARRAY_BUFFER,
sphereData.first.size() * sizeof(Vertex),
sphereData.first.data(),
GL_STATIC_DRAW
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexObjects.sphere.ibo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sphereData.second.size() * sizeof(GLushort),
sphereData.second.data(),
GL_STATIC_DRAW
);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(Vertex, uv)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(offsetof(Vertex, rgba)));
glBindVertexArray(0);
vertexObjects.sphere.nElements = static_cast<int>(sphereData.second.size());
//
// Empty vertex array objects
//
@@ -262,6 +314,10 @@ void deinitialize() {
glDeleteVertexArrays(1, &vertexObjects.square.vao);
glDeleteBuffers(1, &vertexObjects.square.vbo);
glDeleteVertexArrays(1, &vertexObjects.sphere.vao);
glDeleteBuffers(1, &vertexObjects.sphere.vbo);
glDeleteBuffers(1, &vertexObjects.sphere.ibo);
glDeleteVertexArrays(1, &vertexObjects.empty.vao);
isInitialized = false;
@@ -316,14 +372,14 @@ void renderBox(ghoul::opengl::ProgramObject& program, GLint orthoLocation,
}
void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color,
Anchor anchor)
Anchor anchor)
{
auto& shdr = shaders.xyuvrgba;
shdr.program->activate();
shdr.program->setUniform(shdr.cache.hasTexture, 0);
renderBox(
*shdr.program,
shdr.cache.ortho,
shdr.cache.proj,
shdr.cache.color,
position, size,
color,
@@ -345,7 +401,7 @@ void renderBox(const glm::vec2& position, const glm::vec2& size, const glm::vec4
shdr.program->setUniform(shdr.cache.tex, unit);
renderBox(
*shdr.program,
shdr.cache.ortho,
shdr.cache.proj,
shdr.cache.color,
position,
size,
@@ -388,4 +444,63 @@ std::vector<Vertex> createRing(int nSegments, float radius, glm::vec4 colors) {
return vertices;
}
std::pair<std::vector<Vertex>, std::vector<GLushort>> createSphere(int nSegments,
glm::vec3 radii,
glm::vec4 colors)
{
std::vector<Vertex> vertices;
vertices.reserve(nSegments * nSegments);
for (int i = 0; i <= nSegments; i++) {
for (int j = 0; j <= nSegments; j++) {
const float fi = static_cast<float>(i);
const float fj = static_cast<float>(j);
// inclination angle (north to south)
// 0 -> PI
// azimuth angle (east to west)
const float theta = fi * glm::pi<float>() / nSegments;
// 0 -> 2*PI
const float phi = fj * glm::pi<float>() * 2.f / nSegments;
const float x = radii[0] * sin(theta) * cos(phi);
const float y = radii[1] * sin(theta) * sin(phi);
const float z = radii[2] * cos(theta); // Z points towards pole (theta = 0)
Vertex v;
v.xyz[0] = x;
v.xyz[1] = y;
v.xyz[2] = z;
const float t1 = fj / nSegments;
const float t2 = 1.f - (fi / nSegments);
v.uv[0] = t1;
v.uv[1] = t2;
v.rgba[0] = colors.r;
v.rgba[1] = colors.g;
v.rgba[2] = colors.b;
v.rgba[3] = colors.a;
vertices.push_back(v);
}
}
std::vector<GLushort> indices;
indices.reserve(vertices.size() * 3);
for (int i = 1; i <= nSegments; i++) {
for (int j = 0; j < nSegments; j++) {
const int t = nSegments + 1;
indices.push_back(static_cast<GLushort>(t * (i - 1) + j + 0));
indices.push_back(static_cast<GLushort>(t * (i + 0) + j + 0));
indices.push_back(static_cast<GLushort>(t * (i + 0) + j + 1));
indices.push_back(static_cast<GLushort>(t * (i - 1) + j + 0));
indices.push_back(static_cast<GLushort>(t * (i + 0) + j + 1));
indices.push_back(static_cast<GLushort>(t * (i - 1) + j + 1));
}
}
return { vertices, indices };
}
} // namespace openspace::rendering::helper
+5 -13
View File
@@ -58,11 +58,6 @@ namespace {
openspace::properties::Property::Visibility::Hidden
};
constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = {
"BoundingSphere",
"Bounding Sphere",
"The size of the bounding sphere radius."
};
struct [[codegen::Dictionary(Renderable)]] Parameters {
// [[codegen::verbatim(EnabledInfo.description)]]
std::optional<bool> enabled;
@@ -76,9 +71,6 @@ namespace {
// [[codegen::verbatim(RenderableTypeInfo.description)]]
std::optional<std::string> type;
// [[codegen::verbatim(BoundingSphereInfo.description)]]
std::optional<float> boundingSphere;
};
#include "renderable_codegen.cpp"
} // namespace
@@ -120,7 +112,6 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
: properties::PropertyOwner({ "Renderable" })
, _enabled(EnabledInfo, true)
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
, _boundingSphere(BoundingSphereInfo, 0.f, 0.f, 3e10f)
, _renderableType(RenderableTypeInfo, "Renderable")
{
ZoneScoped
@@ -154,9 +145,6 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
// set type for UI
_renderableType = p.type.value_or(_renderableType);
addProperty(_renderableType);
_boundingSphere = p.boundingSphere.value_or(_boundingSphere);
addProperty(_boundingSphere);
}
void Renderable::initialize() {}
@@ -179,12 +167,16 @@ double Renderable::boundingSphere() const {
return _boundingSphere;
}
double Renderable::interactionSphere() const {
return _interactionSphere;
}
SurfacePositionHandle Renderable::calculateSurfacePositionHandle(
const glm::dvec3& targetModelSpace) const
{
const glm::dvec3 directionFromCenterToTarget = glm::normalize(targetModelSpace);
return {
directionFromCenterToTarget * boundingSphere(),
directionFromCenterToTarget * _parent->interactionSphere(),
directionFromCenterToTarget,
0.0
};
-12
View File
@@ -1111,30 +1111,18 @@ void RenderEngine::takeScreenshot() {
_latestScreenshotNumber = global::windowDelegate->takeScreenshot(_applyWarping);
}
/**
* Get the latest screenshot filename
*/
unsigned int RenderEngine::latestScreenshotNumber() const {
return _latestScreenshotNumber;
}
/**
* Set raycasting uniforms on the program object, and setup raycasting.
*/
void RenderEngine::preRaycast(ghoul::opengl::ProgramObject& programObject) {
_renderer->preRaycast(programObject);
}
/**
* Tear down raycasting for the specified program object.
*/
void RenderEngine::postRaycast(ghoul::opengl::ProgramObject& programObject) {
_renderer->postRaycast(programObject);
}
/**
* Set renderer
*/
void RenderEngine::setRenderer(std::unique_ptr<Renderer> renderer) {
ZoneScoped
+153 -24
View File
@@ -31,12 +31,15 @@
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/rendering/helper.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/timeframe.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/opengl/ghoul_gl.h>
@@ -89,11 +92,23 @@ namespace {
constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = {
"BoundingSphere",
"Bounding Sphere",
"The bounding sphere of the scene graph node. This can be the "
"bounding sphere of an attached renderable or directly specified to the node. "
"If there is a boundingsphere on both the renderable and the node, the largest "
"number will be picked.",
openspace::properties::Property::Visibility::Hidden
"The bounding sphere of the scene graph node meaning that everything that this "
"scene graph node renders must be contained within this sphere. This value is "
"only used as an override to the bounding sphere calculated by the Renderable, "
"if present. If this value is -1, the Renderable's computed bounding sphere is "
"used",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo InteractionSphereInfo = {
"InteractionSphere",
"Interaction Sphere",
"The minimum radius that the camera is allowed to get close to this scene graph "
"node. This value is "
"only used as an override to the bounding sphere calculated by the Renderable, "
"if present. If this value is -1, the Renderable's computed interaction sphere "
"is used",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo GuiPathInfo = {
@@ -128,6 +143,14 @@ namespace {
openspace::properties::Property::Visibility::Hidden
};
constexpr openspace::properties::Property::PropertyInfo ShowDebugSphereInfo = {
"ShowDebugSphere",
"Show Debug Sphere",
"If enabled the bounding sphere of this scene graph node is rendered as a debug "
"method",
openspace::properties::Property::Visibility::Developer
};
struct [[codegen::Dictionary(SceneGraphNode)]] Parameters {
// The identifier of this scenegraph node. This name must be unique among all
// scene graph nodes that are loaded in a specific scene. If a duplicate is
@@ -156,6 +179,10 @@ namespace {
// sphere needs to be overwritten for some reason
std::optional<double> boundingSphere;
// A hard-coded radius for limiting the interaction radius, meaning the minimal
// distance that the camera can approach this scene graph node
std::optional<double> interactionSphere;
struct Transform {
// This node describes a translation that is applied to the scenegraph node
// and all its children. Depending on the 'Type' of the translation, this can
@@ -258,10 +285,8 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
}
}
if (p.boundingSphere.has_value()) {
result->_boundingSphere = *p.boundingSphere;
result->_boundingSphere.setVisibility(properties::Property::Visibility::All);
}
result->_overrideBoundingSphere = p.boundingSphere;
result->_overrideInteractionSphere = p.interactionSphere;
if (p.transform.has_value()) {
if (p.transform->translation.has_value()) {
@@ -345,23 +370,11 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
if (p.renderable.has_value()) {
result->_renderable = Renderable::createFromDictionary(*p.renderable);
ghoul_assert(result->_renderable, "Failed to create Renderable");
result->_renderable->_parent = result.get();
result->addPropertySubOwner(result->_renderable.get());
LDEBUG(fmt::format(
"Successfully created renderable for '{}'", result->identifier()
));
// If the renderable child has a larger bounding sphere, we allow it to override
if (result->_renderable->boundingSphere() > result->_boundingSphere) {
result->_boundingSphere = result->_renderable->boundingSphere();
if (p.boundingSphere.has_value()) {
LWARNING(fmt::format(
"The specified property 'BoundingSphere' for '{}' was overwritten "
"by a child renderable",
result->_identifier
));
}
}
}
if (p.tag.has_value()) {
@@ -392,6 +405,8 @@ documentation::Documentation SceneGraphNode::Documentation() {
return doc;
}
ghoul::opengl::ProgramObject* SceneGraphNode::_debugSphereProgram = nullptr;
SceneGraphNode::SceneGraphNode()
: properties::PropertyOwner({ "" })
, _guiHidden(GuiHiddenInfo)
@@ -409,13 +424,15 @@ SceneGraphNode::SceneGraphNode()
global::memoryManager->PersistentMemory.alloc<StaticScale>()
)
}
, _boundingSphere(BoundingSphereInfo, 0.0)
, _boundingSphere(BoundingSphereInfo, -1.0, -1.0, 1e12)
, _interactionSphere(InteractionSphereInfo, -1.0, -1.0, -1.0, 1e12)
, _computeScreenSpaceValues(ComputeScreenSpaceInfo, false)
, _screenSpacePosition(ScreenSpacePositionInfo, glm::ivec2(-1, -1))
, _screenVisibility(ScreenVisibilityInfo, false)
, _distFromCamToNode(DistanceFromCamToNodeInfo, -1.0)
, _screenSizeRadius(ScreenSizeRadiusInfo, 0)
, _visibilityDistance(VisibilityDistanceInfo, 6e10f)
, _showDebugSphere(ShowDebugSphereInfo, false)
{
addProperty(_computeScreenSpaceValues);
addProperty(_screenSpacePosition);
@@ -423,7 +440,25 @@ SceneGraphNode::SceneGraphNode()
addProperty(_distFromCamToNode);
addProperty(_screenSizeRadius);
addProperty(_visibilityDistance);
_boundingSphere.onChange([this]() {
if (_boundingSphere >= 0.0) {
_overrideBoundingSphere = _boundingSphere;
}
else {
_overrideBoundingSphere = std::nullopt;
}
});
addProperty(_boundingSphere);
_interactionSphere.onChange([this]() {
if (_interactionSphere >= 0.0) {
_overrideInteractionSphere = _interactionSphere;
}
else {
_overrideInteractionSphere = std::nullopt;
}
});
addProperty(_interactionSphere);
addProperty(_showDebugSphere);
}
SceneGraphNode::~SceneGraphNode() {} // NOLINT
@@ -461,6 +496,25 @@ void SceneGraphNode::initializeGL() {
if (_renderable) {
_renderable->initializeGL();
}
// The first one to get here will create program shared between all scene graph nodes
if (_debugSphereProgram == nullptr) {
std::unique_ptr<ghoul::opengl::ProgramObject> shader =
global::renderEngine->buildRenderProgram(
"DebugSphere",
absPath("${SHADERS}/core/xyzuvrgba_vs.glsl"),
absPath("${SHADERS}/core/xyzuvrgba_fs.glsl")
);
// Since we are only going to create a single of these shaders for the lifetime of
// the program, we are not bothering with freeing it as the overhead of detecting
// when the last scenegraph node will be destroyed would be a bit too much for the
// benefit that we would gain from it
_debugSphereProgram = shader.release();
_debugSphereProgram->setIgnoreUniformLocationError(
ghoul::opengl::ProgramObject::IgnoreError::Yes
);
}
_state = State::GLInitialized;
LDEBUG(fmt::format("Finished initializating GL: {}", identifier()));
@@ -598,6 +652,59 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
computeScreenSpaceData(newData);
}
}
if (_showDebugSphere) {
if (const double bs = boundingSphere(); bs > 0.0) {
renderDebugSphere(data.camera, bs, glm::vec4(0.5f, 0.15f, 0.5f, 0.75f));
}
if (const double is = interactionSphere(); is > 0.0) {
renderDebugSphere(data.camera, is, glm::vec4(0.15f, 0.35f, 0.85f, 0.75f));
}
}
}
void SceneGraphNode::renderDebugSphere(const Camera& camera, double size, glm::vec4 color)
{
glm::dvec3 scaleVec = _worldScaleCached * size;
glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), _worldPositionCached) *
glm::dmat4(_worldRotationCached) *
glm::scale(glm::dmat4(1.0), scaleVec);
glm::mat4 modelViewProjection = camera.projectionMatrix() *
glm::mat4(camera.combinedViewMatrix() * modelTransform);
_debugSphereProgram->activate();
_debugSphereProgram->setUniform("hasTexture", 0);
_debugSphereProgram->setUniform("proj", modelViewProjection);
_debugSphereProgram->setUniform("color", color);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glBindVertexArray(rendering::helper::vertexObjects.sphere.vao);
glDrawElements(
GL_TRIANGLES,
rendering::helper::vertexObjects.sphere.nElements,
GL_UNSIGNED_SHORT,
nullptr
);
glLineWidth(2.0);
_debugSphereProgram->setUniform("color", glm::vec4(1.f, 1.f, 1.f, 1.f));
glDrawElements(
GL_LINES,
rendering::helper::vertexObjects.sphere.nElements,
GL_UNSIGNED_SHORT,
nullptr
);
glBindVertexArray(0);
_debugSphereProgram->deactivate();
}
void SceneGraphNode::setParent(SceneGraphNode& parent) {
@@ -955,7 +1062,29 @@ std::vector<SceneGraphNode*> SceneGraphNode::children() const {
}
double SceneGraphNode::boundingSphere() const {
return _boundingSphere;
if (_overrideBoundingSphere.has_value()) {
return glm::compMax(scale() * *_overrideBoundingSphere);
}
if (_renderable) {
return glm::compMax(scale() * _renderable->boundingSphere());
}
else {
return 0.0;
}
}
double SceneGraphNode::interactionSphere() const {
if (_overrideInteractionSphere.has_value()) {
return glm::compMax(scale() * *_overrideInteractionSphere);
}
if (_renderable) {
return glm::compMax(scale() * _renderable->interactionSphere());
}
else {
return 0.0;
}
}
const Renderable* SceneGraphNode::renderable() const {