Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 65 additions & 4 deletions Cesium3DTiles/include/Cesium3DTiles/ViewState.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,64 @@ class CESIUM3DTILES_API ViewState final {

// TODO: Add support for orthographic and off-center perspective frustums
public:
/**
* @brief The frustum type type to use with the {@link ViewState}
*/
enum class FrustumType { Perspective, Orthographic };

/**
* @brief Creates a new instance of a view state.
*
* @param frustumType The frustum type of the camera.
* @param position The position of the eye point of the camera.
* @param direction The view direction vector of the camera.
* @param up The up vector of the camera.
* @param viewportSize The size of the viewport, in pixels.
* @param horizontalFieldOfView The horizontal field-of-view (opening)
* angle of the camera, in radians.
* angle of the camera, in radians. Only applicable when using perspective
* projection.
* @param verticalFieldOfView The vertical field-of-view (opening)
* angle of the camera, in radians.
* angle of the camera, in radians. Only applicable when using perspective
* projection.
* @param orthographicWidth The width in meters of the orthographic frustum.
* Only applicable when using orthographic projection.
* @param orthographicHeight The height in meters of the orthographic frustum.
* Only applicable when using orthographic projection.
* @param ellipsoid The ellipsoid that will be used to compute the
* {@link ViewState#getPositionCartographic cartographic position}
* from the cartesian position.
* Default value: {@link CesiumGeospatial::Ellipsoid::WGS84}.
*/
static ViewState create(
const FrustumType& frutumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
const glm::dvec2& viewportSize,
double horizontalFieldOfView,
double verticalFieldOfView,
double orthographicWidth,
double orthographicHeight,
const CesiumGeospatial::Ellipsoid& ellipsoid =
CesiumGeospatial::Ellipsoid::WGS84);

static CullingVolume createCullingVolume(
const FrustumType& frustumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
double horizontalFieldOfView,
double verticalFieldOfView,
double orthographicWidth,
double orthographicHeight);

/**
* @brief Gets the frustum type of the camera.
*/
const FrustumType& getFrustumType() const noexcept {
return this->_frustumType;
}

/**
* @brief Gets the position of the camera in Earth-centered, Earth-fixed
* coordinates.
Expand Down Expand Up @@ -99,6 +131,22 @@ class CESIUM3DTILES_API ViewState final {
return this->_verticalFieldOfView;
}

/**
* @brief Gets the width in meters of the orthographic frustum. Only relevant
* when the `frustumType` is `FrustumType::Orthographic`.
*/
double getOrthographicWidth() const noexcept {
return this->_orthographicWidth;
}

/**
* @brief Gets the height in meters of the orthographic frustum. Only
* relevant when the `frustumType` is `FrustumType::Orthographic`.
*/
double getOrthographicHeight() const noexcept {
return this->_orthographicHeight;
}

/**
* @brief Returns whether the given {@link BoundingVolume} is visible for this
* camera
Expand Down Expand Up @@ -145,31 +193,44 @@ class CESIUM3DTILES_API ViewState final {
/**
* @brief Creates a new instance.
*
* @param frustumType The frustum type of the camera.
* @param position The position of the eye point of the camera.
* @param direction The view direction vector of the camera.
* @param up The up vector of the camera.
* @param viewportSize The size of the viewport, in pixels.
* @param horizontalFieldOfView The horizontal field-of-view (opening)
* angle of the camera, in radians.
* angle of the camera, in radians. Only applicable when using perspective
* projection.
* @param verticalFieldOfView The vertical field-of-view (opening)
* angle of the camera, in radians.
* angle of the camera, in radians. Only applicable when using perspective
* projection
* @param orthographicWidth The width in meters of the orthographic frustum.
* Only applicable when using orthographic projection.
* @param orthographicHeight The height in meters of the orthographic frustum.
* Only applicable when using orthographic projection.
*/
ViewState(
const FrustumType& frustumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
const glm::dvec2& viewportSize,
double horizontalFieldOfView,
double verticalFieldOfView,
double orthographicWidth,
double orthographicHeight,
const std::optional<CesiumGeospatial::Cartographic>&
positionCartographic);

const FrustumType _frustumType;
const glm::dvec3 _position;
const glm::dvec3 _direction;
const glm::dvec3 _up;
const glm::dvec2 _viewportSize;
const double _horizontalFieldOfView;
const double _verticalFieldOfView;
const double _orthographicWidth;
const double _orthographicHeight;

const double _sseDenominator;
const std::optional<CesiumGeospatial::Cartographic> _positionCartographic;
Expand Down
76 changes: 55 additions & 21 deletions Cesium3DTiles/src/ViewState.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

#include "Cesium3DTiles/ViewState.h"
#include "CesiumGeometry/CullingVolume.h"

#include <glm/trigonometric.hpp>

Expand All @@ -10,69 +9,99 @@ using namespace CesiumGeospatial;
namespace Cesium3DTiles {

/* static */ ViewState ViewState::create(
const FrustumType& frustumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
const glm::dvec2& viewportSize,
double horizontalFieldOfView,
double verticalFieldOfView,
double orthographicWidth,
double orthographicHeight,
const CesiumGeospatial::Ellipsoid& ellipsoid) {
return ViewState(
frustumType,
position,
direction,
up,
viewportSize,
horizontalFieldOfView,
verticalFieldOfView,
orthographicWidth,
orthographicHeight,
ellipsoid.cartesianToCartographic(position));
}

/* static */ CullingVolume ViewState::createCullingVolume(
const FrustumType& frustumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
const double horizontalFieldOfView,
const double verticalFieldOfView,
const double orthographicWidth,
const double orthographicHeight) {

if (frustumType == FrustumType::Perspective) {
return createPerspectiveCullingVolume(
position,
direction,
up,
horizontalFieldOfView,
verticalFieldOfView);
} else if (frustumType == FrustumType::Orthographic) {
return createOrthographicCullingVolume(
position,
direction,
up,
orthographicWidth,
orthographicHeight);
} else {
return CullingVolume({});
}
}

ViewState::ViewState(
const FrustumType& frustumType,
const glm::dvec3& position,
const glm::dvec3& direction,
const glm::dvec3& up,
const glm::dvec2& viewportSize,
double horizontalFieldOfView,
double verticalFieldOfView,
double orthographicWidth,
double orthographicHeight,
const std::optional<CesiumGeospatial::Cartographic>& positionCartographic)
: _position(position),
: _frustumType(frustumType),
_position(position),
_direction(direction),
_up(up),
_viewportSize(viewportSize),
_horizontalFieldOfView(horizontalFieldOfView),
_verticalFieldOfView(verticalFieldOfView),
_orthographicWidth(orthographicWidth),
_orthographicHeight(orthographicHeight),
_sseDenominator(2.0 * glm::tan(0.5 * verticalFieldOfView)),
_positionCartographic(positionCartographic),
_cullingVolume(createCullingVolume(
frustumType,
position,
direction,
up,
horizontalFieldOfView,
verticalFieldOfView)) {}
verticalFieldOfView,
orthographicWidth,
orthographicHeight)) {}

