3
0

AnimViewportWidget.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/RPI.Public/View.h>
  9. #include <Atom/RPI.Public/ViewportContext.h>
  10. #include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
  11. #include <AzCore/Math/MatrixUtils.h>
  12. #include <AzFramework/Viewport/CameraInput.h>
  13. #include <AzFramework/Viewport/ViewportBus.h>
  14. #include <AzFramework/Viewport/ViewportControllerList.h>
  15. #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
  16. #include <EMStudio/AnimViewportRenderer.h>
  17. #include <EMStudio/AnimViewportSettings.h>
  18. #include <EMStudio/AnimViewportWidget.h>
  19. #include <EMStudio/AtomRenderPlugin.h>
  20. namespace EMStudio
  21. {
  22. AnimViewportWidget::AnimViewportWidget(AtomRenderPlugin* parentPlugin)
  23. : AtomToolsFramework::RenderViewportWidget(parentPlugin->GetInnerWidget())
  24. , m_plugin(parentPlugin)
  25. , m_renderOverlay(m_plugin->GetInnerWidget())
  26. {
  27. setObjectName(QString::fromUtf8("AtomViewportWidget"));
  28. QSizePolicy qSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
  29. qSize.setHorizontalStretch(0);
  30. qSize.setVerticalStretch(0);
  31. qSize.setHeightForWidth(sizePolicy().hasHeightForWidth());
  32. setSizePolicy(qSize);
  33. setAutoFillBackground(false);
  34. setStyleSheet(QString::fromUtf8(""));
  35. m_renderer = AZStd::make_unique<AnimViewportRenderer>(GetViewportContext(), m_plugin->GetRenderOptions());
  36. SetScene(m_renderer->GetFrameworkScene(), false);
  37. SetupCameras();
  38. SetupCameraController();
  39. Reinit();
  40. AnimViewportRequestBus::Handler::BusConnect();
  41. ViewportPluginRequestBus::Handler::BusConnect();
  42. m_renderOverlay.setVisible(true);
  43. m_renderOverlay.setUpdatesEnabled(false);
  44. m_renderOverlay.setMouseTracking(true);
  45. m_renderOverlay.setObjectName("renderOverlay");
  46. m_renderOverlay.setContentsMargins(0, 0, 0, 0);
  47. m_renderOverlay.winId(); // Force the render overlay to create a backing native window
  48. m_renderOverlay.lower();
  49. // get debug display interface for the viewport
  50. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  51. AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, GetViewportId());
  52. AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus.");
  53. m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  54. m_viewportUiManager.InitializeViewportUi(this, &m_renderOverlay);
  55. m_viewportUiManager.ConnectViewportUiBus(GetViewportId());
  56. AZ::RPI::SceneNotificationBus::Handler::BusConnect(m_renderer->GetRenderSceneId());
  57. }
  58. AnimViewportWidget::~AnimViewportWidget()
  59. {
  60. m_debugDisplay = nullptr;
  61. AZ::RPI::SceneNotificationBus::Handler::BusDisconnect();
  62. m_viewportUiManager.DisconnectViewportUiBus();
  63. ViewportPluginRequestBus::Handler::BusDisconnect();
  64. AnimViewportRequestBus::Handler::BusDisconnect();
  65. }
  66. void AnimViewportWidget::Reinit(bool resetCamera)
  67. {
  68. m_renderer->Reinit();
  69. m_renderer->UpdateActorRenderFlag(m_plugin->GetRenderOptions()->GetRenderFlags());
  70. if (resetCamera)
  71. {
  72. UpdateCameraViewMode(RenderOptions::CameraViewMode::DEFAULT);
  73. }
  74. }
  75. void AnimViewportWidget::SetupCameras()
  76. {
  77. const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::TranslateCameraInputChannelIds();
  78. m_lookRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(EMStudio::ViewportUtil::RotateCameraInputChannelId());
  79. m_lookTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
  80. translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
  81. m_lookTranslateCamera->m_translateSpeedFn = []
  82. {
  83. return 3.0f;
  84. };
  85. m_lookScrollTranslationCamera = AZStd::make_shared<AzFramework::LookScrollTranslationCameraInput>();
  86. m_lookPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
  87. EMStudio::ViewportUtil::PanCameraInputChannelId(), AzFramework::LookPan, AzFramework::TranslatePivotLook);
  88. m_orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>(EMStudio::ViewportUtil::OrbitCameraInputChannelId());
  89. m_orbitCamera->SetPivotFn(
  90. [this]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
  91. {
  92. return m_renderer->GetCharacterCenter();
  93. });
  94. m_orbitCamera->SetActivationEndedFn(
  95. [viewportId = GetViewportId()]
  96. {
  97. // when the orbit camera ends, ensure that the internal camera returns to a look state
  98. // (internal offset value for camera is zero)
  99. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  100. viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookFromOrbit);
  101. });
  102. m_orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
  103. translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
  104. m_orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(EMStudio::ViewportUtil::OrbitLookCameraInputChannelId());
  105. m_orbitScrollDollyCamera = AZStd::make_shared<AzFramework::OrbitScrollDollyCameraInput>();
  106. m_orbitPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
  107. EMStudio::ViewportUtil::PanCameraInputChannelId(), AzFramework::LookPan, AzFramework::TranslateOffsetOrbit);
  108. m_orbitMotionDollyCamera =
  109. AZStd::make_shared<AzFramework::OrbitMotionDollyCameraInput>(EMStudio::ViewportUtil::OrbitDollyCameraInputChannelId());
  110. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera);
  111. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitScrollDollyCamera);
  112. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera);
  113. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitMotionDollyCamera);
  114. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera);
  115. m_followRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(EMStudio::ViewportUtil::OrbitLookCameraInputChannelId());
  116. m_followScrollDollyCamera = AZStd::make_shared<AzFramework::OrbitScrollDollyCameraInput>();
  117. m_followScrollMotionCamera =
  118. AZStd::make_shared<AzFramework::OrbitMotionDollyCameraInput>(EMStudio::ViewportUtil::OrbitDollyCameraInputChannelId());
  119. }
  120. void AnimViewportWidget::SetupCameraController()
  121. {
  122. auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
  123. controller->SetCameraViewportContextBuilderCallback(
  124. [viewportId =
  125. GetViewportContext()->GetId()](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext)
  126. {
  127. cameraViewportContext = AZStd::make_unique<AtomToolsFramework::ModularCameraViewportContextImpl>(viewportId);
  128. });
  129. controller->SetCameraPriorityBuilderCallback(
  130. [](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn)
  131. {
  132. cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority;
  133. });
  134. controller->SetCameraPropsBuilderCallback(
  135. [](AzFramework::CameraProps& cameraProps)
  136. {
  137. cameraProps.m_rotateSmoothnessFn = []
  138. {
  139. return EMStudio::ViewportUtil::CameraRotateSmoothness();
  140. };
  141. cameraProps.m_translateSmoothnessFn = []
  142. {
  143. return EMStudio::ViewportUtil::CameraTranslateSmoothness();
  144. };
  145. cameraProps.m_rotateSmoothingEnabledFn = []
  146. {
  147. return EMStudio::ViewportUtil::CameraRotateSmoothingEnabled();
  148. };
  149. cameraProps.m_translateSmoothingEnabledFn = []
  150. {
  151. return EMStudio::ViewportUtil::CameraTranslateSmoothingEnabled();
  152. };
  153. });
  154. controller->SetCameraListBuilderCallback(
  155. [this](AzFramework::Cameras& cameras)
  156. {
  157. cameras.AddCamera(m_lookRotateCamera);
  158. cameras.AddCamera(m_lookTranslateCamera);
  159. cameras.AddCamera(m_lookScrollTranslationCamera);
  160. cameras.AddCamera(m_lookPanCamera);
  161. cameras.AddCamera(m_orbitCamera);
  162. });
  163. GetControllerList()->Add(controller);
  164. }
  165. void AnimViewportWidget::UpdateCameraViewMode(RenderOptions::CameraViewMode mode)
  166. {
  167. // Set the camera view mode.
  168. const AZ::Vector3 targetPosition = m_renderer->GetCharacterCenter();
  169. AZ::Vector3 cameraPosition;
  170. switch (mode)
  171. {
  172. case RenderOptions::CameraViewMode::FRONT:
  173. cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() + CameraDistance, targetPosition.GetZ());
  174. break;
  175. case RenderOptions::CameraViewMode::BACK:
  176. cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() - CameraDistance, targetPosition.GetZ());
  177. break;
  178. case RenderOptions::CameraViewMode::TOP:
  179. cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), CameraDistance + targetPosition.GetZ());
  180. break;
  181. case RenderOptions::CameraViewMode::BOTTOM:
  182. cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), -CameraDistance + targetPosition.GetZ());
  183. break;
  184. case RenderOptions::CameraViewMode::LEFT:
  185. cameraPosition.Set(targetPosition.GetX() - CameraDistance, targetPosition.GetY(), targetPosition.GetZ());
  186. break;
  187. case RenderOptions::CameraViewMode::RIGHT:
  188. cameraPosition.Set(targetPosition.GetX() + CameraDistance, targetPosition.GetY(), targetPosition.GetZ());
  189. break;
  190. case RenderOptions::CameraViewMode::DEFAULT:
  191. // The default view mode is looking from the top left of the character.
  192. const AZ::Vector3 displacement = AZ::Vector3(-1.0f, 1.0f, 1.0f).GetNormalized() * CameraDistance;
  193. cameraPosition = targetPosition + displacement;
  194. break;
  195. }
  196. GetViewportContext()->SetCameraTransform(AZ::Transform::CreateLookAt(cameraPosition, targetPosition));
  197. // only if we're in follow mode should we set the pivot to the target position
  198. // (when not following, the pivot will be the camera position until alt is pressed)
  199. if (m_plugin->GetRenderOptions()->GetCameraFollowUp())
  200. {
  201. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  202. GetViewportId(),
  203. &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotDetachedImmediate,
  204. targetPosition);
  205. }
  206. }
  207. void AnimViewportWidget::UpdateCameraFollowUp(bool followUp)
  208. {
  209. const auto lookAndOrbitCameras =
  210. AZStd::vector<AZStd::shared_ptr<AzFramework::CameraInput>>{ m_lookRotateCamera, m_lookTranslateCamera,
  211. m_lookScrollTranslationCamera, m_lookPanCamera, m_orbitCamera };
  212. const auto followCameras =
  213. AZStd::vector<AZStd::shared_ptr<AzFramework::CameraInput>>{ m_followRotateCamera, m_followScrollDollyCamera,
  214. m_followScrollMotionCamera };
  215. if (followUp)
  216. {
  217. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  218. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::RemoveCameras,
  219. lookAndOrbitCameras);
  220. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  221. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::AddCameras, followCameras);
  222. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  223. GetViewportId(),
  224. &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttachedImmediate,
  225. m_renderer->GetCharacterCenter());
  226. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  227. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffsetImmediate,
  228. AZ::Vector3::CreateAxisY(-CameraDistance));
  229. }
  230. else
  231. {
  232. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  233. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::RemoveCameras, followCameras);
  234. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  235. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::AddCameras, lookAndOrbitCameras);
  236. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  237. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffsetImmediate,
  238. AZ::Vector3::CreateZero());
  239. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  240. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttachedImmediate,
  241. GetViewportContext()->GetCameraTransform().GetTranslation());
  242. }
  243. }
  244. void AnimViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time)
  245. {
  246. RenderViewportWidget::OnTick(deltaTime, time);
  247. CalculateCameraProjection();
  248. RenderCustomPluginData();
  249. FollowCharacter();
  250. m_viewportUiManager.Update();
  251. }
  252. void AnimViewportWidget::CalculateCameraProjection()
  253. {
  254. auto viewportContext = GetViewportContext();
  255. auto windowSize = viewportContext->GetViewportSize();
  256. // Prevent division by zero
  257. const float height = AZStd::max<float>(aznumeric_cast<float>(windowSize.m_height), 1.0f);
  258. const float aspectRatio = aznumeric_cast<float>(windowSize.m_width) / height;
  259. const RenderOptions* renderOptions = m_plugin->GetRenderOptions();
  260. AZ::Matrix4x4 viewToClipMatrix;
  261. AZ::MakePerspectiveFovMatrixRH(
  262. viewToClipMatrix, AZ::DegToRad(renderOptions->GetFOV()), aspectRatio, renderOptions->GetNearClipPlaneDistance(),
  263. renderOptions->GetFarClipPlaneDistance(), true);
  264. viewportContext->GetDefaultView()->SetViewToClipMatrix(viewToClipMatrix);
  265. }
  266. void AnimViewportWidget::RenderCustomPluginData()
  267. {
  268. const EMotionFX::ActorRenderFlagsNamespace::ActorRenderFlags renderFlags = m_plugin->GetRenderOptions()->GetRenderFlags();
  269. for (EMStudioPlugin* plugin : GetPluginManager()->GetActivePlugins())
  270. {
  271. plugin->Render(renderFlags);
  272. }
  273. for (const AZStd::unique_ptr<PersistentPlugin>& plugin : GetPluginManager()->GetPersistentPlugins())
  274. {
  275. plugin->Render(renderFlags);
  276. }
  277. }
  278. void AnimViewportWidget::FollowCharacter()
  279. {
  280. if (m_plugin->GetRenderOptions()->GetCameraFollowUp())
  281. {
  282. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  283. GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached,
  284. m_renderer->GetCharacterCenter());
  285. m_renderer->UpdateGroundplane();
  286. }
  287. }
  288. void AnimViewportWidget::UpdateRenderFlags(EMotionFX::ActorRenderFlags renderFlags)
  289. {
  290. m_renderer->UpdateActorRenderFlag(renderFlags);
  291. m_plugin->UpdatePickingRenderFlags(renderFlags);
  292. }
  293. AZ::s32 AnimViewportWidget::GetViewportId() const
  294. {
  295. return GetViewportContext()->GetId();
  296. }
  297. void AnimViewportWidget::mousePressEvent(QMouseEvent* event)
  298. {
  299. m_pixelsSinceClick = 0;
  300. m_prevMousePoint = event->globalPos();
  301. }
  302. void AnimViewportWidget::mouseMoveEvent(QMouseEvent* event)
  303. {
  304. int deltaX = event->globalX() - m_prevMousePoint.x();
  305. int deltaY = event->globalY() - m_prevMousePoint.y();
  306. m_pixelsSinceClick += AZStd::abs(deltaX) + AZStd::abs(deltaY);
  307. }
  308. void AnimViewportWidget::mouseReleaseEvent(QMouseEvent* event)
  309. {
  310. if (event->button() == Qt::RightButton && m_pixelsSinceClick < MinMouseMovePixes)
  311. {
  312. OnContextMenuEvent(event);
  313. }
  314. }
  315. void AnimViewportWidget::OnContextMenuEvent(QMouseEvent* event)
  316. {
  317. QMenu* menu = new QMenu(this);
  318. {
  319. QMenu* cameraMenu = menu->addMenu("Camera Options");
  320. QAction* frontAction = cameraMenu->addAction("Front");
  321. QAction* backAction = cameraMenu->addAction("Back");
  322. QAction* topAction = cameraMenu->addAction("Top");
  323. QAction* bottomAction = cameraMenu->addAction("Bottom");
  324. QAction* leftAction = cameraMenu->addAction("Left");
  325. QAction* rightAction = cameraMenu->addAction("Right");
  326. cameraMenu->addSeparator();
  327. QAction* resetCamAction = cameraMenu->addAction("Reset Camera");
  328. cameraMenu->addSeparator();
  329. QAction* followAction = cameraMenu->addAction("Follow Character");
  330. followAction->setCheckable(true);
  331. followAction->setChecked(m_plugin->GetRenderOptions()->GetCameraFollowUp());
  332. connect(frontAction, &QAction::triggered, this, [this]()
  333. {
  334. UpdateCameraViewMode(RenderOptions::CameraViewMode::FRONT);
  335. });
  336. connect(backAction, &QAction::triggered, this, [this]()
  337. {
  338. UpdateCameraViewMode(RenderOptions::CameraViewMode::BACK);
  339. });
  340. connect(topAction, &QAction::triggered, this, [this]()
  341. {
  342. UpdateCameraViewMode(RenderOptions::CameraViewMode::TOP);
  343. });
  344. connect(bottomAction, &QAction::triggered, this, [this]()
  345. {
  346. UpdateCameraViewMode(RenderOptions::CameraViewMode::BOTTOM);
  347. });
  348. connect(leftAction, &QAction::triggered, this, [this]()
  349. {
  350. UpdateCameraViewMode(RenderOptions::CameraViewMode::LEFT);
  351. });
  352. connect(rightAction, &QAction::triggered, this, [this]()
  353. {
  354. UpdateCameraViewMode(RenderOptions::CameraViewMode::RIGHT);
  355. });
  356. connect(resetCamAction, &QAction::triggered, this, [this]()
  357. {
  358. UpdateCameraViewMode(RenderOptions::CameraViewMode::DEFAULT);
  359. });
  360. connect(followAction, &QAction::triggered, this, [this, followAction]()
  361. {
  362. m_plugin->GetRenderOptions()->SetCameraFollowUp(followAction->isChecked());
  363. AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateCameraFollowUp, followAction->isChecked());
  364. });
  365. }
  366. if (m_renderer && m_renderer->GetEntityId() != AZ::EntityId())
  367. {
  368. QAction* resetAction = menu->addAction("Move Character to Origin");
  369. connect(resetAction, &QAction::triggered, this, [this]()
  370. {
  371. m_renderer->MoveActorEntitiesToOrigin();
  372. UpdateCameraViewMode(RenderOptions::CameraViewMode::DEFAULT);
  373. });
  374. }
  375. if (!menu->isEmpty())
  376. {
  377. menu->popup(event->globalPos());
  378. }
  379. }
  380. void AnimViewportWidget::resizeEvent(QResizeEvent* event)
  381. {
  382. QWidget::resizeEvent(event);
  383. m_renderOverlay.setGeometry(geometry());
  384. m_viewportUiManager.Update();
  385. CalculateCameraProjection();
  386. }
  387. void AnimViewportWidget::OnBeginPrepareRender()
  388. {
  389. if (m_debugDisplay)
  390. {
  391. for (const auto* entity : m_renderer->GetActorEntities())
  392. {
  393. AzFramework::EntityDebugDisplayEventBus::Event(
  394. entity->GetId(),
  395. &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport,
  396. AzFramework::ViewportInfo{ GetViewportId() },
  397. *m_debugDisplay);
  398. }
  399. }
  400. }
  401. } // namespace EMStudio