Allow user-defined visualization geoms to be added to the passive viewer.
Fixes #1023, #1082 PiperOrigin-RevId: 572303635 Change-Id: Ia8399f816f311b38a7b137f5bd4f359f77a1da1c
This commit is contained in:
committed by
Copybara-Service
parent
1bd6c94e6d
commit
2e15574b58
+5
-3
@@ -131,6 +131,8 @@ Python bindings
|
|||||||
|
|
||||||
23. Fixed `#870 <https://github.com/google-deepmind/mujoco/issues/870>`__ where calling ``update_scene`` with an invalid
|
23. Fixed `#870 <https://github.com/google-deepmind/mujoco/issues/870>`__ where calling ``update_scene`` with an invalid
|
||||||
camera name used the default camera.
|
camera name used the default camera.
|
||||||
|
24. Added ``user_scn`` to the :ref:`passive viewer<PyViewerPassive>` handle, which allows users to add custom
|
||||||
|
visualization geoms (`#1023 <https://github.com/google-deepmind/mujoco/issues/870>`__).
|
||||||
|
|
||||||
Simulate
|
Simulate
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
@@ -139,18 +141,18 @@ Simulate
|
|||||||
:align: right
|
:align: right
|
||||||
:width: 240px
|
:width: 240px
|
||||||
|
|
||||||
24. Added **state history** mechanism to :ref:`simulate<saSimulate>` and the managed
|
25. Added **state history** mechanism to :ref:`simulate<saSimulate>` and the managed
|
||||||
:ref:`Python viewer<PyViewerManaged>`. State history can be viewed by scrubbing the History slider and (more
|
:ref:`Python viewer<PyViewerManaged>`. State history can be viewed by scrubbing the History slider and (more
|
||||||
precisely) with the left and right arrow keys. See screen capture:
|
precisely) with the left and right arrow keys. See screen capture:
|
||||||
|
|
||||||
25. The ``LOADING...`` label is now shown correctly.
|
26. The ``LOADING...`` label is now shown correctly.
|
||||||
`Contribution <https://github.com/google-deepmind/mujoco/pull/1070>`__ by
|
`Contribution <https://github.com/google-deepmind/mujoco/pull/1070>`__ by
|
||||||
`Levi Burner <https://github.com/aftersomemath>`__.
|
`Levi Burner <https://github.com/aftersomemath>`__.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
26. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
27. Fixed a bug that was causing :ref:`geom margin<body-geom-margin>` to be ignored during the construction of
|
||||||
midphase collision trees.
|
midphase collision trees.
|
||||||
|
|
||||||
27. Fixed a bug that was generating incorrect values in ``efc_diagApprox`` for weld equality constraints.
|
27. Fixed a bug that was generating incorrect values in ``efc_diagApprox`` for weld equality constraints.
|
||||||
|
|||||||
@@ -1989,7 +1989,7 @@ struct mjvSceneState_ {
|
|||||||
int nbuffer; // size of the buffer in bytes
|
int nbuffer; // size of the buffer in bytes
|
||||||
void* buffer; // heap-allocated memory for all arrays in this struct
|
void* buffer; // heap-allocated memory for all arrays in this struct
|
||||||
int maxgeom; // maximum number of mjvGeom supported by this state object
|
int maxgeom; // maximum number of mjvGeom supported by this state object
|
||||||
mjvScene plugincache; // scratch space for vis geoms inserted by plugins
|
mjvScene scratch; // scratch space for vis geoms inserted by the user and plugins
|
||||||
|
|
||||||
// fields in mjModel that are necessary to re-render a scene
|
// fields in mjModel that are necessary to re-render a scene
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
+35
-5
@@ -96,13 +96,13 @@ perturbations will not work unless the user explicitly synchronizes incoming eve
|
|||||||
The ``launch_passive`` function returns a handle which can be used to interact with the viewer. It has the following
|
The ``launch_passive`` function returns a handle which can be used to interact with the viewer. It has the following
|
||||||
attributes:
|
attributes:
|
||||||
|
|
||||||
- ``scn``, ``cam``, ``opt``, and ``pert`` properties: correspond to :ref:`mjvScene`, :ref:`mjvCamera`,
|
- ``cam``, ``opt``, and ``pert`` properties: correspond to :ref:`mjvCamera`, :ref:`mjvOption`, and :ref:`mjvPerturb`
|
||||||
:ref:`mjvOption`, and :ref:`mjvPerturb` structs, respectively.
|
structs, respectively.
|
||||||
|
|
||||||
- ``lock()``: provides a mutex lock for the viewer as a context manager. Since the viewer operates its own
|
- ``lock()``: provides a mutex lock for the viewer as a context manager. Since the viewer operates its own
|
||||||
thread, user code must ensure that it is holding the viewer lock before modifying any physics or visualization
|
thread, user code must ensure that it is holding the viewer lock before modifying any physics or visualization
|
||||||
state. These include the ``mjModel`` and ``mjData`` instance passed to ``launch_passive``, and also the ``scn``,
|
state. These include the ``mjModel`` and ``mjData`` instance passed to ``launch_passive``, and also the ``cam``,
|
||||||
``cam``, ``opt``, and ``pert`` properties of the viewer handle.
|
``opt``, and ``pert`` properties of the viewer handle.
|
||||||
|
|
||||||
- ``sync()``: synchronizes state between ``mjModel``, ``mjData``, and GUI user inputs since the previous call to
|
- ``sync()``: synchronizes state between ``mjModel``, ``mjData``, and GUI user inputs since the previous call to
|
||||||
``sync``. In order to allow user scripts to make arbitrary modifications to ``mjModel`` and ``mjData`` without
|
``sync``. In order to allow user scripts to make arbitrary modifications to ``mjModel`` and ``mjData`` without
|
||||||
@@ -124,6 +124,37 @@ attributes:
|
|||||||
- ``is_running()``: returns ``True`` if the viewer window is running and ``False`` if it is closed.
|
- ``is_running()``: returns ``True`` if the viewer window is running and ``False`` if it is closed.
|
||||||
This method can be safely called without locking.
|
This method can be safely called without locking.
|
||||||
|
|
||||||
|
- ``user_scn``: an :ref:`mjvScene` object that allows users to add custom visualization geoms to the rendered scene.
|
||||||
|
This is separate from the ``mjvScene`` that the viewer uses internally to render the final scene, and is entirely
|
||||||
|
under the user's control. User scripts can call e.g. :ref:`mjv_initGeom` or :ref:`mjv_makeConnector` to add
|
||||||
|
visualization geoms to ``user_scn``, and upon the next call to ``sync()``, the viewer will incorporate
|
||||||
|
these geoms to future rendered images. For example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with mujoco.viewer.launch_passive(m, d, key_callback=key_callback) as viewer:
|
||||||
|
while viewer.is_running():
|
||||||
|
...
|
||||||
|
# Step the physics.
|
||||||
|
mujoco.mj_step(m, d)
|
||||||
|
|
||||||
|
# Add a 3x3x3 grid of variously colored spheres to the middle of the scene.
|
||||||
|
viewer.user_scn.ngeom = 0
|
||||||
|
i = 0
|
||||||
|
for x, y, z in itertools.product(*((range(-1, 2),) * 3)):
|
||||||
|
mujoco.mjv_initGeom(
|
||||||
|
viewer.user_scn.geoms[i],
|
||||||
|
type=mujoco.mjtGeom.mjGEOM_SPHERE,
|
||||||
|
size=[0.02, 0, 0],
|
||||||
|
pos=0.1*np.array([x, y, z]),
|
||||||
|
mat=np.eye(3).flatten(),
|
||||||
|
rgba=0.5*np.array([x + 1, y + 1, z + 1, 2])
|
||||||
|
)
|
||||||
|
i += 1
|
||||||
|
viewer.user_scn.ngeom = i
|
||||||
|
viewer.sync()
|
||||||
|
...
|
||||||
|
|
||||||
The viewer handle can also be used as a context manager which calls ``close()`` automatically upon exit. A minimal
|
The viewer handle can also be used as a context manager which calls ``close()`` automatically upon exit. A minimal
|
||||||
example of a user script that uses ``launch_passive`` might look like the following. (Note that example is a simple
|
example of a user script that uses ``launch_passive`` might look like the following. (Note that example is a simple
|
||||||
illustrative example that does **not** necessarily keep the physics ticking at the correct wallclock rate.)
|
illustrative example that does **not** necessarily keep the physics ticking at the correct wallclock rate.)
|
||||||
@@ -183,7 +214,6 @@ pause or resume the run loop when the spacebar is pressed.
|
|||||||
viewer.sync()
|
viewer.sync()
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
.. _PyUsage:
|
.. _PyUsage:
|
||||||
|
|
||||||
Basic usage
|
Basic usage
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ struct mjvSceneState_ {
|
|||||||
int nbuffer; // size of the buffer in bytes
|
int nbuffer; // size of the buffer in bytes
|
||||||
void* buffer; // heap-allocated memory for all arrays in this struct
|
void* buffer; // heap-allocated memory for all arrays in this struct
|
||||||
int maxgeom; // maximum number of mjvGeom supported by this state object
|
int maxgeom; // maximum number of mjvGeom supported by this state object
|
||||||
mjvScene plugincache; // scratch space for vis geoms inserted by plugins
|
mjvScene scratch; // scratch space for vis geoms inserted by the user and plugins
|
||||||
|
|
||||||
// fields in mjModel that are necessary to re-render a scene
|
// fields in mjModel that are necessary to re-render a scene
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@@ -5476,9 +5476,9 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='maximum number of mjvGeom supported by this state object',
|
doc='maximum number of mjvGeom supported by this state object',
|
||||||
),
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='plugincache',
|
name='scratch',
|
||||||
type=ValueType(name='mjvScene'),
|
type=ValueType(name='mjvScene'),
|
||||||
doc='scratch space for vis geoms inserted by plugins',
|
doc='scratch space for vis geoms inserted by the user and plugins', # pylint: disable=line-too-long
|
||||||
),
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='model',
|
name='model',
|
||||||
|
|||||||
@@ -69,19 +69,23 @@ class UIAdapterWithPyCallback : public Adapter {
|
|||||||
class SimulateWrapper {
|
class SimulateWrapper {
|
||||||
public:
|
public:
|
||||||
SimulateWrapper(std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
SimulateWrapper(std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
||||||
py::object scn, py::object cam, py::object opt,
|
py::object cam, py::object opt,
|
||||||
py::object pert, bool is_passive)
|
py::object pert, py::object user_scn, bool is_passive)
|
||||||
: simulate_(new mujoco::Simulate(
|
: simulate_(new mujoco::Simulate(
|
||||||
std::move(platform_ui_adapter), scn.cast<MjvSceneWrapper&>().get(),
|
std::move(platform_ui_adapter),
|
||||||
cam.cast<MjvCameraWrapper&>().get(),
|
cam.cast<MjvCameraWrapper&>().get(),
|
||||||
opt.cast<MjvOptionWrapper&>().get(),
|
opt.cast<MjvOptionWrapper&>().get(),
|
||||||
pert.cast<MjvPerturbWrapper&>().get(), is_passive)),
|
pert.cast<MjvPerturbWrapper&>().get(), is_passive)),
|
||||||
m_(py::none()),
|
m_(py::none()),
|
||||||
d_(py::none()),
|
d_(py::none()),
|
||||||
scn_(scn),
|
|
||||||
cam_(cam),
|
cam_(cam),
|
||||||
opt_(opt),
|
opt_(opt),
|
||||||
pert_(pert) {}
|
pert_(pert),
|
||||||
|
user_scn_(user_scn) {
|
||||||
|
if (!user_scn.is_none()) {
|
||||||
|
simulate_->user_scn = user_scn_.cast<MjvSceneWrapper&>().get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~SimulateWrapper() { Destroy(); }
|
~SimulateWrapper() { Destroy(); }
|
||||||
|
|
||||||
@@ -127,10 +131,10 @@ class SimulateWrapper {
|
|||||||
// simulate object.
|
// simulate object.
|
||||||
py::object m_;
|
py::object m_;
|
||||||
py::object d_;
|
py::object d_;
|
||||||
py::object scn_;
|
|
||||||
py::object cam_;
|
py::object cam_;
|
||||||
py::object opt_;
|
py::object opt_;
|
||||||
py::object pert_;
|
py::object pert_;
|
||||||
|
py::object user_scn_;
|
||||||
|
|
||||||
mjModel* m_raw_ = nullptr;
|
mjModel* m_raw_ = nullptr;
|
||||||
mjData* d_raw_ = nullptr;
|
mjData* d_raw_ = nullptr;
|
||||||
@@ -207,7 +211,8 @@ PYBIND11_MODULE(_simulate, pymodule) {
|
|||||||
.def("load_message", CallIfNotNull(&mujoco::Simulate::LoadMessage),
|
.def("load_message", CallIfNotNull(&mujoco::Simulate::LoadMessage),
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def("load", &SimulateWrapper::Load)
|
.def("load", &SimulateWrapper::Load)
|
||||||
.def("load_message_clear", CallIfNotNull(&mujoco::Simulate::LoadMessageClear),
|
.def("load_message_clear",
|
||||||
|
CallIfNotNull(&mujoco::Simulate::LoadMessageClear),
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
.def("sync", CallIfNotNull(&mujoco::Simulate::Sync),
|
.def("sync", CallIfNotNull(&mujoco::Simulate::Sync),
|
||||||
py::call_guard<py::gil_scoped_release>())
|
py::call_guard<py::gil_scoped_release>())
|
||||||
|
|||||||
@@ -1050,7 +1050,9 @@ MjvGeomWrapper::MjWrapper()
|
|||||||
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0])*9);
|
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0])*9);
|
||||||
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
||||||
}()),
|
}()),
|
||||||
X(rgba) {}
|
X(rgba) {
|
||||||
|
mjv_initGeom(ptr_, mjGEOM_NONE, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
MjvGeomWrapper::MjWrapper(raw::MjvGeom* ptr, py::handle owner)
|
MjvGeomWrapper::MjWrapper(raw::MjvGeom* ptr, py::handle owner)
|
||||||
: WrapperBase(ptr, owner),
|
: WrapperBase(ptr, owner),
|
||||||
|
|||||||
+16
-13
@@ -67,20 +67,16 @@ class Handle:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
sim: _Simulate,
|
sim: _Simulate,
|
||||||
scn: mujoco.MjvScene,
|
|
||||||
cam: mujoco.MjvCamera,
|
cam: mujoco.MjvCamera,
|
||||||
opt: mujoco.MjvOption,
|
opt: mujoco.MjvOption,
|
||||||
pert: mujoco.MjvPerturb,
|
pert: mujoco.MjvPerturb,
|
||||||
|
user_scn: Optional[mujoco.MjvScene],
|
||||||
):
|
):
|
||||||
self._sim = weakref.ref(sim)
|
self._sim = weakref.ref(sim)
|
||||||
self._scn = scn
|
|
||||||
self._cam = cam
|
self._cam = cam
|
||||||
self._opt = opt
|
self._opt = opt
|
||||||
self._pert = pert
|
self._pert = pert
|
||||||
|
self._user_scn = user_scn
|
||||||
@property
|
|
||||||
def scn(self):
|
|
||||||
return self._scn
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cam(self):
|
def cam(self):
|
||||||
@@ -94,6 +90,10 @@ class Handle:
|
|||||||
def perturb(self):
|
def perturb(self):
|
||||||
return self._pert
|
return self._pert
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_scn(self):
|
||||||
|
return self._user_scn
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
sim = self._sim()
|
sim = self._sim()
|
||||||
if sim is not None:
|
if sim is not None:
|
||||||
@@ -340,14 +340,16 @@ def _launch_internal(
|
|||||||
|
|
||||||
loader = _loader
|
loader = _loader
|
||||||
|
|
||||||
if model and not run_physics_thread:
|
|
||||||
scn = mujoco.MjvScene(model, _Simulate.MAX_GEOM)
|
|
||||||
else:
|
|
||||||
scn = mujoco.MjvScene()
|
|
||||||
cam = mujoco.MjvCamera()
|
cam = mujoco.MjvCamera()
|
||||||
opt = mujoco.MjvOption()
|
opt = mujoco.MjvOption()
|
||||||
pert = mujoco.MjvPerturb()
|
pert = mujoco.MjvPerturb()
|
||||||
simulate = _Simulate(scn, cam, opt, pert, run_physics_thread, key_callback)
|
if model and not run_physics_thread:
|
||||||
|
user_scn = mujoco.MjvScene(model, _Simulate.MAX_GEOM)
|
||||||
|
else:
|
||||||
|
user_scn = None
|
||||||
|
simulate = _Simulate(
|
||||||
|
cam, opt, pert, user_scn, run_physics_thread, key_callback
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize GLFW if not using mjpython.
|
# Initialize GLFW if not using mjpython.
|
||||||
if _MJPYTHON is None:
|
if _MJPYTHON is None:
|
||||||
@@ -357,8 +359,9 @@ def _launch_internal(
|
|||||||
|
|
||||||
notify_loaded = None
|
notify_loaded = None
|
||||||
if handle_return:
|
if handle_return:
|
||||||
notify_loaded = (
|
notify_loaded = lambda: handle_return.put_nowait(
|
||||||
lambda: handle_return.put_nowait(Handle(simulate, scn, cam, opt, pert)))
|
Handle(simulate, cam, opt, pert, user_scn)
|
||||||
|
)
|
||||||
|
|
||||||
if run_physics_thread:
|
if run_physics_thread:
|
||||||
side_thread = threading.Thread(
|
side_thread = threading.Thread(
|
||||||
|
|||||||
+1
-4
@@ -474,9 +474,6 @@ int main(int argc, char** argv) {
|
|||||||
// scan for libraries in the plugin directory to load additional plugins
|
// scan for libraries in the plugin directory to load additional plugins
|
||||||
scanPluginLibraries();
|
scanPluginLibraries();
|
||||||
|
|
||||||
mjvScene scn;
|
|
||||||
mjv_defaultScene(&scn);
|
|
||||||
|
|
||||||
mjvCamera cam;
|
mjvCamera cam;
|
||||||
mjv_defaultCamera(&cam);
|
mjv_defaultCamera(&cam);
|
||||||
|
|
||||||
@@ -489,7 +486,7 @@ int main(int argc, char** argv) {
|
|||||||
// simulate object encapsulates the UI
|
// simulate object encapsulates the UI
|
||||||
auto sim = std::make_unique<mj::Simulate>(
|
auto sim = std::make_unique<mj::Simulate>(
|
||||||
std::make_unique<mj::GlfwAdapter>(),
|
std::make_unique<mj::GlfwAdapter>(),
|
||||||
&scn, &cam, &opt, &pert, /* is_passive = */ false
|
&cam, &opt, &pert, /* is_passive = */ false
|
||||||
);
|
);
|
||||||
|
|
||||||
const char* filename = nullptr;
|
const char* filename = nullptr;
|
||||||
|
|||||||
+21
-6
@@ -1737,16 +1737,15 @@ namespace mujoco {
|
|||||||
namespace mju = ::mujoco::sample_util;
|
namespace mju = ::mujoco::sample_util;
|
||||||
|
|
||||||
Simulate::Simulate(std::unique_ptr<PlatformUIAdapter> platform_ui,
|
Simulate::Simulate(std::unique_ptr<PlatformUIAdapter> platform_ui,
|
||||||
mjvScene* scn, mjvCamera* cam,
|
mjvCamera* cam, mjvOption* opt, mjvPerturb* pert,
|
||||||
mjvOption* opt, mjvPerturb* pert,
|
|
||||||
bool is_passive)
|
bool is_passive)
|
||||||
: is_passive_(is_passive),
|
: is_passive_(is_passive),
|
||||||
scn(*scn),
|
|
||||||
cam(*cam),
|
cam(*cam),
|
||||||
opt(*opt),
|
opt(*opt),
|
||||||
pert(*pert),
|
pert(*pert),
|
||||||
platform_ui(std::move(platform_ui)),
|
platform_ui(std::move(platform_ui)),
|
||||||
uistate(this->platform_ui->state()) {
|
uistate(this->platform_ui->state()) {
|
||||||
|
mjv_defaultScene(&scn);
|
||||||
mjv_defaultSceneState(&scnstate_);
|
mjv_defaultSceneState(&scnstate_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2011,6 +2010,23 @@ void Simulate::Sync() {
|
|||||||
mjv_updateScene(m_, d_, &this->opt, &this->pert, &this->cam, mjCAT_ALL, &this->scn);
|
mjv_updateScene(m_, d_, &this->opt, &this->pert, &this->cam, mjCAT_ALL, &this->scn);
|
||||||
} else {
|
} else {
|
||||||
mjv_updateSceneState(m_, d_, &this->opt, &scnstate_);
|
mjv_updateSceneState(m_, d_, &this->opt, &scnstate_);
|
||||||
|
|
||||||
|
// append geoms from user_scn to scnstate_ scratch space
|
||||||
|
if (user_scn) {
|
||||||
|
int ngeom = user_scn->ngeom;
|
||||||
|
int maxgeom = scnstate_.scratch.maxgeom - scnstate_.scratch.ngeom;
|
||||||
|
if (ngeom > maxgeom) {
|
||||||
|
mj_warning(d_, mjWARN_VGEOMFULL, scnstate_.scratch.maxgeom);
|
||||||
|
ngeom = maxgeom;
|
||||||
|
}
|
||||||
|
if (ngeom > 0) {
|
||||||
|
std::memcpy(scnstate_.scratch.geoms + scnstate_.scratch.ngeom,
|
||||||
|
user_scn->geoms,
|
||||||
|
sizeof(mjvGeom) * ngeom);
|
||||||
|
scnstate_.scratch.ngeom += ngeom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mjopt_prev_ = scnstate_.model.opt;
|
mjopt_prev_ = scnstate_.model.opt;
|
||||||
warn_vgeomfull_prev_ = scnstate_.data.warning[mjWARN_VGEOMFULL].number;
|
warn_vgeomfull_prev_ = scnstate_.data.warning[mjWARN_VGEOMFULL].number;
|
||||||
}
|
}
|
||||||
@@ -2172,9 +2188,8 @@ void Simulate::LoadOnRenderThread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// re-create scene and context
|
// re-create scene and context
|
||||||
if (!this->is_passive_) {
|
mjv_makeScene(this->m_, &this->scn, kMaxGeom);
|
||||||
mjv_makeScene(this->m_, &this->scn, kMaxGeom);
|
if (this->is_passive_) {
|
||||||
} else {
|
|
||||||
mjopt_prev_ = m_->opt;
|
mjopt_prev_ = m_->opt;
|
||||||
opt_prev_ = opt;
|
opt_prev_ = opt;
|
||||||
cam_prev_ = cam;
|
cam_prev_ = cam;
|
||||||
|
|||||||
+5
-3
@@ -51,8 +51,7 @@ class Simulate {
|
|||||||
// create object and initialize the simulate ui
|
// create object and initialize the simulate ui
|
||||||
Simulate(
|
Simulate(
|
||||||
std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
|
||||||
mjvScene* scn, mjvCamera* cam,
|
mjvCamera* cam, mjvOption* opt, mjvPerturb* pert, bool is_passive);
|
||||||
mjvOption* opt, mjvPerturb* pert, bool is_passive);
|
|
||||||
|
|
||||||
// Synchronize mjModel and mjData state with UI inputs, and update
|
// Synchronize mjModel and mjData state with UI inputs, and update
|
||||||
// visualization.
|
// visualization.
|
||||||
@@ -233,7 +232,7 @@ class Simulate {
|
|||||||
int camera = 0;
|
int camera = 0;
|
||||||
|
|
||||||
// abstract visualization
|
// abstract visualization
|
||||||
mjvScene& scn;
|
mjvScene scn;
|
||||||
mjvCamera& cam;
|
mjvCamera& cam;
|
||||||
mjvOption& opt;
|
mjvOption& opt;
|
||||||
mjvPerturb& pert;
|
mjvPerturb& pert;
|
||||||
@@ -243,6 +242,9 @@ class Simulate {
|
|||||||
mjvFigure figsize = {};
|
mjvFigure figsize = {};
|
||||||
mjvFigure figsensor = {};
|
mjvFigure figsensor = {};
|
||||||
|
|
||||||
|
// additional user-defined visualization geoms (used in passive mode)
|
||||||
|
mjvScene* user_scn = nullptr;
|
||||||
|
|
||||||
// OpenGL rendering and UI
|
// OpenGL rendering and UI
|
||||||
int refresh_rate = 60;
|
int refresh_rate = 60;
|
||||||
int window_pos[2] = {0};
|
int window_pos[2] = {0};
|
||||||
|
|||||||
@@ -48,19 +48,19 @@ static inline size_t roundUpToCacheLine(size_t n) {
|
|||||||
// set default scene
|
// set default scene
|
||||||
void mjv_defaultSceneState(mjvSceneState* scnstate) {
|
void mjv_defaultSceneState(mjvSceneState* scnstate) {
|
||||||
memset(scnstate, 0, sizeof(mjvSceneState));
|
memset(scnstate, 0, sizeof(mjvSceneState));
|
||||||
mjv_defaultScene(&scnstate->plugincache);
|
mjv_defaultScene(&scnstate->scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// allocate and init scene state
|
// allocate and init scene state
|
||||||
void mjv_makeSceneState(const mjModel* m, const mjData* d, mjvSceneState* scnstate, int maxgeom) {
|
void mjv_makeSceneState(const mjModel* m, const mjData* d, mjvSceneState* scnstate, int maxgeom) {
|
||||||
mjv_freeScene(&scnstate->plugincache);
|
mjv_freeScene(&scnstate->scratch);
|
||||||
mju_free(scnstate->buffer);
|
mju_free(scnstate->buffer);
|
||||||
|
|
||||||
#ifdef MEMORY_SANITIZER
|
#ifdef MEMORY_SANITIZER
|
||||||
__msan_allocated_memory(scnstate, sizeof(mjvSceneState));
|
__msan_allocated_memory(scnstate, sizeof(mjvSceneState));
|
||||||
mjv_defaultScene(&scnstate->plugincache);
|
mjv_defaultScene(&scnstate->scratch);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scnstate->nbuffer = 0;
|
scnstate->nbuffer = 0;
|
||||||
@@ -144,14 +144,14 @@ void mjv_makeSceneState(const mjModel* m, const mjData* d, mjvSceneState* scnsta
|
|||||||
mjERROR("mjvSceneState buffer is not fully used");
|
mjERROR("mjvSceneState buffer is not fully used");
|
||||||
}
|
}
|
||||||
|
|
||||||
mjv_makeScene(m, &scnstate->plugincache, maxgeom);
|
mjv_makeScene(m, &scnstate->scratch, maxgeom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// free scene state
|
// free scene state
|
||||||
void mjv_freeSceneState(mjvSceneState* scnstate) {
|
void mjv_freeSceneState(mjvSceneState* scnstate) {
|
||||||
mjv_freeScene(&scnstate->plugincache);
|
mjv_freeScene(&scnstate->scratch);
|
||||||
mju_free(scnstate->buffer);
|
mju_free(scnstate->buffer);
|
||||||
mjv_defaultSceneState(scnstate);
|
mjv_defaultSceneState(scnstate);
|
||||||
}
|
}
|
||||||
@@ -229,14 +229,14 @@ int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt
|
|||||||
int warning_start = d.warning[mjWARN_VGEOMFULL].number;
|
int warning_start = d.warning[mjWARN_VGEOMFULL].number;
|
||||||
|
|
||||||
// copy mjvGeoms added by plugins
|
// copy mjvGeoms added by plugins
|
||||||
int nplugingeom = scnstate->plugincache.ngeom;
|
int nplugingeom = scnstate->scratch.ngeom;
|
||||||
if (nplugingeom > scn->maxgeom) {
|
if (nplugingeom > scn->maxgeom) {
|
||||||
mj_warning(&d, mjWARN_VGEOMFULL, scn->maxgeom);
|
mj_warning(&d, mjWARN_VGEOMFULL, scn->maxgeom);
|
||||||
scn->ngeom = scn->maxgeom;
|
scn->ngeom = scn->maxgeom;
|
||||||
} else {
|
} else {
|
||||||
scn->ngeom = nplugingeom;
|
scn->ngeom = nplugingeom;
|
||||||
}
|
}
|
||||||
memcpy(scn->geoms, scnstate->plugincache.geoms, sizeof(mjvGeom) * scn->ngeom);
|
memcpy(scn->geoms, scnstate->scratch.geoms, sizeof(mjvGeom) * scn->ngeom);
|
||||||
|
|
||||||
// add all categories
|
// add all categories
|
||||||
mjv_addGeoms(&m, &d, opt, pert, catmask, scn);
|
mjv_addGeoms(&m, &d, opt, pert, catmask, scn);
|
||||||
@@ -272,7 +272,7 @@ void mjv_updateSceneState(const mjModel* m, mjData* d, const mjvOption* opt,
|
|||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
// Update plugin visualization cache.
|
// Update plugin visualization cache.
|
||||||
scnstate->plugincache.ngeom = 0;
|
scnstate->scratch.ngeom = 0;
|
||||||
if (m->nplugin) {
|
if (m->nplugin) {
|
||||||
const int nslot = mjp_pluginCount();
|
const int nslot = mjp_pluginCount();
|
||||||
// iterate over plugins, call visualize if defined
|
// iterate over plugins, call visualize if defined
|
||||||
@@ -283,7 +283,7 @@ void mjv_updateSceneState(const mjModel* m, mjData* d, const mjvOption* opt,
|
|||||||
mjERROR("invalid plugin slot: %d", slot);
|
mjERROR("invalid plugin slot: %d", slot);
|
||||||
}
|
}
|
||||||
if (plugin->visualize) {
|
if (plugin->visualize) {
|
||||||
plugin->visualize(m, d, opt, &scnstate->plugincache, i);
|
plugin->visualize(m, d, opt, &scnstate->scratch, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6148,7 +6148,7 @@ public unsafe struct mjvSceneState_ {
|
|||||||
public int nbuffer;
|
public int nbuffer;
|
||||||
public void* buffer;
|
public void* buffer;
|
||||||
public int maxgeom;
|
public int maxgeom;
|
||||||
public mjvScene_ plugincache;
|
public mjvScene_ scratch;
|
||||||
public model model;
|
public model model;
|
||||||
public data data;
|
public data data;
|
||||||
}public struct mjuiItem_ {}public struct mjfItemEnable {}
|
}public struct mjuiItem_ {}public struct mjfItemEnable {}
|
||||||
|
|||||||
Reference in New Issue
Block a user