@@ -973,57 +973,6 @@ namespace lfs::vis::gui {
973973 };
974974 }
975975
976- [[nodiscard]] std::optional<glm::vec2> projectPointToPanelScreen (
977- const VulkanGuidePanelTarget& panel,
978- const RenderSettings& settings,
979- const glm::vec3& world) {
980- const glm::mat3 rotation = panel.viewport ->getRotationMatrix ();
981- const glm::vec3 translation = panel.viewport ->getTranslation ();
982- const glm::vec3 view = glm::transpose (rotation) * (world - translation);
983-
984- if (settings.equirectangular ) {
985- const float len = glm::length (view);
986- if (!std::isfinite (len) || len <= 1e-6f ) {
987- return std::nullopt ;
988- }
989- const glm::vec3 dir = view / len;
990- const float ndc_x = std::atan2 (dir.x , -dir.z ) / glm::pi<float >();
991- const float ndc_y = -std::asin (std::clamp (dir.y , -1 .0f , 1 .0f )) /
992- (glm::pi<float >() * 0 .5f );
993- if (!std::isfinite (ndc_x) || !std::isfinite (ndc_y)) {
994- return std::nullopt ;
995- }
996- return panel.pos + glm::vec2 ((ndc_x * 0 .5f + 0 .5f ) * panel.size .x ,
997- (ndc_y * 0 .5f + 0 .5f ) * panel.size .y );
998- }
999-
1000- constexpr float kMinViewZ = -1e-4f ;
1001- if (view.z >= kMinViewZ ) {
1002- return std::nullopt ;
1003- }
1004-
1005- const float width = static_cast <float >(std::max (panel.render_size .x , 1 ));
1006- const float height = static_cast <float >(std::max (panel.render_size .y , 1 ));
1007- const float cx = width * 0 .5f ;
1008- const float cy = height * 0 .5f ;
1009- if (settings.orthographic ) {
1010- if (!std::isfinite (settings.ortho_scale ) || settings.ortho_scale <= 0 .0f ) {
1011- return std::nullopt ;
1012- }
1013- return renderToPanelScreen (panel, glm::vec2 (cx + view.x * settings.ortho_scale ,
1014- cy - view.y * settings.ortho_scale ));
1015- }
1016-
1017- const auto [fx, fy] = lfs::rendering::computePixelFocalLengths (
1018- panel.render_size , settings.focal_length_mm );
1019- const float depth = -view.z ;
1020- if (depth <= 0 .0f ) {
1021- return std::nullopt ;
1022- }
1023- return renderToPanelScreen (panel, glm::vec2 (cx + view.x * fx / depth,
1024- cy - view.y * fy / depth));
1025- }
1026-
1027976 [[nodiscard]] bool projectedQuadVisible (const std::array<glm::vec2, 4 >& points,
1028977 const VulkanGuidePanelTarget& panel) {
1029978 glm::vec2 min_point (std::numeric_limits<float >::max ());
@@ -2068,46 +2017,6 @@ namespace lfs::vis::gui {
20682017 return visualizer_camera_to_world * fov_scale;
20692018 }
20702019
2071- void appendPerspectiveCameraFrustum (VulkanViewportPassParams& params,
2072- const VulkanGuidePanelTarget& panel,
2073- const RenderSettings& settings,
2074- const glm::mat4& model,
2075- const glm::vec4& color) {
2076- constexpr std::array local_points{
2077- glm::vec3 (-0 .5f , -0 .5f , -1 .0f ),
2078- glm::vec3 (0 .5f , -0 .5f , -1 .0f ),
2079- glm::vec3 (0 .5f , 0 .5f , -1 .0f ),
2080- glm::vec3 (-0 .5f , 0 .5f , -1 .0f ),
2081- glm::vec3 (0 .0f , 0 .0f , 0 .0f ),
2082- };
2083- constexpr std::array<std::pair<int , int >, 8 > edges{{
2084- {0 , 1 },
2085- {1 , 2 },
2086- {2 , 3 },
2087- {3 , 0 },
2088- {0 , 4 },
2089- {1 , 4 },
2090- {2 , 4 },
2091- {3 , 4 },
2092- }};
2093-
2094- std::array<glm::vec3, local_points.size ()> world_points{};
2095- for (size_t i = 0 ; i < local_points.size (); ++i) {
2096- world_points[i] = glm::vec3 (model * glm::vec4 (local_points[i], 1 .0f ));
2097- }
2098- for (const auto & [a, b] : edges) {
2099- addProjectedOverlayLine (params.overlay_triangles ,
2100- params,
2101- panel,
2102- settings,
2103- world_points[static_cast <size_t >(a)],
2104- world_points[static_cast <size_t >(b)],
2105- color,
2106- 1 .5f ,
2107- true );
2108- }
2109- }
2110-
21112020 void appendEquirectangularCameraFrustum (VulkanViewportPassParams& params,
21122021 const VulkanGuidePanelTarget& panel,
21132022 const RenderSettings& settings,
@@ -2218,9 +2127,58 @@ namespace lfs::vis::gui {
22182127 }
22192128
22202129 constexpr float kMinRenderAlpha = 0 .01f ;
2221- const glm::vec3 view_position = panel.viewport ->getTranslation ();
2130+ const glm::mat3 panel_rotation = panel.viewport ->getRotationMatrix ();
2131+ const glm::vec3 panel_translation = panel.viewport ->getTranslation ();
2132+ const glm::mat3 world_to_panel_rotation = glm::transpose (panel_rotation);
2133+ const glm::vec3 view_position = panel_translation;
2134+ const float panel_render_width = static_cast <float >(std::max (panel.render_size .x , 1 ));
2135+ const float panel_render_height = static_cast <float >(std::max (panel.render_size .y , 1 ));
2136+ const float panel_cx = panel_render_width * 0 .5f ;
2137+ const float panel_cy = panel_render_height * 0 .5f ;
2138+ const auto [panel_fx, panel_fy] =
2139+ lfs::rendering::computePixelFocalLengths (panel.render_size , settings.focal_length_mm );
2140+ const auto project_panel_point = [&](const glm::vec3& world) -> std::optional<glm::vec2> {
2141+ const glm::vec3 view = world_to_panel_rotation * (world - panel_translation);
2142+ if (settings.equirectangular ) {
2143+ const float len = glm::length (view);
2144+ if (!std::isfinite (len) || len <= 1e-6f ) {
2145+ return std::nullopt ;
2146+ }
2147+ const glm::vec3 dir = view / len;
2148+ const float ndc_x = std::atan2 (dir.x , -dir.z ) / glm::pi<float >();
2149+ const float ndc_y = -std::asin (std::clamp (dir.y , -1 .0f , 1 .0f )) /
2150+ (glm::pi<float >() * 0 .5f );
2151+ if (!std::isfinite (ndc_x) || !std::isfinite (ndc_y)) {
2152+ return std::nullopt ;
2153+ }
2154+ return panel.pos + glm::vec2 ((ndc_x * 0 .5f + 0 .5f ) * panel.size .x ,
2155+ (ndc_y * 0 .5f + 0 .5f ) * panel.size .y );
2156+ }
2157+
2158+ constexpr float kMinViewZ = -1e-4f ;
2159+ if (view.z >= kMinViewZ ) {
2160+ return std::nullopt ;
2161+ }
2162+ if (settings.orthographic ) {
2163+ if (!std::isfinite (settings.ortho_scale ) || settings.ortho_scale <= 0 .0f ) {
2164+ return std::nullopt ;
2165+ }
2166+ return renderToPanelScreen (panel, glm::vec2 (panel_cx + view.x * settings.ortho_scale ,
2167+ panel_cy - view.y * settings.ortho_scale ));
2168+ }
2169+
2170+ const float depth = -view.z ;
2171+ if (depth <= 0 .0f ) {
2172+ return std::nullopt ;
2173+ }
2174+ return renderToPanelScreen (panel, glm::vec2 (panel_cx + view.x * panel_fx / depth,
2175+ panel_cy - view.y * panel_fy / depth));
2176+ };
22222177 size_t background_thumbnail_requests = 0 ;
22232178 constexpr size_t kBackgroundThumbnailRequestsPerFrame = 16 ;
2179+ const std::uint32_t frustum_first_instance =
2180+ static_cast <std::uint32_t >(params.frustum_instances .size ());
2181+ params.frustum_instances .reserve (params.frustum_instances .size () + cameras.size ());
22242182 for (size_t i = 0 ; i < cameras.size (); ++i) {
22252183 const auto & camera = cameras[i];
22262184 if (!camera) {
@@ -2274,18 +2232,16 @@ namespace lfs::vis::gui {
22742232 std::array<glm::vec2, image_corners.size ()> screen_points{};
22752233 std::array<float , image_corners.size ()> corner_depths{};
22762234 bool quad_visible = true ;
2277- const glm::mat3 panel_rotation = panel.viewport ->getRotationMatrix ();
2278- const glm::vec3 panel_translation = panel.viewport ->getTranslation ();
22792235 for (size_t corner = 0 ; corner < image_corners.size (); ++corner) {
22802236 const glm::vec3 world_point =
22812237 glm::vec3 ((*model) * glm::vec4 (image_corners[corner], 1 .0f ));
2282- const auto projected = projectPointToPanelScreen (panel, settings, world_point);
2238+ const auto projected = project_panel_point ( world_point);
22832239 if (!projected) {
22842240 quad_visible = false ;
22852241 break ;
22862242 }
22872243 screen_points[corner] = *projected;
2288- const glm::vec3 view = glm::transpose (panel_rotation) * (world_point - panel_translation);
2244+ const glm::vec3 view = world_to_panel_rotation * (world_point - panel_translation);
22892245 corner_depths[corner] = settings.equirectangular ? glm::length (view) : -view.z ;
22902246 }
22912247 quad_visible = quad_visible && projectedQuadVisible (screen_points, panel);
@@ -2310,10 +2266,32 @@ namespace lfs::vis::gui {
23102266 {emphasis_mix, disabled_mix, 0 .0f , 0 .0f },
23112267 corner_depths);
23122268 }
2313- appendPerspectiveCameraFrustum (params, panel, settings, *model, color);
2269+ params.frustum_instances .push_back (VulkanViewportFrustumInstance{
2270+ .model = *model,
2271+ .color = color,
2272+ });
23142273 }
23152274 }
23162275
2276+ const std::uint32_t frustum_instance_count =
2277+ static_cast <std::uint32_t >(params.frustum_instances .size ()) - frustum_first_instance;
2278+ if (frustum_instance_count > 0 ) {
2279+ const glm::mat4 frustum_view =
2280+ lfs::rendering::makeViewMatrix (panel_rotation, panel_translation);
2281+ params.frustum_batches .push_back (VulkanViewportFrustumBatch{
2282+ .view = frustum_view,
2283+ .viewport_pos = panel.pos ,
2284+ .viewport_size = panel.size ,
2285+ .render_size = glm::vec2 (panel.render_size ),
2286+ .focal_x = settings.orthographic ? settings.ortho_scale : panel_fx,
2287+ .focal_y = settings.orthographic ? settings.ortho_scale : panel_fy,
2288+ .orthographic = settings.orthographic ,
2289+ .equirectangular = settings.equirectangular ,
2290+ .first_instance = frustum_first_instance,
2291+ .instance_count = frustum_instance_count,
2292+ });
2293+ }
2294+
23172295 if (thumbnail_cache.hasPendingWork ()) {
23182296 rendering_manager.markDirty (DirtyFlag::OVERLAY );
23192297 }
0 commit comments