Reformat README.md for better readability.
Wrap long lines to 80 characters. PiperOrigin-RevId: 877983563 Change-Id: I10db94397eb3c2db070734ae78073073eefa0184
This commit is contained in:
committed by
Copybara-Service
parent
c94a5f3bad
commit
0974612338
+49
-19
@@ -123,8 +123,8 @@ joint using `data.jnt('myjoint')`.
|
||||
For more details and examples of how to use named access, please refer to the [named access tests](tests/bindings_test.ts#L1876-L2378) and [documentation](https://mujoco.readthedocs.io/en/stable/python.html#named-access).
|
||||
|
||||
### Memory Management
|
||||
Embind-wrapped C++ object handles created or returned into JavaScript live on the
|
||||
WebAssembly heap and are **not** garbage-collected by the JS runtime.
|
||||
Embind-wrapped C++ object handles created or returned into JavaScript live on
|
||||
the WebAssembly heap and are **not** garbage-collected by the JS runtime.
|
||||
|
||||
Any heap-allocated C++ object exposed to JS (e.g. via `new Module.MyClass(...)`
|
||||
or returned as a pointer/reference from a binding) must be explicitly freed
|
||||
@@ -144,19 +144,26 @@ is an error). In JS code paths that may throw or return early, ensure
|
||||
deletion happens in finally blocks or wrap lifetime management to avoid leaks.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> _Embind's documentation strongly recommends that JavaScript code explicitly deletes any C++ object handles it has received._
|
||||
> _Embind's documentation strongly recommends that JavaScript code explicitly
|
||||
> deletes any C++ object handles it has received._
|
||||
|
||||
### Copy vs. Reference
|
||||
|
||||
When interacting with MuJoCo objects through the WASM bindings, it's important to understand how data is accessed. Properties on objects like `MjModel` and `MjData` can expose data in two ways: by copy or by reference.
|
||||
When interacting with MuJoCo objects through the WASM bindings, it's important
|
||||
to understand how data is accessed. Properties on objects like `MjModel` and
|
||||
`MjData` can expose data in two ways: by copy or by reference.
|
||||
|
||||
#### 1. By Copy (Value-based access)
|
||||
|
||||
Some properties return a copy of the data at the time of access. This is common for complex data structures that need to be marshalled from C++ to JavaScript.
|
||||
Some properties return a copy of the data at the time of access. This is common
|
||||
for complex data structures that need to be marshalled from C++ to JavaScript.
|
||||
|
||||
A key example is `MjData.contact`. When you access `data.contact`, you get an object containing a copy of the contacts at that specific moment in the simulation.
|
||||
A key example is `MjData.contact`. When you access `data.contact`, you get an
|
||||
object containing a copy of the contacts at that specific moment in the
|
||||
simulation.
|
||||
|
||||
If you step the simulation forward, they will not be updated. You must access `data.contact` again to get the new contact information.
|
||||
If you step the simulation forward, they will not be updated. You must access
|
||||
`data.contact` again to get the new contact information.
|
||||
|
||||
The object you get is a JavaScript proxy interface generated by [Emscripten’s Embind library](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#built-in-type-conversions) when you expose a `std::vector` using `register_vector<T>`. It is essentially a "bridge" object.
|
||||
|
||||
@@ -193,9 +200,14 @@ newContacts.delete();
|
||||
|
||||
#### 2. By Reference (View-based access)
|
||||
|
||||
Many properties, especially large numerical arrays, return a live view directly into the WebAssembly memory. This is highly efficient as it avoids copying large amounts of data.
|
||||
Many properties, especially large numerical arrays, return a live view directly
|
||||
into the WebAssembly memory. This is highly efficient as it avoids copying large
|
||||
amounts of data.
|
||||
|
||||
A key example is `MjData.qpos` (joint positions). When you get a reference to this array, it points directly to the simulation's state data. Any changes in the simulation (e.g., after a call to `mj_step`) will be immediately reflected in this array.
|
||||
A key example is `MjData.qpos` (joint positions). When you get a reference to
|
||||
this array, it points directly to the simulation's state data. Any changes in
|
||||
the simulation (e.g., after a call to `mj_step`) will be immediately reflected
|
||||
in this array.
|
||||
|
||||
```typescript
|
||||
// `qpos` is a live view into the simulation state.
|
||||
@@ -215,9 +227,13 @@ data.delete();
|
||||
|
||||
### Data Layout: Row-Major Matrices
|
||||
|
||||
When a function from the MuJoCo C API returns a matrix (or needs a matrix as input), these are represented in the JavaScript bindings as flat, one-dimensional `TypedArray`'s. The elements are stored in row-major order.
|
||||
When a function from the MuJoCo C API returns a matrix (or needs a matrix as
|
||||
input), these are represented in the JavaScript bindings as flat,
|
||||
one-dimensional `TypedArray`'s. The elements are stored in row-major order.
|
||||
|
||||
For example, a 3x10 matrix will be returned as a flat array with 30 elements. The first 10 elements represent the first row, the next 10 represent the second row, and so on.
|
||||
For example, a 3x10 matrix will be returned as a flat array with 30 elements.
|
||||
The first 10 elements represent the first row, the next 10 represent the second
|
||||
row, and so on.
|
||||
|
||||
Example: Accessing an element at `(row, col)`
|
||||
```typescript
|
||||
@@ -232,13 +248,19 @@ const element = matrix[i * nCols + j];
|
||||
|
||||
### Working with Out Parameters
|
||||
|
||||
Many functions in the MuJoCo C API use "out parameters" to return data. This means instead of returning a value, they write the result into one of the arguments passed to them by reference (using pointers). In our JavaScript bindings, you'll need to handle these cases specifically.
|
||||
Many functions in the MuJoCo C API use "out parameters" to return data. This
|
||||
means instead of returning a value, they write the result into one of the
|
||||
arguments passed to them by reference (using pointers). In our JavaScript
|
||||
bindings, you'll need to handle these cases specifically.
|
||||
|
||||
There are two main scenarios you'll encounter:
|
||||
|
||||
#### 1. Array-like Out Parameters
|
||||
|
||||
When a function expects a pointer to a primitive type (like `mjtNum*` or `int*`) to write an array of values, you need to pre-allocate memory for the result on the JavaScript side. We provide helper classes for this: `mujoco.Uint8Buffer`, `mujoco.DoubleBuffer`, `mujoco.FloatBuffer`, and `mujoco.IntBuffer`.
|
||||
When a function expects a pointer to a primitive type (like `mjtNum*` or `int*`)
|
||||
to write an array of values, you need to pre-allocate memory for the result on
|
||||
the JavaScript side. We provide helper classes for this: `mujoco.Uint8Buffer`,
|
||||
`mujoco.DoubleBuffer`, `mujoco.FloatBuffer`, and `mujoco.IntBuffer`.
|
||||
|
||||
Here's how to use them:
|
||||
|
||||
@@ -249,7 +271,8 @@ Here's how to use them:
|
||||
|
||||
Example: Rotating a vector
|
||||
|
||||
The function `mju_rotVecQuat` rotates a vector `vec` by a quaternion `quat` and stores the result in the `res` out parameter.
|
||||
The function `mju_rotVecQuat` rotates a vector `vec` by a quaternion `quat` and
|
||||
stores the result in the `res` out parameter.
|
||||
|
||||
```typescript
|
||||
// Create a buffer to hold the 3D vector result.
|
||||
@@ -274,11 +297,14 @@ try {
|
||||
|
||||
#### 2. Struct Out Parameters (e.g., mjvCamera*, mjvScene*)
|
||||
|
||||
When a function modifies a struct passed by pointer, you should pass an instance of the corresponding JavaScript wrapper class. The underlying C++ struct will be modified in place.
|
||||
When a function modifies a struct passed by pointer, you should pass an instance
|
||||
of the corresponding JavaScript wrapper class. The underlying C++ struct will be
|
||||
modified in place.
|
||||
|
||||
Example: Updating a scene
|
||||
|
||||
The function `mjv_updateScene` populates an `mjvScene` object with information from `mjModel` and `mjData`.
|
||||
The function `mjv_updateScene` populates an `mjvScene` object with information
|
||||
from `mjModel` and `mjData`.
|
||||
```typescript
|
||||
// Create instances of the necessary structs.
|
||||
const model = mujoco.MjModel.loadFromXML(xmlContent);
|
||||
@@ -312,7 +338,8 @@ data.delete();
|
||||
model.delete();
|
||||
```
|
||||
|
||||
As with buffers, you are responsible for managing the memory of these struct instances and must call `.delete()` on them when you are finished.
|
||||
As with buffers, you are responsible for managing the memory of these struct
|
||||
instances and must call `.delete()` on them when you are finished.
|
||||
|
||||
### Enums
|
||||
Access via `.value`:
|
||||
@@ -327,13 +354,16 @@ Scalar constants will be accessed the same way they are on python, simply:
|
||||
mujoco.mjNEQDATA
|
||||
```
|
||||
|
||||
Due to Embind limitations, more complex constants that are not scalar, but are represented in more dimensions are exposed as functions. E.g to use `mujoco.mjFRAMESTRING` you will need to call a function:
|
||||
Due to Embind limitations, more complex constants that are not scalar, but are
|
||||
represented in more dimensions are exposed as functions. E.g. to use
|
||||
`mujoco.mjFRAMESTRING` you will need to call a function:
|
||||
|
||||
```javascript
|
||||
mujoco.get_mjFRAMESTRING()
|
||||
```
|
||||
|
||||
This will return a javascript array representation of the values in MuJoCo `mjFRAMESTRING`.
|
||||
This will return a javascript array representation of the values in MuJoCo
|
||||
`mjFRAMESTRING`.
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
Reference in New Issue
Block a user