camera_augment_helper_v2.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #include "camera_augment_helper_v2_impl.h"
  2. #include "core/math_helper.hpp"
  3. #include "core/imgui_utility.hpp"
  4. #include "module/guidance/cursor_guide.h"
  5. #include <glm/gtc/matrix_transform.hpp>
  6. #include <glm/gtc/type_ptr.hpp>
  7. #include <glm/gtx/rotate_vector.hpp>
  8. #include <boost/asio/post.hpp>
  9. using boost::asio::post;
  10. void camera_augment_helper_v2::impl::freedom_info_type::reset() {
  11. if (auto &mat = pimpl->tracked_transform; mat.has_value()) {
  12. static constexpr auto default_focal_length = 8.0f; // 8mm
  13. eye = glm::vec3((*mat)[3]);
  14. auto rot_part = glm::mat3(*mat);
  15. center = eye + rot_part[2] * default_focal_length;
  16. view_up = -rot_part[1];
  17. } else {
  18. eye = glm::vec3();
  19. center = glm::vec3(0.f, 0.f, 100.f);
  20. view_up = glm::vec3(0.0f, -1.0f, 0.0f);
  21. }
  22. }
  23. glm::mat4 camera_augment_helper_v2::impl::freedom_info_type::to_transform() {
  24. // normalize view up
  25. view_up -= view_dir() * glm::dot(view_up, view_dir());
  26. view_up = glm::normalize(view_up);
  27. auto ret = glm::inverse(glm::lookAt(eye, center, view_up));
  28. ret = glm::rotate(ret, glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // viewport -> camera
  29. return ret;
  30. }
  31. glm::vec3 camera_augment_helper_v2::impl::freedom_info_type::view_dir() const {
  32. return glm::normalize(center - eye);
  33. }
  34. float camera_augment_helper_v2::impl::freedom_info_type::view_dis() const {
  35. return glm::distance(center, eye);
  36. }
  37. void camera_augment_helper_v2::impl::freedom_info_type::translate(glm::vec3 offset) {
  38. eye += offset;
  39. center += offset;
  40. }
  41. void camera_augment_helper_v2::impl::freedom_info_type::forward(float dis) {
  42. translate(view_dir() * dis);
  43. }
  44. void camera_augment_helper_v2::impl::freedom_info_type::move_right(float dis) {
  45. auto axis = glm::cross(view_up, view_dir());
  46. translate(-axis * dis);
  47. }
  48. void camera_augment_helper_v2::impl::freedom_info_type::move_up(float dis) {
  49. translate(view_up * dis);
  50. }
  51. void camera_augment_helper_v2::impl::freedom_info_type::center_forward(float dis) {
  52. center = eye + view_dir() * (view_dis() + dis);
  53. }
  54. void camera_augment_helper_v2::impl::freedom_info_type::roll(float deg) {
  55. view_up = glm::rotate(view_up, glm::radians(deg), view_dir());
  56. }
  57. void camera_augment_helper_v2::impl::freedom_info_type::yaw(float deg) {
  58. auto next_view_dir = glm::rotate(view_dir(), glm::radians(deg), view_up);
  59. center = eye + next_view_dir * view_dis();
  60. }
  61. void camera_augment_helper_v2::impl::freedom_info_type::pitch(float deg) {
  62. auto rot_axis = glm::cross(view_up, view_dir());
  63. view_up = glm::rotate(view_up, glm::radians(deg), rot_axis);
  64. auto next_view_dir = glm::rotate(view_dir(), glm::radians(deg), rot_axis);
  65. center = eye + next_view_dir * view_dis();
  66. }
  67. glm::mat4 camera_augment_helper_v2::impl::fixed_info_type::extra_transform() const {
  68. return to_transform_mat(extra_offset, glm::radians(extra_rotation));
  69. }
  70. camera_augment_helper_v2::impl::impl(const create_config &conf) {
  71. manager = conf.manager;
  72. act_guide = conf.act_guide;
  73. sophiar_conn = conf.sophiar_conn;
  74. ctx = conf.ctx;
  75. pre_render_conn = manager->pre_render_sig.connect(
  76. [this](auto info) { pre_render_slot(info); });
  77. switch (conf.camera.index()) {
  78. case 1: {
  79. mode = MODE_FREEDOM;
  80. auto info = std::get<1>(conf.camera);
  81. transform_var = info.transform_var;
  82. freedom_info.pimpl = this;
  83. break;
  84. }
  85. case 2: {
  86. mode = MODE_FIXED;
  87. auto info = std::get<2>(conf.camera);
  88. fov = info.fov;
  89. transform_var = info.transform_var;
  90. break;
  91. }
  92. case 3: {
  93. mode = MODE_RELATIVE;
  94. auto info = std::get<3>(conf.camera);
  95. relative_info.parent = info.parent->pimpl.get();
  96. relative_info.transform = info.transform;
  97. break;
  98. }
  99. default: {
  100. RET_ERROR;
  101. }
  102. }
  103. }
  104. camera_augment_helper_v2::impl::~impl() {
  105. pre_render_conn.disconnect();
  106. }
  107. void camera_augment_helper_v2::impl::update_tracked_transform() {
  108. if (sophiar_conn == nullptr) return;
  109. auto trans = sophiar_conn->
  110. query_transform_variable(transform_var);
  111. is_missing = !trans.has_value();
  112. if (trans.has_value()) {
  113. auto cur_ts = current_timestamp();
  114. track_pool.add(to_mat4(*trans), cur_ts);
  115. tracked_transform = track_pool.query(cur_ts + time_offset);
  116. track_pool.remove_old(-time_offset);
  117. } else {
  118. tracked_transform = {};
  119. }
  120. }
  121. void camera_augment_helper_v2::impl::update_freedom() {
  122. update_tracked_transform();
  123. transform = freedom_info.to_transform();
  124. is_missing = false;
  125. }
  126. void camera_augment_helper_v2::impl::update_fixed() {
  127. assert(sophiar_conn != nullptr);
  128. update_tracked_transform();
  129. if (tracked_transform.has_value()) {
  130. auto extra_mat = fixed_info.extra_transform();
  131. transform = *tracked_transform * extra_mat;
  132. }
  133. }
  134. void camera_augment_helper_v2::impl::update_relative() {
  135. auto par = relative_info.parent;
  136. par->update_transform();
  137. is_missing = par->is_missing;
  138. transform = par->transform * relative_info.transform;
  139. fov = par->fov;
  140. }
  141. void camera_augment_helper_v2::impl::update_transform() {
  142. switch (mode) {
  143. // @formatter:off
  144. case MODE_FREEDOM: { update_freedom(); break; }
  145. case MODE_RELATIVE: { update_relative(); break; }
  146. case MODE_FIXED: { update_fixed(); break; }
  147. // @formatter:on
  148. }
  149. }
  150. void camera_augment_helper_v2::impl::update_camera() {
  151. update_transform();
  152. last_camera = camera_info{
  153. .transform = transform, .fov = fov,
  154. .near = ui->near, .far = ui->far
  155. };
  156. }
  157. void camera_augment_helper_v2::impl::render() {
  158. update_camera();
  159. if (!is_missing || ui->ignore_missing) {
  160. last_vp_size = query_viewport_size();
  161. manager->record_current_camera_helper(q_this);
  162. manager->render(last_camera);
  163. }
  164. }
  165. void camera_augment_helper_v2::impl::render_image(output_config conf) {
  166. fbo_conf.size = conf.size;
  167. fbo.create(fbo_conf);
  168. if (img_downloader == nullptr) [[unlikely]] {
  169. img_downloader = std::make_unique<viewport_downloader>(
  170. viewport_downloader::create_config{.stream = conf.stream});
  171. }
  172. fbo.bind();
  173. render();
  174. auto out_img = img_downloader->download_v2();
  175. OBJ_SAVE(conf.img_name, out_img);
  176. fbo.unbind();
  177. }
  178. void camera_augment_helper_v2::impl::show_freedom() {
  179. auto &info = freedom_info;
  180. if (ImGui::Button("Reset")) {
  181. freedom_info.reset();
  182. }
  183. if (ImGui::TreeNode("Center")) {
  184. if (ImGui::Button("X+")) { info.move_right(info.linear_speed); }
  185. ImGui::SameLine();
  186. if (ImGui::Button("Y+")) { info.move_up(info.linear_speed); }
  187. ImGui::SameLine();
  188. if (ImGui::Button("Z+")) { info.forward(info.linear_speed); }
  189. // ImGui::SameLine();
  190. // if (ImGui::Button("D+")) { info.center_forward(info.linear_speed); }
  191. if (ImGui::Button("X-")) { info.move_right(-info.linear_speed); }
  192. ImGui::SameLine();
  193. if (ImGui::Button("Y-")) { info.move_up(-info.linear_speed); }
  194. ImGui::SameLine();
  195. if (ImGui::Button("Z-")) { info.forward(-info.linear_speed); }
  196. // ImGui::SameLine();
  197. // if (ImGui::Button("D-")) { info.center_forward(-info.linear_speed); }
  198. ImGui::TreePop();
  199. }
  200. if (ImGui::TreeNode("Eye")) {
  201. if (ImGui::Button("Ro+")) { info.roll(info.angle_speed); } // roll
  202. ImGui::SameLine();
  203. if (ImGui::Button("Ya+")) { info.yaw(info.angle_speed); } // yaw
  204. ImGui::SameLine();
  205. if (ImGui::Button("Pi+")) { info.pitch(info.angle_speed); } // pitch
  206. if (ImGui::Button("Ro-")) { info.roll(-info.angle_speed); } // roll
  207. ImGui::SameLine();
  208. if (ImGui::Button("Ya-")) { info.yaw(-info.angle_speed); } // yaw
  209. ImGui::SameLine();
  210. if (ImGui::Button("Pi-")) { info.pitch(-info.angle_speed); } // pitch
  211. ImGui::TreePop();
  212. }
  213. if (ImGui::TreeNode("Extra")) {
  214. ImGui::SliderFloat("Angular Step", &info.angle_speed, 0.01f, 10.0f, "%.2f");
  215. ImGui::SliderFloat("Linear Step", &info.linear_speed, 0.01f, 100.0f, "%.2f");
  216. ImGui::DragFloat("FOV (deg)", &fov, 0.5f, 10.0f, 178.0f, "%.01f");
  217. ImGui::TreePop();
  218. }
  219. }
  220. void camera_augment_helper_v2::impl::show_fixed() {
  221. ImGui::DragFloat3("Offset (mm)", glm::value_ptr(fixed_info.extra_offset),
  222. 0.05f, 0.0f, 0.0f, "%.02f");
  223. ImGui::DragFloat3("Offset (deg)", glm::value_ptr(fixed_info.extra_rotation),
  224. 0.1f, -180.0f, 180.0f, "%.01f");
  225. }
  226. void camera_augment_helper_v2::impl::show() {
  227. ImGui::Checkbox("Ignore Missing", &ui->ignore_missing); // TODO: enable sync with another
  228. if (allow_active_guide) {
  229. ImGui::SameLine();
  230. ImGui::Checkbox("Guidance", &ui->enable_active_guide);
  231. }
  232. ImGui::SliderFloat("Clip Near", &ui->near, 1.0f, ui->far, "%.f", ImGuiSliderFlags_Logarithmic);
  233. ImGui::SliderFloat("Clip Far", &ui->far, ui->near, 10000.0f, "%.f", ImGuiSliderFlags_Logarithmic);
  234. switch (mode) {
  235. // @formatter:off
  236. case MODE_FIXED: { show_fixed(); break; }
  237. case MODE_RELATIVE: { break; }
  238. case MODE_FREEDOM: { show_freedom(); break; }
  239. // @formatter:on
  240. default: {
  241. RET_ERROR;
  242. }
  243. }
  244. if (ui->enable_active_guide) {
  245. ImGui::SeparatorText("Cursor Guidance");
  246. act_guide->show();
  247. }
  248. }
  249. std::optional<glm::vec3> camera_augment_helper_v2::impl::
  250. get_cursor_coordinate(glm::vec2 s_pos) {
  251. auto w = last_vp_size.width, h = last_vp_size.height;
  252. if (s_pos.x < 0 || s_pos.x > w) return {};
  253. if (s_pos.y < 0 || s_pos.y > h) return {};
  254. s_pos.y = h - s_pos.y; // flip y to texture coordinate
  255. float depth;
  256. glReadPixels(s_pos.x, s_pos.y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
  257. if (depth == 1.f) return {};
  258. auto proj = last_camera.projection(last_vp_size.aspectRatio());
  259. auto ndc = glm::vec3(s_pos.x / w, s_pos.y / h, depth);
  260. auto c_pos_h = glm::inverse(proj) * to_homo(2.f * ndc - 1.f);
  261. auto c_pos = from_homo(c_pos_h);
  262. auto cam_mat = glm::rotate(last_camera.transform,
  263. glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // camera -> viewport
  264. auto w_pos_h = cam_mat * to_homo(c_pos);
  265. auto w_pos = from_homo(w_pos_h);
  266. return w_pos;
  267. }
  268. void camera_augment_helper_v2::impl::pre_render_slot(const scene_ptr &info) {
  269. if (ui->enable_active_guide && allow_active_guide) {
  270. auto rec_info = scene_render_info::custom_info{
  271. .func = [this] {
  272. if (manager->get_current_camera_helper() != q_this) {
  273. return; // not current camera helper
  274. }
  275. auto s_pos = ImGui::GetMousePos();
  276. auto info = cursor_guide::guide_info{
  277. .position = get_cursor_coordinate(to_vec2(s_pos))
  278. };
  279. auto &io = ImGui::GetIO();
  280. if (!io.WantCaptureMouse) {
  281. info.mouse_left = io.MouseClicked[ImGuiMouseButton_Left];
  282. info.mouse_right = io.MouseClicked[ImGuiMouseButton_Right];
  283. info.mouse_wheel = io.MouseWheel;
  284. }
  285. act_guide->update(info);
  286. },
  287. };
  288. info->items.push_back({.info = rec_info});
  289. act_guide->pre_render_slot(info);
  290. }
  291. // TODO: not implemented
  292. // if (enable_passive_guide) {
  293. // auto rec_info = scene_render_info::custom_info{
  294. // .func = [=, this] {
  295. // auto w_pos = get_cursor_coordinate(pas_info.pos);
  296. // pas_guide.update({.position = w_pos});
  297. // },
  298. // };
  299. // info->items.push_back({.info = rec_info});
  300. // pas_guide.pre_render_slot(info);
  301. // }
  302. }
  303. camera_augment_helper_v2::camera_augment_helper_v2(const create_config &conf)
  304. : pimpl(std::make_unique<impl>(conf)) {
  305. pimpl->q_this = this;
  306. }
  307. camera_augment_helper_v2::~camera_augment_helper_v2() = default;
  308. void camera_augment_helper_v2::render() {
  309. pimpl->render();
  310. }
  311. void camera_augment_helper_v2::render_image(output_config conf) {
  312. pimpl->render_image(conf);
  313. }
  314. void camera_augment_helper_v2::show() {
  315. pimpl->show();
  316. }
  317. void camera_augment_helper_v2::sync_with(camera_augment_helper_v2 *other) {
  318. pimpl->ui = other->pimpl->ui;
  319. }
  320. camera_info camera_augment_helper_v2::get_camera() {
  321. pimpl->update_camera();
  322. return pimpl->last_camera;
  323. }
  324. void camera_augment_helper_v2::set_fixed_transform_latency(int offset) {
  325. pimpl->time_offset = offset;
  326. }
  327. void camera_augment_helper_v2::set_active_guidance(bool flag) {
  328. pimpl->allow_active_guide = flag;
  329. }
  330. void camera_augment_helper_v2::set_passive_guidance(bool flag, const guide_info &info) {
  331. pimpl->enable_passive_guide = flag;
  332. pimpl->pas_info = info;
  333. }