template <class T>
static bool isBoundingVolumeVisible(
const T& boundingVolume,
const CullingVolume& cullingVolume) noexcept {
CullingResult left = boundingVolume.intersectPlane(cullingVolume.leftPlane);
if (left == CullingResult::Outside) {
return false;
}

CullingResult right = boundingVolume.intersectPlane(cullingVolume.rightPlane);
if (right == CullingResult::Outside) {
return false;
}

CullingResult top = boundingVolume.intersectPlane(cullingVolume.topPlane);
if (top == CullingResult::Outside) {
return false;
}

CullingResult bottom =
boundingVolume.intersectPlane(cullingVolume.bottomPlane);
if (bottom == CullingResult::Outside) {
return false;
for (const CesiumGeometry::Plane& plane : cullingVolume.getPlanes()) {
if (boundingVolume.intersectPlane(plane) == CullingResult::Outside) {
return false;
}
}

return true;
Expand Down Expand Up @@ -157,6 +186,11 @@ double ViewState::computeScreenSpaceError(
double distance) const noexcept {
// Avoid divide by zero when viewer is inside the tile
distance = glm::max(distance, 1e-7);

if (this->_frustumType == FrustumType::Orthographic) {
return geometricError * this->_viewportSize.y / this->_orthographicHeight;
}

double sseDenominator = this->_sseDenominator;
return (geometricError * this->_viewportSize.y) / (distance * sseDenominator);
}
Expand Down
25 changes: 20 additions & 5 deletions Cesium3DTiles/test/TestTilesetSelectionAlgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ static void initializeTileset(Tileset& tileset) {
double verticalFieldOfView =
std::atan(std::tan(horizontalFieldOfView * 0.5) / aspectRatio) * 2.0;
ViewState viewState = ViewState::create(
ViewState::FrustumType::Perspective,
viewPosition,
glm::normalize(viewFocus - viewPosition),
viewUp,
viewPortSize,
horizontalFieldOfView,
verticalFieldOfView);
verticalFieldOfView,
0.0,
0.0);

tileset.updateView({viewState});
}
Expand Down Expand Up @@ -99,12 +102,15 @@ static ViewState zoomToTileset(const Tileset& tileset) {
double verticalFieldOfView =
std::atan(std::tan(horizontalFieldOfView * 0.5) / aspectRatio) * 2.0;
return ViewState::create(
ViewState::FrustumType::Perspective,
viewPosition,
glm::normalize(viewFocus - viewPosition),
viewUp,
viewPortSize,
horizontalFieldOfView,
verticalFieldOfView);
verticalFieldOfView,
0.0,
0.0);
}

