Replace functionally opaque Viscous Pause with functionally transparent "Viscous posing mode" toggle.
PiperOrigin-RevId: 947527204 Change-Id: I122a9730fa22ac9e8809762046a89fb0a774d827
This commit is contained in:
committed by
Copybara-Service
parent
3c6080b1c0
commit
0ce8f7b06b
@@ -32,14 +32,12 @@ PYBIND11_MODULE(sim, m, pybind11::mod_gil_not_used()) {
|
|||||||
py::enum_<StepControl::Status>(m, "StepStatus")
|
py::enum_<StepControl::Status>(m, "StepStatus")
|
||||||
.value("OK", StepControl::Status::kOk)
|
.value("OK", StepControl::Status::kOk)
|
||||||
.value("PAUSED", StepControl::Status::kPaused)
|
.value("PAUSED", StepControl::Status::kPaused)
|
||||||
.value("VISCOUS_PAUSED", StepControl::Status::kViscousPaused)
|
|
||||||
.value("AUTO_RESET", StepControl::Status::kAutoReset)
|
.value("AUTO_RESET", StepControl::Status::kAutoReset)
|
||||||
.value("DIVERGED", StepControl::Status::kDiverged);
|
.value("DIVERGED", StepControl::Status::kDiverged);
|
||||||
|
|
||||||
py::enum_<StepControl::PauseState>(m, "PauseState")
|
py::enum_<StepControl::PauseState>(m, "PauseState")
|
||||||
.value("UNPAUSED", StepControl::PauseState::kUnpaused)
|
.value("UNPAUSED", StepControl::PauseState::kUnpaused)
|
||||||
.value("NORMAL_PAUSED", StepControl::PauseState::kNormalPaused)
|
.value("NORMAL_PAUSED", StepControl::PauseState::kNormalPaused);
|
||||||
.value("VISCOUS_PAUSED", StepControl::PauseState::kViscousPaused);
|
|
||||||
|
|
||||||
py::class_<StepControl>(m, "StepControl")
|
py::class_<StepControl>(m, "StepControl")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
|
|||||||
@@ -157,15 +157,8 @@ def handle_step_control_keyboard_events(
|
|||||||
|
|
||||||
pressed = imgui.IsKeyChordPressed
|
pressed = imgui.IsKeyChordPressed
|
||||||
|
|
||||||
if pressed(int(imgui.Key.Ctrl) | int(imgui.Key.Space)):
|
if pressed(imgui.Key.Space):
|
||||||
if step_control.get_pause_state() == sim.PauseState.VISCOUS_PAUSED:
|
if step_control.get_pause_state() == sim.PauseState.UNPAUSED:
|
||||||
step_control.set_pause_state(sim.PauseState.UNPAUSED)
|
|
||||||
else:
|
|
||||||
step_control.set_pause_state(sim.PauseState.VISCOUS_PAUSED)
|
|
||||||
return True
|
|
||||||
elif pressed(imgui.Key.Space):
|
|
||||||
pause = step_control.get_pause_state()
|
|
||||||
if pause in (sim.PauseState.VISCOUS_PAUSED, sim.PauseState.UNPAUSED):
|
|
||||||
step_control.set_pause_state(sim.PauseState.NORMAL_PAUSED)
|
step_control.set_pause_state(sim.PauseState.NORMAL_PAUSED)
|
||||||
else:
|
else:
|
||||||
step_control.set_pause_state(sim.PauseState.UNPAUSED)
|
step_control.set_pause_state(sim.PauseState.UNPAUSED)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
|
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
@@ -32,31 +31,7 @@ static mjtNum Timer() {
|
|||||||
return Milliseconds(Clock::now() - start).count();
|
return Milliseconds(Clock::now() - start).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates key viscous pause parameters restores them when done.
|
|
||||||
struct ViscousPauseState {
|
|
||||||
ViscousPauseState(mjModel* model) : model(model) {
|
|
||||||
if (model) {
|
|
||||||
mju_copy3(gravity, model->opt.gravity);
|
|
||||||
viscosity = model->opt.viscosity;
|
|
||||||
disableflags = model->opt.disableflags;
|
|
||||||
mju_zero3(model->opt.gravity);
|
|
||||||
model->opt.viscosity = 10;
|
|
||||||
model->opt.disableflags |= mjDSBL_SPRING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~ViscousPauseState() {
|
|
||||||
if (model) {
|
|
||||||
mju_copy3(model->opt.gravity, gravity);
|
|
||||||
model->opt.viscosity = viscosity;
|
|
||||||
model->opt.disableflags = disableflags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mjModel* model;
|
|
||||||
mjtNum gravity[3];
|
|
||||||
mjtNum viscosity;
|
|
||||||
int disableflags;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
StepControl::StepControl() { mjcb_time = Timer; }
|
StepControl::StepControl() { mjcb_time = Timer; }
|
||||||
@@ -100,10 +75,6 @@ StepControl::Status StepControl::Advance(mjModel* m, mjData* d) {
|
|||||||
return Status::kOk;
|
return Status::kOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ViscousPauseState> viscous_pause_state;
|
|
||||||
if (m && pause_state_ == PauseState::kViscousPaused) {
|
|
||||||
viscous_pause_state.emplace(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pause_state_ == PauseState::kNormalPaused) {
|
if (pause_state_ == PauseState::kNormalPaused) {
|
||||||
// When we eventually unpause, we need to make sure we sync to immediately
|
// When we eventually unpause, we need to make sure we sync to immediately
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ class StepControl {
|
|||||||
// Simulation was not stepped because it is paused.
|
// Simulation was not stepped because it is paused.
|
||||||
kPaused,
|
kPaused,
|
||||||
|
|
||||||
// Simulation is viscously paused (stepping with zero gravity, high
|
|
||||||
// viscosity, and no spring forces).
|
|
||||||
kViscousPaused,
|
|
||||||
|
|
||||||
// Simulation diverged with autoreset enabled.
|
// Simulation diverged with autoreset enabled.
|
||||||
kAutoReset,
|
kAutoReset,
|
||||||
@@ -73,7 +70,7 @@ class StepControl {
|
|||||||
void SetPreStepCallback(StepFn step_fn);
|
void SetPreStepCallback(StepFn step_fn);
|
||||||
void SetPostStepCallback(StepFn step_fn);
|
void SetPostStepCallback(StepFn step_fn);
|
||||||
|
|
||||||
enum class PauseState { kUnpaused, kNormalPaused, kViscousPaused };
|
enum class PauseState { kUnpaused, kNormalPaused };
|
||||||
|
|
||||||
// Sets the pause state of the simulation.
|
// Sets the pause state of the simulation.
|
||||||
void SetPauseState(PauseState state);
|
void SetPauseState(PauseState state);
|
||||||
|
|||||||
@@ -511,9 +511,6 @@ void StepControlGui(StepControl* step_control, int& speed_index) {
|
|||||||
make_button(ICON_FA_PAUSE, StepControl::PauseState::kNormalPaused, yellow,
|
make_button(ICON_FA_PAUSE, StepControl::PauseState::kNormalPaused, yellow,
|
||||||
ImDrawFlags_RoundCornersLeft, "Pause", .3f, 1.6f);
|
ImDrawFlags_RoundCornersLeft, "Pause", .3f, 1.6f);
|
||||||
ImGui::SameLine(0.f, 0.f);
|
ImGui::SameLine(0.f, 0.f);
|
||||||
make_button(ICON_FA_MAGIC, StepControl::PauseState::kViscousPaused, yellow,
|
|
||||||
ImDrawFlags_RoundCornersNone, "Viscous Pause", .3f, 1.3f);
|
|
||||||
ImGui::SameLine(0.f, 0.f);
|
|
||||||
make_button(ICON_FA_PLAY, StepControl::PauseState::kUnpaused, green,
|
make_button(ICON_FA_PLAY, StepControl::PauseState::kUnpaused, green,
|
||||||
ImDrawFlags_RoundCornersRight, "", .3f, 1.6f);
|
ImDrawFlags_RoundCornersRight, "", .3f, 1.6f);
|
||||||
|
|
||||||
@@ -983,6 +980,30 @@ void PhysicsGui(mjModel* model, float min_width) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (SectionHeader("Physical Parameters")) {
|
if (SectionHeader("Physical Parameters")) {
|
||||||
|
// Viscous posing mode toggle: disables gravity and passive springs, adds
|
||||||
|
// viscosity. All changes are directly visible in the parameters below.
|
||||||
|
{
|
||||||
|
constexpr mjtNum kPosingViscosity = 10;
|
||||||
|
bool active = (opt.disableflags & mjDSBL_GRAVITY) &&
|
||||||
|
(opt.disableflags & mjDSBL_SPRING) &&
|
||||||
|
(opt.viscosity >= kPosingViscosity);
|
||||||
|
if (ImGui_ButtonToggle("Viscous posing mode", &active)) {
|
||||||
|
if (active) {
|
||||||
|
opt.disableflags |= mjDSBL_GRAVITY;
|
||||||
|
opt.disableflags |= mjDSBL_SPRING;
|
||||||
|
opt.viscosity += kPosingViscosity;
|
||||||
|
} else {
|
||||||
|
opt.disableflags &= ~mjDSBL_GRAVITY;
|
||||||
|
opt.disableflags &= ~mjDSBL_SPRING;
|
||||||
|
opt.viscosity = std::max<mjtNum>(0, opt.viscosity - kPosingViscosity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SetItemTooltip(
|
||||||
|
"Disable gravity and passive springs,\n"
|
||||||
|
"add viscosity for easier posing.");
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
ImGui_InputN("Gravity", opt.gravity, 3);
|
ImGui_InputN("Gravity", opt.gravity, 3);
|
||||||
ImGui_InputN("Wind", opt.wind, 3);
|
ImGui_InputN("Wind", opt.wind, 3);
|
||||||
ImGui_InputN("Magnetic", opt.magnetic, 3);
|
ImGui_InputN("Magnetic", opt.magnetic, 3);
|
||||||
|
|||||||
@@ -733,16 +733,8 @@ void App::HandleKeyboardEvents() {
|
|||||||
LoadHistory(sim_history_.GetIndex() + 1);
|
LoadHistory(sim_history_.GetIndex() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiMod_Ctrl | ImGuiKey_Space)) {
|
|
||||||
if (step_control_.GetPauseState() == PauseState::kViscousPaused) {
|
|
||||||
step_control_.SetPauseState(PauseState::kUnpaused);
|
|
||||||
} else {
|
|
||||||
step_control_.SetPauseState(PauseState::kViscousPaused);
|
|
||||||
}
|
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_Space)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_Space)) {
|
||||||
if (step_control_.GetPauseState() == PauseState::kViscousPaused) {
|
if (step_control_.GetPauseState() == PauseState::kUnpaused) {
|
||||||
step_control_.SetPauseState(PauseState::kNormalPaused);
|
|
||||||
} else if (step_control_.GetPauseState() == PauseState::kUnpaused) {
|
|
||||||
step_control_.SetPauseState(PauseState::kNormalPaused);
|
step_control_.SetPauseState(PauseState::kNormalPaused);
|
||||||
} else {
|
} else {
|
||||||
step_control_.SetPauseState(PauseState::kUnpaused);
|
step_control_.SetPauseState(PauseState::kUnpaused);
|
||||||
@@ -1461,6 +1453,7 @@ void App::TimelineScrubberGui() {
|
|||||||
|
|
||||||
// Advance layout cursor past this row.
|
// Advance layout cursor past this row.
|
||||||
ImGui::SetCursorScreenPos(ImVec2(cursor.x, cursor.y + total_h));
|
ImGui::SetCursorScreenPos(ImVec2(cursor.x, cursor.y + total_h));
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::ModelOptionsGui() {
|
void App::ModelOptionsGui() {
|
||||||
@@ -2178,8 +2171,8 @@ void App::ToolBarGui() {
|
|||||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, right_width);
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, right_width);
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
|
ImGui::Dummy(ImVec2(ImGui::GetStyle().WindowPadding.x, 0.0f));
|
||||||
ImGui::GetStyle().WindowPadding.x);
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
|
||||||
const float btn_size = ImGui::GetFrameHeight();
|
const float btn_size = ImGui::GetFrameHeight();
|
||||||
const ImVec2 square_size(btn_size, btn_size);
|
const ImVec2 square_size(btn_size, btn_size);
|
||||||
@@ -2200,7 +2193,7 @@ void App::ToolBarGui() {
|
|||||||
}
|
}
|
||||||
ImGui::SetItemTooltip("%s", "Reset");
|
ImGui::SetItemTooltip("%s", "Reset");
|
||||||
|
|
||||||
// Combined (Normal Pause, Viscous Pause, Play) widget and Speed selection.
|
// Combined (Pause, Play) widget and Speed selection.
|
||||||
ImGui::SameLine(0, separator_width);
|
ImGui::SameLine(0, separator_width);
|
||||||
platform::StepControlGui(&step_control_, tmp_.speed_index);
|
platform::StepControlGui(&step_control_, tmp_.speed_index);
|
||||||
|
|
||||||
@@ -2228,9 +2221,6 @@ void App::StatusBarGui() {
|
|||||||
|
|
||||||
if (!has_model()) {
|
if (!has_model()) {
|
||||||
ImGui::Text("No model loaded");
|
ImGui::Text("No model loaded");
|
||||||
} else if (step_control_.GetPauseState() == PauseState::kViscousPaused) {
|
|
||||||
ImGui::Text("Viscous Pause");
|
|
||||||
ImGui::SetItemTooltip("Zero gravity, high viscosity, no spring forces");
|
|
||||||
} else if (step_control_.GetPauseState() == PauseState::kNormalPaused) {
|
} else if (step_control_.GetPauseState() == PauseState::kNormalPaused) {
|
||||||
ImGui::Text("Paused");
|
ImGui::Text("Paused");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user