diff --git a/include/neural-graphics-primitives/camera_path.h b/include/neural-graphics-primitives/camera_path.h index 9d121757233a323295f0f722f2025df523b0dffe..96a0e8c31b54e7a6ca7f69b36e2c8a276f467018 100644 --- a/include/neural-graphics-primitives/camera_path.h +++ b/include/neural-graphics-primitives/camera_path.h @@ -139,7 +139,7 @@ struct CameraPath { #ifdef NGP_GUI void add_debug_line(ImDrawList* list, const Eigen::Matrix<float, 4, 4>&proj, Eigen::Vector3f a, Eigen::Vector3f b, uint32_t col = 0xffffffff, float thickness = 1.0f); -void visualize_unit_cube(ImDrawList* list, const Eigen::Matrix<float, 4, 4>& world2proj, const Eigen::Vector3f& a, const Eigen::Vector3f& b, const Eigen::Matrix3f& render_aabb_to_local); +void visualize_cube(ImDrawList* list, const Eigen::Matrix<float, 4, 4>& world2proj, const Eigen::Vector3f& a, const Eigen::Vector3f& b, const Eigen::Matrix3f& render_aabb_to_local); void visualize_nerf_camera(ImDrawList* list, const Eigen::Matrix<float, 4, 4>& world2proj, const Eigen::Matrix<float, 3, 4>& xform, float aspect, uint32_t col = 0x80ffffff, float thickness = 1.0f); #endif diff --git a/include/neural-graphics-primitives/testbed.h b/include/neural-graphics-primitives/testbed.h index c8ade4596ed2095dd8a9c13aee6aeb32da6f14ce..cb5c9dea856bf57a40085457176fa2c8d017ed8a 100644 --- a/include/neural-graphics-primitives/testbed.h +++ b/include/neural-graphics-primitives/testbed.h @@ -944,6 +944,7 @@ public: bool m_visualize_unit_cube = false; bool m_edit_render_aabb = false; + bool m_edit_world_transform = true; bool m_snap_to_pixel_centers = false; diff --git a/src/camera_path.cu b/src/camera_path.cu index 6b8953ce339c6dbff353012d9ca975afba970250..463e05faddc8b8633c7be808358ee2d1f4c31381 100644 --- a/src/camera_path.cu +++ b/src/camera_path.cu @@ -276,7 +276,7 @@ void add_debug_line(ImDrawList* list, const Matrix<float, 4, 4>& proj, Vector3f } } -void visualize_unit_cube(ImDrawList* list, const Matrix<float, 4, 4>& world2proj, const Vector3f& a, const Vector3f& b, const Matrix3f& render_aabb_to_local) { +void visualize_cube(ImDrawList* list, const Matrix<float, 4, 4>& world2proj, const Vector3f& a, const Vector3f& b, const Matrix3f& render_aabb_to_local) { Eigen::Matrix3f m = render_aabb_to_local.transpose(); add_debug_line(list, world2proj, m * Vector3f{a.x(), a.y(), a.z()}, m * Vector3f{a.x(), a.y(), b.z()}, 0xffff4040); // Z add_debug_line(list, world2proj, m * Vector3f{b.x(), a.y(), a.z()}, m * Vector3f{b.x(), a.y(), b.z()}, 0xffffffff); diff --git a/src/testbed.cu b/src/testbed.cu index f87d0c10fe814293ca618cd4185d27c45ec1397d..7b40794846b78a33a62241c4d6eac9192fea5efa 100644 --- a/src/testbed.cu +++ b/src/testbed.cu @@ -479,7 +479,6 @@ void Testbed::reset_camera() { m_camera.col(3) -= m_scale * view_dir(); m_smoothed_camera = m_camera; - m_up_dir = {0.0f, 1.0f, 0.0f}; m_sun_dir = Vector3f::Ones().normalized(); reset_accumulation(); @@ -1011,59 +1010,88 @@ void Testbed::imgui() { float max_diam = (m_aabb.max-m_aabb.min).maxCoeff(); float render_diam = (m_render_aabb.max-m_render_aabb.min).maxCoeff(); float old_render_diam = render_diam; - if (ImGui::SliderFloat("Crop size", &render_diam, 0.1f, max_diam, "%.3f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat)) { - accum_reset = true; - if (old_render_diam > 0.f && render_diam > 0.f) { - const Vector3f center = (m_render_aabb.max + m_render_aabb.min) * 0.5f; - float scale = render_diam / old_render_diam; - m_render_aabb.max = ((m_render_aabb.max-center) * scale + center).cwiseMin(m_aabb.max); - m_render_aabb.min = ((m_render_aabb.min-center) * scale + center).cwiseMax(m_aabb.min); + + if (m_testbed_mode == ETestbedMode::Nerf || m_testbed_mode == ETestbedMode::Volume) { + if (ImGui::SliderFloat("Crop size", &render_diam, 0.1f, max_diam, "%.3f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat)) { + accum_reset = true; + if (old_render_diam > 0.f && render_diam > 0.f) { + const Vector3f center = (m_render_aabb.max + m_render_aabb.min) * 0.5f; + float scale = render_diam / old_render_diam; + m_render_aabb.max = ((m_render_aabb.max-center) * scale + center).cwiseMin(m_aabb.max); + m_render_aabb.min = ((m_render_aabb.min-center) * scale + center).cwiseMax(m_aabb.min); + } } } - if (ImGui::TreeNode("Crop aabb")) { + std::string transform_section_name = "World transform"; + if (m_testbed_mode == ETestbedMode::Nerf) { + transform_section_name += " & Crop box"; + } + + if (ImGui::TreeNode(transform_section_name.c_str())) { m_edit_render_aabb = true; - accum_reset |= ImGui::SliderFloat("Min x", ((float*)&m_render_aabb.min)+0, m_aabb.min.x(), m_render_aabb.max.x(), "%.3f"); - accum_reset |= ImGui::SliderFloat("Min y", ((float*)&m_render_aabb.min)+1, m_aabb.min.y(), m_render_aabb.max.y(), "%.3f"); - accum_reset |= ImGui::SliderFloat("Min z", ((float*)&m_render_aabb.min)+2, m_aabb.min.z(), m_render_aabb.max.z(), "%.3f"); - ImGui::Separator(); - accum_reset |= ImGui::SliderFloat("Max x", ((float*)&m_render_aabb.max)+0, m_render_aabb.min.x(), m_aabb.max.x(), "%.3f"); - accum_reset |= ImGui::SliderFloat("Max y", ((float*)&m_render_aabb.max)+1, m_render_aabb.min.y(), m_aabb.max.y(), "%.3f"); - accum_reset |= ImGui::SliderFloat("Max z", ((float*)&m_render_aabb.max)+2, m_render_aabb.min.z(), m_aabb.max.z(), "%.3f"); - ImGui::Separator(); - Vector3f diag = m_render_aabb.diag(); - bool edit_diag = false; - float max_diag = m_aabb.diag().maxCoeff(); - edit_diag |= ImGui::SliderFloat("Size x", ((float*)&diag)+0, 0.001f, max_diag, "%.3f"); - edit_diag |= ImGui::SliderFloat("Size y", ((float*)&diag)+1, 0.001f, max_diag, "%.3f"); - edit_diag |= ImGui::SliderFloat("Size z", ((float*)&diag)+2, 0.001f, max_diag, "%.3f"); - if (edit_diag) { - accum_reset = true; - Vector3f cen = m_render_aabb.center(); - m_render_aabb = BoundingBox(cen - diag * 0.5f, cen + diag * 0.5f); - } - if (ImGui::Button("Reset")) { - accum_reset = true; - m_render_aabb = m_aabb; - m_render_aabb_to_local = Matrix3f::Identity(); + + if (ImGui::RadioButton("Translate world", m_camera_path.m_gizmo_op == ImGuizmo::TRANSLATE && m_edit_world_transform)) { + m_camera_path.m_gizmo_op = ImGuizmo::TRANSLATE; + m_edit_world_transform = true; } + ImGui::SameLine(); - if (ImGui::Button("Reset Rotation Only")) { - accum_reset = true; - Eigen::Vector3f world_cen = m_render_aabb_to_local.transpose() * m_render_aabb.center(); - m_render_aabb_to_local = Matrix3f::Identity(); - Eigen::Vector3f new_cen = m_render_aabb_to_local * world_cen; - Eigen::Vector3f old_cen = m_render_aabb.center(); - m_render_aabb.min += new_cen - old_cen; - m_render_aabb.max += new_cen - old_cen; + if (ImGui::RadioButton("Rotate world", m_camera_path.m_gizmo_op == ImGuizmo::ROTATE && m_edit_world_transform)) { + m_camera_path.m_gizmo_op = ImGuizmo::ROTATE; + m_edit_world_transform = true; } - if (/*m_visualize_unit_cube*/ 1) { - if (ImGui::RadioButton("Translate", m_camera_path.m_gizmo_op == ImGuizmo::TRANSLATE)) + + if (m_testbed_mode == ETestbedMode::Nerf) { + if (ImGui::RadioButton("Translate crop box", m_camera_path.m_gizmo_op == ImGuizmo::TRANSLATE && !m_edit_world_transform)) { m_camera_path.m_gizmo_op = ImGuizmo::TRANSLATE; + m_edit_world_transform = false; + } + ImGui::SameLine(); - if (ImGui::RadioButton("Rotate", m_camera_path.m_gizmo_op == ImGuizmo::ROTATE)) + if (ImGui::RadioButton("Rotate crop box", m_camera_path.m_gizmo_op == ImGuizmo::ROTATE && !m_edit_world_transform)) { m_camera_path.m_gizmo_op = ImGuizmo::ROTATE; + m_edit_world_transform = false; + } + + accum_reset |= ImGui::SliderFloat("Min x", ((float*)&m_render_aabb.min)+0, m_aabb.min.x(), m_render_aabb.max.x(), "%.3f"); + accum_reset |= ImGui::SliderFloat("Min y", ((float*)&m_render_aabb.min)+1, m_aabb.min.y(), m_render_aabb.max.y(), "%.3f"); + accum_reset |= ImGui::SliderFloat("Min z", ((float*)&m_render_aabb.min)+2, m_aabb.min.z(), m_render_aabb.max.z(), "%.3f"); + ImGui::Separator(); + accum_reset |= ImGui::SliderFloat("Max x", ((float*)&m_render_aabb.max)+0, m_render_aabb.min.x(), m_aabb.max.x(), "%.3f"); + accum_reset |= ImGui::SliderFloat("Max y", ((float*)&m_render_aabb.max)+1, m_render_aabb.min.y(), m_aabb.max.y(), "%.3f"); + accum_reset |= ImGui::SliderFloat("Max z", ((float*)&m_render_aabb.max)+2, m_render_aabb.min.z(), m_aabb.max.z(), "%.3f"); + ImGui::Separator(); + Vector3f diag = m_render_aabb.diag(); + bool edit_diag = false; + float max_diag = m_aabb.diag().maxCoeff(); + edit_diag |= ImGui::SliderFloat("Size x", ((float*)&diag)+0, 0.001f, max_diag, "%.3f"); + edit_diag |= ImGui::SliderFloat("Size y", ((float*)&diag)+1, 0.001f, max_diag, "%.3f"); + edit_diag |= ImGui::SliderFloat("Size z", ((float*)&diag)+2, 0.001f, max_diag, "%.3f"); + if (edit_diag) { + accum_reset = true; + Vector3f cen = m_render_aabb.center(); + m_render_aabb = BoundingBox(cen - diag * 0.5f, cen + diag * 0.5f); + } + + if (ImGui::Button("Reset crop box")) { + accum_reset = true; + m_render_aabb = m_aabb; + m_render_aabb_to_local = Matrix3f::Identity(); + } + + ImGui::SameLine(); + if (ImGui::Button("rotation only")) { + accum_reset = true; + Eigen::Vector3f world_cen = m_render_aabb_to_local.transpose() * m_render_aabb.center(); + m_render_aabb_to_local = Matrix3f::Identity(); + Eigen::Vector3f new_cen = m_render_aabb_to_local * world_cen; + Eigen::Vector3f old_cen = m_render_aabb.center(); + m_render_aabb.min += new_cen - old_cen; + m_render_aabb.max += new_cen - old_cen; + } } + ImGui::TreePop(); } else { m_edit_render_aabb = false; @@ -1574,72 +1602,99 @@ void Testbed::visualize_nerf_cameras(ImDrawList* list, const Matrix<float, 4, 4> } void Testbed::draw_visualizations(ImDrawList* list, const Matrix<float, 3, 4>& camera_matrix) { - // Visualize 3D cameras for SDF or NeRF use cases - if (m_testbed_mode != ETestbedMode::Image) { - Matrix<float, 4, 4> world2view, view2world, view2proj, world2proj; - view2world.setIdentity(); - view2world.block<3,4>(0,0) = camera_matrix; - - auto focal = calc_focal_length(Vector2i::Ones(), m_relative_focal_length, m_fov_axis, m_zoom); - float zscale = 1.0f / focal[m_fov_axis]; - - float xyscale = (float)m_window_res[m_fov_axis]; - Vector2f screen_center = render_screen_center(m_screen_center); - view2proj << - xyscale, 0, (float)m_window_res.x()*screen_center.x()*zscale, 0, - 0, xyscale, (float)m_window_res.y()*screen_center.y()*zscale, 0, - 0, 0, 1, 0, - 0, 0, zscale, 0; - - world2view = view2world.inverse(); - world2proj = view2proj * world2view; - float aspect = (float)m_window_res.x() / (float)m_window_res.y(); - - // Visualize NeRF training poses - if (m_testbed_mode == ETestbedMode::Nerf) { - if (m_nerf.visualize_cameras) { - visualize_nerf_cameras(list, world2proj); - } + Matrix<float, 4, 4> world2view, view2world, view2proj, world2proj; + view2world.setIdentity(); + view2world.block<3, 4>(0, 0) = camera_matrix; + + auto focal = calc_focal_length(Vector2i::Ones(), m_relative_focal_length, m_fov_axis, m_zoom); + float zscale = 1.0f / focal[m_fov_axis]; + + float xyscale = (float)m_window_res[m_fov_axis]; + Vector2f screen_center = render_screen_center(m_screen_center); + view2proj << + xyscale, 0, (float)m_window_res.x()*screen_center.x()*zscale, 0, + 0, xyscale, (float)m_window_res.y()*screen_center.y()*zscale, 0, + 0, 0, 1, 0, + 0, 0, zscale, 0; + + world2view = view2world.inverse(); + world2proj = view2proj * world2view; + float aspect = (float)m_window_res.x() / (float)m_window_res.y(); + + // Visualize NeRF training poses + if (m_testbed_mode == ETestbedMode::Nerf) { + if (m_nerf.visualize_cameras) { + visualize_nerf_cameras(list, world2proj); } + } - if (m_visualize_unit_cube) { - visualize_unit_cube(list, world2proj, Eigen::Vector3f::Constant(0.f), Eigen::Vector3f::Constant(1.f), Eigen::Matrix3f::Identity()); + if (m_visualize_unit_cube) { + visualize_cube(list, world2proj, Eigen::Vector3f::Constant(0.f), Eigen::Vector3f::Constant(1.f), Eigen::Matrix3f::Identity()); + } + + if (m_edit_render_aabb) { + if (m_testbed_mode == ETestbedMode::Nerf || m_testbed_mode == ETestbedMode::Volume) { + visualize_cube(list, world2proj, m_render_aabb.min, m_render_aabb.max, m_render_aabb_to_local); } - if (m_edit_render_aabb) { - if (m_testbed_mode == ETestbedMode::Nerf) { - visualize_unit_cube(list, world2proj, m_render_aabb.min, m_render_aabb.max, m_render_aabb_to_local); - ImGuiIO& io = ImGui::GetIO(); - float flx = focal.x(); - float fly = focal.y(); - Matrix<float, 4, 4> view2proj_guizmo; - float zfar = m_ndc_zfar; - float znear = m_ndc_znear; - view2proj_guizmo << - fly * 2.f / aspect, 0, 0, 0, - 0, -fly * 2.f, 0, 0, - 0, 0, (zfar + znear) / (zfar - znear), -(2.f * zfar * znear) / (zfar - znear), - 0, 0, 1, 0; - ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); - - Eigen::Matrix4f matrix=Eigen::Matrix4f::Identity(); - matrix.block<3,3>(0,0) = m_render_aabb_to_local.transpose(); - Eigen::Vector3f cen = m_render_aabb_to_local.transpose() * m_render_aabb.center(); - matrix.block<3,4>(0,0).col(3) = cen; - if (ImGuizmo::Manipulate((const float*)&world2view, (const float*)&view2proj_guizmo, m_camera_path.m_gizmo_op, ImGuizmo::LOCAL, (float*)&matrix, NULL, NULL)) { - m_render_aabb_to_local = matrix.block<3,3>(0,0).transpose(); - Eigen::Vector3f new_cen = m_render_aabb_to_local * matrix.block<3,4>(0,0).col(3); - Eigen::Vector3f old_cen = m_render_aabb.center(); - m_render_aabb.min += new_cen - old_cen; - m_render_aabb.max += new_cen - old_cen; - reset_accumulation(); - } - } + + ImGuiIO& io = ImGui::GetIO(); + float flx = focal.x(); + float fly = focal.y(); + Matrix<float, 4, 4> view2proj_guizmo; + float zfar = m_ndc_zfar; + float znear = m_ndc_znear; + view2proj_guizmo << + fly * 2.f / aspect, 0, 0, 0, + 0, -fly * 2.f, 0, 0, + 0, 0, (zfar + znear) / (zfar - znear), -(2.f * zfar * znear) / (zfar - znear), + 0, 0, 1, 0; + + ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); + + static bool manipulating = false; + static Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity(); + static Eigen::Matrix4f world2view_guizmo = Eigen::Matrix4f::Identity(); + + if (!ImGuizmo::IsUsing()) { + // The the guizmo is being used, it handles updating its matrix on its own. + // Outside interference can only lead to trouble. + matrix.block<3, 3>(0, 0) = m_render_aabb_to_local.transpose(); + Eigen::Vector3f cen = m_render_aabb_to_local.transpose() * m_render_aabb.center(); + matrix.block<3, 4>(0, 0).col(3) = cen; + + // Additionally, the world2view transform must stay fixed, else the guizmo will incorrectly + // interpret the state from past frames. Special handling is necessary here, because below + // we emulate world translation and rotation through (inverse) camera movement. + world2view_guizmo = world2view; } - if (m_camera_path.imgui_viz(list, view2proj, world2proj, world2view, focal, aspect, m_ndc_znear, m_ndc_zfar)) { - m_pip_render_buffer->reset_accumulation(); + Eigen::Vector3f cen = m_render_aabb_to_local.transpose() * m_render_aabb.center(); + auto prev_matrix = matrix; + + if (ImGuizmo::Manipulate((const float*)&world2view_guizmo, (const float*)&view2proj_guizmo, m_camera_path.m_gizmo_op, ImGuizmo::LOCAL, (float*)&matrix, NULL, NULL)) { + auto crop_transform = matrix; + if (m_edit_world_transform) { + // We transform the world by transforming the camera in the opposite direction. + auto rel = prev_matrix * matrix.inverse(); + m_camera = rel.block<3, 3>(0, 0) * m_camera; + m_camera.col(3) += rel.block<3, 1>(0, 3); + + m_up_dir = rel.block<3, 3>(0, 0) * m_up_dir; + } else { + m_render_aabb_to_local = matrix.block<3, 3>(0, 0).transpose(); + Eigen::Vector3f new_cen = m_render_aabb_to_local * matrix.block<3, 4>(0, 0).col(3); + Eigen::Vector3f old_cen = m_render_aabb.center(); + m_render_aabb.min += new_cen - old_cen; + m_render_aabb.max += new_cen - old_cen; + } + + reset_accumulation(); } } + + if (m_camera_path.imgui_viz(list, view2proj, world2proj, world2view, focal, aspect, m_ndc_znear, m_ndc_zfar)) { + m_pip_render_buffer->reset_accumulation(); + } } void glfw_error_callback(int error, const char* description) { @@ -1951,7 +2006,7 @@ void Testbed::handle_user_input() { } // Only respond to mouse inputs when not interacting with ImGui - if (!ImGui::IsAnyItemActive() && !ImGuizmo::IsUsing() && !ImGuizmo::IsOver() && !ImGui::GetIO().WantCaptureMouse) { + if (!ImGui::IsAnyItemActive() && !ImGuizmo::IsUsing() && !ImGui::GetIO().WantCaptureMouse) { mouse_wheel(); mouse_drag(); } @@ -3795,9 +3850,9 @@ void Testbed::train(uint32_t batch_size) { }}; switch (m_testbed_mode) { - case ETestbedMode::Nerf: train_nerf(batch_size, get_loss_scalar, m_stream.get()); break; - case ETestbedMode::Sdf: train_sdf(batch_size, get_loss_scalar, m_stream.get()); break; - case ETestbedMode::Image: train_image(batch_size, get_loss_scalar, m_stream.get()); break; + case ETestbedMode::Nerf: train_nerf(batch_size, get_loss_scalar, m_stream.get()); break; + case ETestbedMode::Sdf: train_sdf(batch_size, get_loss_scalar, m_stream.get()); break; + case ETestbedMode::Image: train_image(batch_size, get_loss_scalar, m_stream.get()); break; case ETestbedMode::Volume: train_volume(batch_size, get_loss_scalar, m_stream.get()); break; default: throw std::runtime_error{"Invalid training mode."}; } @@ -4458,6 +4513,7 @@ void Testbed::save_snapshot(const fs::path& path, bool include_optimizer_state, snapshot["bounding_radius"] = m_bounding_radius; to_json(snapshot["render_aabb_to_local"], m_render_aabb_to_local); snapshot["render_aabb"] = m_render_aabb; + to_json(snapshot["up_dir"], m_up_dir); if (m_testbed_mode == ETestbedMode::Nerf) { snapshot["nerf"]["rgb"]["rays_per_batch"] = m_nerf.training.counters_rgb.rays_per_batch; @@ -4542,6 +4598,7 @@ void Testbed::load_snapshot(const fs::path& path) { // Needs to happen after `load_nerf_post()` if (snapshot.contains("render_aabb_to_local")) from_json(snapshot.at("render_aabb_to_local"), m_render_aabb_to_local); m_render_aabb = snapshot.value("render_aabb", m_render_aabb); + if (snapshot.contains("up_dir")) from_json(snapshot.at("up_dir"), m_up_dir); m_network_config_path = path; m_network_config = std::move(config); diff --git a/src/testbed_image.cu b/src/testbed_image.cu index 59d385a7840d561eb389fbdc8bca34cbff606ed2..3156c1edf31d69ab552f9a729b47afda604d4503 100644 --- a/src/testbed_image.cu +++ b/src/testbed_image.cu @@ -379,6 +379,9 @@ void Testbed::load_image(const fs::path& data_path) { load_stbi_image(data_path); } + m_aabb = m_render_aabb = BoundingBox{Vector3f::Zero(), Vector3f::Ones()}; + m_render_aabb_to_local = Matrix3f::Identity(); + tlog::success() << "Loaded a " << (m_image.type == EDataType::Half ? "half" : "full") << "-precision image with " << m_image.resolution.x() << "x" << m_image.resolution.y() << " pixels."; diff --git a/src/testbed_nerf.cu b/src/testbed_nerf.cu index bdc35f1256a1272900b21cf3840219e97f0c33e2..df70273b9f31c12200cf58778476c7288afda934 100644 --- a/src/testbed_nerf.cu +++ b/src/testbed_nerf.cu @@ -2667,10 +2667,6 @@ void Testbed::load_nerf(const fs::path& data_path) { json_paths.emplace_back(path); } } - } else if (equals_case_insensitive(data_path.extension(), "msgpack")) { - load_snapshot(data_path.str()); - set_train(false); - return; } else if (equals_case_insensitive(data_path.extension(), "json")) { json_paths.emplace_back(data_path); } else { diff --git a/src/testbed_volume.cu b/src/testbed_volume.cu index c8c7a09a7236b2740b0d6f5b5da5d1496a68673d..fc84205cd5021904fbcfc35f6e9146ed1142ffd6 100644 --- a/src/testbed_volume.cu +++ b/src/testbed_volume.cu @@ -618,6 +618,8 @@ void Testbed::load_volume(const fs::path& data_path) { Vector3f{0.5f - xsize * scale * 0.5f, 0.5f - ysize * scale * 0.5f, 0.5f - zsize * scale * 0.5f}, Vector3f{0.5f + xsize * scale * 0.5f, 0.5f + ysize * scale * 0.5f, 0.5f + zsize * scale * 0.5f}, }; + m_render_aabb_to_local = Matrix3f::Identity(); + m_volume.world2index_scale = maxsize; m_volume.world2index_offset = Vector3f{ (metadata.indexBBox[0][0] + metadata.indexBBox[1][0]) * 0.5f - 0.5f * maxsize,