From 0bfcfe5901b6052c6c8f7d35519bc17d2dc14045 Mon Sep 17 00:00:00 2001 From: crosstyan Date: Wed, 11 Mar 2026 11:56:25 +0800 Subject: [PATCH] fix: track full-motion scene bounds and ignore runtime files Accumulate scene bounds from actual geometry and marker samples across the full trajectory instead of seeding Range3D with sentinel extrema and only joining against the first sample. Why this loader change is necessary: - Viewer camera framing and reference sizing derive from scene.initialBounds. - The old code only incorporated sample==0 geometry and marker positions, so motions that travel away from the initial pose could be framed incorrectly. - The old sentinel initialization depended on joining with artificial min/max values instead of real bounds. What changed: - Use first-real-bound initialization in scaledBounds(), transformBounds(), and buildCpuMesh(). - Accumulate scene.initialBounds across all trajectory samples in src/OpenSimLoader.cpp. - Ignore generated runtime files imgui.ini and opensim.log in .gitignore. Validation: - Rebuilt successfully with: cmake --build build -j --- .gitignore | 4 ++++ src/OpenSimLoader.cpp | 45 ++++++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 1961137..5ba9d92 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,7 @@ compile_commands.json Makefile cmake_install.cmake Testing/ + +# runtime files +imgui.ini +opensim.log diff --git a/src/OpenSimLoader.cpp b/src/OpenSimLoader.cpp index 10a8a76..7853f9e 100644 --- a/src/OpenSimLoader.cpp +++ b/src/OpenSimLoader.cpp @@ -44,9 +44,8 @@ Color4 toColor(const OpenSim::Appearance& appearance) { } Range3D scaledBounds(const Range3D& bounds, const Vector3& scale) { + bool hasBounds = false; Range3D out; - out.min() = Vector3{std::numeric_limits::max()}; - out.max() = Vector3{-std::numeric_limits::max()}; for(const Vector3& corner: { Vector3{bounds.min().x(), bounds.min().y(), bounds.min().z()}, Vector3{bounds.min().x(), bounds.min().y(), bounds.max().z()}, @@ -57,15 +56,17 @@ Range3D scaledBounds(const Range3D& bounds, const Vector3& scale) { Vector3{bounds.max().x(), bounds.max().y(), bounds.min().z()}, Vector3{bounds.max().x(), bounds.max().y(), bounds.max().z()}, }) { - out = Math::join(out, Range3D::fromSize(corner*scale, {})); + const Range3D point = Range3D::fromSize(corner*scale, {}); + if(hasBounds) out = Math::join(out, point); + else out = point; + hasBounds = true; } return out; } Range3D transformBounds(const Range3D& bounds, const Matrix4& transform) { + bool hasBounds = false; Range3D out; - out.min() = Vector3{std::numeric_limits::max()}; - out.max() = Vector3{-std::numeric_limits::max()}; for(const Vector3& corner: { Vector3{bounds.min().x(), bounds.min().y(), bounds.min().z()}, Vector3{bounds.min().x(), bounds.min().y(), bounds.max().z()}, @@ -76,7 +77,10 @@ Range3D transformBounds(const Range3D& bounds, const Matrix4& transform) { Vector3{bounds.max().x(), bounds.max().y(), bounds.min().z()}, Vector3{bounds.max().x(), bounds.max().y(), bounds.max().z()}, }) { - out = Math::join(out, Range3D::fromSize(transform.transformPoint(corner), {})); + const Range3D point = Range3D::fromSize(transform.transformPoint(corner), {}); + if(hasBounds) out = Math::join(out, point); + else out = point; + hasBounds = true; } return out; } @@ -114,15 +118,17 @@ std::shared_ptr buildCpuMesh(const SimTK::PolygonalMesh& mesh) { } } + bool hasBounds = false; Range3D bounds; - bounds.min() = Vector3{std::numeric_limits::max()}; - bounds.max() = Vector3{-std::numeric_limits::max()}; cpu->vertices.reserve(positions.size()); for(std::size_t i = 0; i != positions.size(); ++i) { const Vector3 normal = normals[i].isZero() ? Vector3::yAxis() : normals[i].normalized(); cpu->vertices.push_back({positions[i], normal}); - bounds = Math::join(bounds, Range3D::fromSize(positions[i], {})); + const Range3D point = Range3D::fromSize(positions[i], {}); + if(hasBounds) bounds = Math::join(bounds, point); + else bounds = point; + hasBounds = true; } cpu->bounds = bounds; return cpu; @@ -302,8 +308,7 @@ LoadedScene loadScene(const std::string& modelPath, } for(MarkerTrack& marker: scene.markers) marker.positions.reserve(trajectory.getSize()); - scene.initialBounds.min() = Vector3{std::numeric_limits::max()}; - scene.initialBounds.max() = Vector3{-std::numeric_limits::max()}; + bool hasSceneBounds = false; for(std::size_t sample = 0; sample != trajectory.getSize(); ++sample) { const SimTK::State& state = trajectory[sample]; @@ -317,19 +322,23 @@ LoadedScene loadScene(const std::string& modelPath, scene.frames[i].translations.push_back(translation); scene.frames[i].rotations.push_back(rotation); - if(sample == 0) { - const Matrix4 world = frameMatrix(translation, rotation); - for(const GeometrySpec& geometry: scene.frames[i].geometries) { - const Range3D scaled = scaledBounds(geometry.mesh->bounds, geometry.scale); - scene.initialBounds = Math::join(scene.initialBounds, transformBounds(scaled, world)); - } + const Matrix4 world = frameMatrix(translation, rotation); + for(const GeometrySpec& geometry: scene.frames[i].geometries) { + const Range3D scaled = scaledBounds(geometry.mesh->bounds, geometry.scale); + const Range3D worldBounds = transformBounds(scaled, world); + if(hasSceneBounds) scene.initialBounds = Math::join(scene.initialBounds, worldBounds); + else scene.initialBounds = worldBounds; + hasSceneBounds = true; } } for(std::size_t i = 0; i != markerPtrs.size(); ++i) { const Vector3 position = toVector3(markerPtrs[i]->getLocationInGround(state)); scene.markers[i].positions.push_back(position); - if(sample == 0) scene.initialBounds = Math::join(scene.initialBounds, Range3D::fromSize(position, {})); + const Range3D point = Range3D::fromSize(position, {}); + if(hasSceneBounds) scene.initialBounds = Math::join(scene.initialBounds, point); + else scene.initialBounds = point; + hasSceneBounds = true; } }