1 #include <Gui/Viewer/Gizmo/RotateGizmo.hpp>
3 #include <Core/Containers/VectorArray.hpp>
4 #include <Core/Geometry/MeshPrimitives.hpp>
5 #include <Core/Utils/Color.hpp>
7 #include <Core/Asset/Camera.hpp>
8 #include <Engine/Data/Mesh.hpp>
9 #include <Engine/Rendering/RenderObject.hpp>
10 #include <Engine/Rendering/RenderTechnique.hpp>
11 #include <Engine/Scene/CameraComponent.hpp>
16 RotateGizmo::RotateGizmo( Engine::Scene::Component* c,
17 const Core::Transform& worldTo,
18 const Core::Transform& t,
20 Gizmo( c, worldTo, t, mode ), m_initialPix( Core::Vector2::Zero() ), m_selectedAxis( -1 ) {
21 constexpr Scalar torusOutRadius = .1_ra;
22 constexpr Scalar torusAspectRatio = .08_ra;
24 for ( uint i = 0; i < 3; ++i ) {
25 Core::Geometry::TriangleMesh torus = Core::Geometry::makeParametricTorus<32>(
26 torusOutRadius, torusAspectRatio * torusOutRadius );
28 auto& data = torus.verticesWithLock();
29 for (
auto& v : data ) {
31 if ( i < 2 ) { std::swap( v[2], v[i] ); }
33 torus.verticesUnlock();
35 auto mesh = std::shared_ptr<Engine::Data::Mesh>(
new Engine::Data::Mesh(
"Gizmo Torus" ) );
36 mesh->loadGeometry( std::move( torus ) );
38 auto torusDrawable =
new Engine::Rendering::RenderObject(
39 "Gizmo Torus", m_comp, Engine::Rendering::RenderObjectType::UI );
40 auto rt = std::shared_ptr<Engine::Rendering::RenderTechnique>( makeRenderTechnique( i ) );
41 torusDrawable->setRenderTechnique( rt );
42 torusDrawable->setMesh( mesh );
43 addRenderObject( torusDrawable );
45 updateTransform( mode, m_worldTo, m_transform );
48 void RotateGizmo::updateTransform( Gizmo::Mode mode,
49 const Core::Transform& worldTo,
50 const Core::Transform& t ) {
54 Core::Transform displayTransform = Core::Transform::Identity();
55 displayTransform.translate( m_transform.translation() );
56 if ( m_mode == LOCAL ) {
57 Core::Matrix3 R = m_transform.rotation();
58 R.col( 0 ).normalize();
59 R.col( 1 ).normalize();
60 R.col( 2 ).normalize();
61 displayTransform.rotate( R );
64 for (
auto ro : ros() ) {
65 ro->setLocalTransform( m_worldTo * displayTransform );
69 void RotateGizmo::selectConstraint(
int drawableIdx ) {
71 if ( m_selectedAxis != -1 ) {
72 getControler( m_selectedAxis )->clearState();
76 if ( drawableIdx < 0 ) {
return; }
79 auto found = std::find_if( ros().cbegin(), ros().cend(), [drawableIdx](
const auto& ro ) {
80 return ro->getIndex() == Core::Utils::Index( drawableIdx );
82 if ( found != ros().cend() ) {
83 m_selectedAxis = int( std::distance( ros().cbegin(), found ) );
84 getControler( m_selectedAxis )->setState();
89 const Core::Vector2& nextXY,
92 static const Scalar step = Ra::Core::Math::Pi / 10_ra;
94 if ( m_selectedAxis == -1 )
return m_transform;
97 Core::Matrix3 rotationMat;
98 Core::Matrix3 scaleMat;
99 m_transform.computeRotationScaling( &rotationMat, &scaleMat );
102 const Core::Vector3 origin = m_transform.translation();
103 Core::Vector3 rotationAxis = Core::Vector3::Unit( m_selectedAxis );
104 if ( m_mode == LOCAL ) { rotationAxis = rotationMat * rotationAxis; }
105 rotationAxis.normalize();
106 const Core::Vector3 originW = m_worldTo * origin;
107 const Core::Vector3 rotationAxisW = m_worldTo * rotationAxis;
113 m_initialRot = rotationMat;
117 std::vector<Scalar> hits1, hits2;
118 Core::Vector3 originalHit, currentHit;
119 bool hit1 = findPointOnPlane( cam, originW, rotationAxisW, m_initialPix, originalHit, hits1 );
120 bool hit2 = findPointOnPlane( cam, originW, rotationAxisW, nextXY, currentHit, hits2 );
125 if ( hit1 && hit2 && hits1[0] > .2_ra && hits2[0] > .2_ra ) {
127 originalHit -= originW;
128 currentHit -= originW;
132 auto c = originalHit.cross( currentHit );
133 Scalar d = originalHit.dot( currentHit );
135 angle = Core::Math::sign( c.dot( rotationAxisW ) ) * std::atan2( c.norm(), d );
139 Core::Vector2 dir = ( cam.
projectToScreen( originW + rotationAxisW ).head<2>() -
142 if ( std::abs( dir( 0 ) ) < 1e-3_ra ) { dir << 1, 0; }
143 else if ( std::abs( dir( 1 ) ) < 1e-3_ra ) { dir << 0, 1; }
144 else { dir = Core::Vector2( dir( 1 ), -dir( 0 ) ); }
146 angle = dir.dot( ( nextXY - m_initialPix ) ) * 8_ra / diag;
148 if ( std::isnan( angle ) ) { angle = 0_ra; }
150 Core::Vector2 nextXY_ = nextXY;
152 angle = int( angle / step ) * step;
153 if ( Core::Math::areApproxEqual( angle, 0_ra ) ) { nextXY_ = m_initialPix; }
155 Scalar diff = m_totalAngle - int( m_totalAngle / step ) * step;
160 m_totalAngle += angle;
161 if ( !Core::Math::areApproxEqual( angle, 0_ra ) ) {
162 auto newRot = Core::AngleAxis( angle, rotationAxis ) * rotationMat;
163 m_transform.fromPositionOrientationScale( origin, newRot, scaleMat.diagonal() );
165 m_initialPix = nextXY_;
171 const Core::Vector2& initialXY ) {
172 m_initialPix = initialXY;
Camera class storing the Camera frame and the projection properties The view direction is -z in camer...
Scalar getWidth() const
Return the width of the viewport.
Scalar getHeight() const
Return the height of the viewport.
Core::Vector3 projectToScreen(const Core::Vector3 &p) const
Return the screen coordinates + depth of the given point p (in world coordinates).