32void Camera::setDirection(
const Core::Vector3& direction ) {
33 Core::Transform T = Core::Transform::Identity();
35 Core::Vector3 d0 = getDirection();
36 Core::Vector3 d1 = direction.normalized();
38 Core::Vector3 c = d0.cross( d1 );
39 Scalar d = d0.dot( d1 );
43 if ( Math::areApproxEqual( c.squaredNorm(), 0_ra ) && d < 0_ra ) {
44 T.rotate( Core::AngleAxis( Core::Math::Pi, getUpVector() ) );
46 else { T.rotate( Core::Quaternion::FromTwoVectors( d0, d1 ) ); }
66void Camera::updateProjMatrix() {
67 switch ( m_projType ) {
68 case ProjType::ORTHOGRAPHIC: {
69 const Scalar r = m_xmag * m_zoomFactor;
70 const Scalar t = m_ymag * m_zoomFactor / m_aspect;
71 m_projMatrix = ortho( -r, r, -t, t, m_zNear, m_zFar );
74 case ProjType::PERSPECTIVE: {
75 Scalar fov = std::clamp( m_zoomFactor * m_fov, 0.001_ra, Math::Pi - 0.1_ra );
76 m_projMatrix = perspective( m_aspect, fov, m_zNear, m_zFar );
84Core::Matrix4 Camera::perspective( Scalar a, Scalar fov, Scalar n, Scalar f ) {
85 Core::Matrix4 projMatrix;
86 Scalar tanf =
std::tan( fov * .5_ra );
89 projMatrix << 1_ra / tanf, 0_ra, 0_ra, 0_ra,
90 0_ra, a / tanf, 0_ra, 0_ra,
91 0_ra, 0_ra, ( f + n ) / ( n - f ), ( 2_ra * f * n ) / ( n - f ),
92 0_ra, 0_ra, -1_ra, 0_ra;
98Core::Matrix4 Camera::frustum( Scalar l, Scalar r, Scalar b, Scalar t, Scalar n, Scalar f ) {
99 Core::Matrix4 projMatrix;
100 projMatrix.setZero();
101 const Scalar A = ( r + l ) / ( r - l );
103 const Scalar B = ( t + b ) / ( t - b );
104 const Scalar C = ( f + n ) / ( n - f );
105 const Scalar D = ( 2_ra * f * n ) / ( n - f );
107 projMatrix << 2_ra * n / ( r - l ), 0_ra, A, 0_ra,
108 0_ra, 2_ra * n / ( t - b ), B, 0_ra,
110 0_ra, 0_ra, -1_ra, 0_ra;
116Core::Matrix4 Camera::ortho( Scalar l, Scalar r, Scalar b, Scalar t, Scalar n, Scalar f ) {
117 Core::Matrix4 projMatrix;
118 projMatrix.setZero();
121 -( r + l ) / ( r - l ), -( t + b ) / ( t - b ), -( f + n ) / ( f - n ), 1_ra );
123 projMatrix.setIdentity();
124 projMatrix.coeffRef( 0, 0 ) = 2_ra / ( r - l );
125 projMatrix.coeffRef( 1, 1 ) = 2_ra / ( t - b );
126 projMatrix.coeffRef( 2, 2 ) = 2_ra / ( n - f );
127 projMatrix.block<4, 1>( 0, 3 ) = tr;
132void Camera::fitZRange(
const Core::Aabb& aabb ) {
134 const Core::Vector3& position = getPosition();
135 Core::Vector3 direction = -m_frame.affine().block<3, 1>( 0, 2 );
137 const Core::Vector3& minAabb = aabb.min();
138 const Core::Vector3& maxAabb = aabb.max();
139 this->m_zNear = this->m_zFar = direction.dot( minAabb - position );
141 auto adaptRange = [position, direction,
this]( Scalar x, Scalar y, Scalar z ) {
142 Ra::Core::Vector3 corner( x, y, z );
143 auto d = direction.dot( corner - position );
144 this->m_zNear =
std::min( d, this->m_zNear );
145 this->m_zFar =
std::max( d, this->m_zFar );
149 const auto position = Ra::Core::Vector3 { 0_ra, 0_ra, 0_ra };
150 const auto direction = Ra::Core::Vector3 { 0_ra, 0_ra, -1_ra };
151 const auto view = getFrame().inverse();
152 const auto& minAabb = aabb.min();
153 const auto& maxAabb = aabb.max();
155 m_zNear = m_zFar = direction.dot( view * minAabb - position );
156 auto adaptRange = [view, position, direction,
this]( Scalar x, Scalar y, Scalar z ) {
157 auto corner = Core::Vector3 { x, y, z };
158 auto d = direction.dot( view * corner - position );
159 this->m_zNear =
std::min( d, this->m_zNear );
160 this->m_zFar =
std::max( d, this->m_zFar );
164 adaptRange( minAabb[0], minAabb[1], maxAabb[2] );
165 adaptRange( minAabb[0], maxAabb[1], minAabb[2] );
166 adaptRange( minAabb[0], maxAabb[1], maxAabb[2] );
167 adaptRange( maxAabb[0], maxAabb[1], maxAabb[2] );
168 adaptRange( maxAabb[0], maxAabb[1], minAabb[2] );
169 adaptRange( maxAabb[0], minAabb[1], maxAabb[2] );
170 adaptRange( maxAabb[0], minAabb[1], minAabb[2] );
172 if ( m_zNear < m_minZNear ) { m_zNear = m_minZNear; }
173 if ( ( m_zFar - m_zNear ) < m_minZRange ) { m_zFar = m_zNear + m_minZRange; }
191Core::Vector3 Camera::projectToScreen(
const Core::Vector3& p )
const {
192 Core::Vector3 vpPoint = projectToNDC( p );
193 return Core::Vector3( getWidth() * 0.5_ra * ( 1_ra + vpPoint.x() ),
194 getHeight() * 0.5_ra * ( 1_ra - vpPoint.y() ),
195 vpPoint.z() * .5_ra + .5_ra );
202Core::Vector3 Camera::unProjectFromScreen(
const Core::Vector3& pix )
const {
203 Core::Vector3 ndc { pix.cwiseProduct( Core::Vector3( 2_ra, -2_ra, 2_ra ) )
204 .cwiseQuotient( Core::Vector3( getWidth(), getHeight(), 1_ra ) ) +
205 Core::Vector3 { -1_ra, 1_ra, -1_ra } };
206 return unProjectFromNDC( ndc );
209Core::Vector3 Camera::unProjectFromNDC(
const Core::Vector3& ndc )
const {
210 Core::Vector4 localPoint4;
211 localPoint4 << ndc, 1_ra;
212 const Core::Vector4 unproj = getProjMatrix().inverse() * localPoint4;
213 return getFrame() * ( unproj.head<3>() / unproj.w() );