TEST_CASE("Test replace refinement for render") {
Expand Down Expand Up @@ -175,12 +181,15 @@ TEST_CASE("Test replace refinement for render") {
glm::dvec3 zoomOutPosition =
viewState.getPosition() - viewState.getDirection() * 2500.0;
ViewState zoomOutViewState = ViewState::create(
viewState.getFrustumType(),
zoomOutPosition,
viewState.getDirection(),
viewState.getUp(),
viewState.getViewportSize(),
viewState.getHorizontalFieldOfView(),
viewState.getVerticalFieldOfView());
viewState.getVerticalFieldOfView(),
viewState.getOrthographicWidth(),
viewState.getOrthographicHeight());

// Check 1st and 2nd frame. Root should meet sse and render. No transitions
// are expected here
Expand Down Expand Up @@ -301,12 +310,15 @@ TEST_CASE("Test replace refinement for render") {
glm::dvec3 zoomInPosition =
viewState.getPosition() + viewState.getDirection() * 200.0;
ViewState zoomInViewState = ViewState::create(
viewState.getFrustumType(),
zoomInPosition,
viewState.getDirection(),
viewState.getUp(),
viewState.getViewportSize(),
viewState.getHorizontalFieldOfView(),
viewState.getVerticalFieldOfView());
viewState.getVerticalFieldOfView(),
viewState.getOrthographicWidth(),
viewState.getOrthographicHeight());

// remove the ll.b3dm (one of the root's children) request to replicate
// network failure
Expand Down Expand Up @@ -397,12 +409,15 @@ TEST_CASE("Test replace refinement for render") {
glm::dvec3 zoomOutPosition =
viewState.getPosition() - viewState.getDirection() * 100.0;
ViewState zoomOutViewState = ViewState::create(
viewState.getFrustumType(),
zoomOutPosition,
viewState.getDirection(),
viewState.getUp(),
viewState.getViewportSize(),
viewState.getHorizontalFieldOfView(),
viewState.getVerticalFieldOfView());
viewState.getVerticalFieldOfView(),
viewState.getOrthographicWidth(),
viewState.getOrthographicHeight());

ViewUpdateResult result = tileset.updateView({zoomOutViewState});

Expand Down
Loading