Prevent floating point over- and underflows; specifically when interpolating the camera position (closes #575)

This commit is contained in:
Alexander Bock
2018-04-10 15:04:41 -04:00
parent 62eca12e25
commit 34987e9f85
8 changed files with 49 additions and 19 deletions
+1 -1
View File
@@ -173,7 +173,7 @@ private:
// Cached transform data
glm::dvec3 _worldPositionCached;
glm::dmat3 _worldRotationCached;
double _worldScaleCached;
double _worldScaleCached = 1.0;
glm::dmat4 _modelTransformCached;
glm::dmat4 _inverseModelTransformCached;
@@ -292,7 +292,13 @@ void AtmosphereDeferredcaster::preRaycast(const RenderData& renderData,
}
// Sun Position in Object Space
program.setUniform(_uniformCache2.sunDirectionObj, glm::normalize(glm::dvec3(sunPosObj)));
const double l = glm::length(glm::dvec3(sunPosObj));
program.setUniform(
_uniformCache2.sunDirectionObj,
l > 0.0 ?
glm::normalize(glm::dvec3(sunPosObj)) :
glm::dvec3(0.0)
);
// Shadow calculations..
if (!_shadowConfArray.empty()) {
@@ -85,13 +85,21 @@ bool HorizonCuller::isCullable(const glm::dvec3& cameraPosition,
double objectBoundingSphereRadius,
double minimumGlobeRadius)
{
double distanceToHorizon =
sqrt(pow(length(cameraPosition - globePosition), 2) -
pow(minimumGlobeRadius, 2));
const double objectP = pow(length(objectPosition - globePosition), 2);
const double horizonP = pow(minimumGlobeRadius - objectBoundingSphereRadius, 2);
if (objectP < horizonP) {
return false;
}
double minimumAllowedDistanceToObjectFromHorizon = sqrt(
pow(length(objectPosition - globePosition), 2) -
pow(minimumGlobeRadius - objectBoundingSphereRadius, 2));
const double cameraP = pow(length(cameraPosition - globePosition), 2);
const double minR = pow(minimumGlobeRadius, 2);
if (cameraP < minR) {
return false;
}
double minimumAllowedDistanceToObjectFromHorizon = sqrt(objectP - horizonP);
double distanceToHorizon = sqrt(cameraP - minR);
// Minimum allowed for the object to be occluded
double minimumAllowedDistanceToObjectSquared =
@@ -271,8 +271,11 @@ void ChunkRenderer::setCommonUniforms(ghoul::opengl::ProgramObject& programObjec
chunk.owner().generalProperties().atmosphereEnabled ||
chunk.owner().generalProperties().performShading)
{
glm::vec3 directionToSunWorldSpace =
glm::normalize(-data.modelTransform.translation);
glm::dvec3 directionToSunWorldSpace =
length(data.modelTransform.translation) > 0.0 ?
glm::normalize(-data.modelTransform.translation) :
glm::dvec3(0.0);
glm::vec3 directionToSunCameraSpace =
glm::vec3(viewTransform * glm::dvec4(directionToSunWorldSpace, 0));
programObject.setUniform(
+10 -3
View File
@@ -641,15 +641,22 @@ void LuaConsole::update() {
_fullHeight = (bbox.boundingBox.y + EntryFontSize + SeparatorSpace);
_targetHeight = _isVisible ? _fullHeight : 0;
const float frametime = static_cast<float>(OsEng.windowWrapper().deltaTime());
// The first frame is going to be finished in approx 10 us, which causes a floating
// point overflow when computing dHeight
const double frametime = std::max(
OsEng.windowWrapper().deltaTime(),
1e-4
);
// Update the current height.
// The current height is the offset that is used to slide
// the console in from the top.
const glm::ivec2 res = OsEng.windowWrapper().currentWindowResolution();
const glm::vec2 dpiScaling = OsEng.windowWrapper().dpiScaling();
_currentHeight += (_targetHeight - _currentHeight) *
std::pow(0.98f, 1.f / (ConsoleOpenSpeed / dpiScaling.y * frametime));
const double dHeight = (_targetHeight - _currentHeight) *
std::pow(0.98, 1.0 / (ConsoleOpenSpeed / dpiScaling.y * frametime));
_currentHeight += static_cast<float>(dHeight);
_currentHeight = std::max(0.0f, _currentHeight);
_currentHeight = std::min(static_cast<float>(res.y), _currentHeight);
+5 -1
View File
@@ -377,7 +377,11 @@ glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime,
localCameraRotation,
glm::dquat(glm::dvec3(0.0)),
glm::min(t * _rotateToFocusNodeInterpolator.deltaTimeScaled(), 1.0));
if (angle(result) < 0.01) {
// Retrieving the angle of a quaternion uses acos on the w component, which can
// have numerical instability for values close to 1.0
constexpr double Epsilon = 1.0e-13;
if (abs((abs(result.w) - 1.0)) < Epsilon || angle(result) < 0.01) {
_rotateToFocusNodeInterpolator.end();
}
return result;
+1
View File
@@ -107,6 +107,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
, _enabled(EnabledInfo, true)
, _opacity(OpacityInfo, 1.f, 0.f, 1.f)
, _renderBin(RenderBin::Opaque)
, _boundingSphere(0.f)
, _startTime("")
, _endTime("")
, _hasTimeInterval(false)
+6 -5
View File
@@ -585,11 +585,12 @@ bool SceneGraphNode::hasGuiHintHidden() const {
glm::dvec3 SceneGraphNode::calculateWorldPosition() const {
// recursive up the hierarchy if there are parents available
if (_parent) {
return
_parent->calculateWorldPosition() +
_parent->worldRotationMatrix() *
_parent->worldScale() *
position();
const glm::dvec3 wp = _parent->calculateWorldPosition();
const glm::dmat3 wrot = _parent->worldRotationMatrix();
const double ws = _parent->worldScale();
const glm::dvec3 p = position();
return wp + wrot * ws * p;
}
else {
return position();