1e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#ifndef ANDROID_DVR_FIELD_OF_VIEW_H_ 2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#define ANDROID_DVR_FIELD_OF_VIEW_H_ 3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <cmath> 5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 6e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <private/dvr/eigen.h> 7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 8e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android { 9e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace dvr { 10e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 11e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Encapsulates a generalized, asymmetric field of view with four half angles. 12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Each half angle denotes the angle between the corresponding frustum plane. 13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Together with a near and far plane, a FieldOfView forms the frustum of an 14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// off-axis perspective projection. 15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoclass FieldOfView { 16e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko public: 17e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // The default constructor sets an angle of 0 (in any unit) for all four 18e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // half-angles. 19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko FieldOfView() : left_(0.0f), right_(0.0f), bottom_(0.0f), top_(0.0f) {} 20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Constructs a FieldOfView from four angles. 22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko FieldOfView(float left, float right, float bottom, float top) 23e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : left_(left), right_(right), bottom_(bottom), top_(top) {} 24e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit FieldOfView(const float* fov) 26e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : FieldOfView(fov[0], fov[1], fov[2], fov[3]) {} 27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Accessors for all four half-angles. 29e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float GetLeft() const { return left_; } 30e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float GetRight() const { return right_; } 31e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float GetBottom() const { return bottom_; } 32e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float GetTop() const { return top_; } 33e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 34e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Setters for all four half-angles. 35e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void SetLeft(float left) { left_ = left; } 36e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void SetRight(float right) { right_ = right; } 37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void SetBottom(float bottom) { bottom_ = bottom; } 38e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void SetTop(float top) { top_ = top; } 39e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 40e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Eigen::AffineMatrix<float, 4> GetProjectionMatrix(float z_near, 41e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float z_far) const { 42e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float x_left = -std::tan(left_) * z_near; 43e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float x_right = std::tan(right_) * z_near; 44e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float y_bottom = -std::tan(bottom_) * z_near; 45e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float y_top = std::tan(top_) * z_near; 46e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 47e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float zero = 0.0f; 48e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (x_left == x_right || y_bottom == y_top || z_near == z_far || 49e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko z_near <= zero || z_far <= zero) { 50e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return Eigen::AffineMatrix<float, 4>::Identity(); 51e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 52e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 53e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float x = (2 * z_near) / (x_right - x_left); 54e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float y = (2 * z_near) / (y_top - y_bottom); 55e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float a = (x_right + x_left) / (x_right - x_left); 56e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float b = (y_top + y_bottom) / (y_top - y_bottom); 57e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float c = (z_near + z_far) / (z_near - z_far); 58e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float d = (2 * z_near * z_far) / (z_near - z_far); 59e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 60e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Note: Eigen matrix initialization syntax is always 'column-major' 61e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // even if the storage is row-major. Or in other words, just write the 62e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // matrix like you'd see in a math textbook. 63e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Eigen::AffineMatrix<float, 4> result; 64e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko result.matrix() << x, 0, a, 0, 65e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 0, y, b, 0, 66e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 0, 0, c, d, 67e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 0, 0, -1, 0; 68e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return result; 69e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 70e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 71e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static FieldOfView FromProjectionMatrix( 72e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const Eigen::AffineMatrix<float, 4>& m) { 73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Compute tangents. 74e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float tan_vert_fov = 1.0f / m(1, 1); 75e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float tan_horz_fov = 1.0f / m(0, 0); 76e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float t = (m(1, 2) + 1.0f) * tan_vert_fov; 77e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float b = (m(1, 2) - 1.0f) * tan_vert_fov; 78e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float l = (m(0, 2) - 1.0f) * tan_horz_fov; 79e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float r = (m(0, 2) + 1.0f) * tan_horz_fov; 80e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 81e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return FieldOfView(std::atan(-l), std::atan(r), std::atan(-b), 82e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::atan(t)); 83e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 84e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 85e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 86e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float left_; 87e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float right_; 88e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float bottom_; 89e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko float top_; 90e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 91e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 92e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace dvr 93e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace android 94e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 95e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#endif // ANDROID_DVR_FIELD_OF_VIEW_H_ 96