Add vertex-based flex constraints (dim=2).
PiperOrigin-RevId: 859552050 Change-Id: I61d4b9dc40f041c5b930e5f8810a803e8bccb87a
This commit is contained in:
committed by
Copybara-Service
parent
2cc2e579f1
commit
54dd623650
@@ -274,6 +274,8 @@ struct mjData_ {
|
|||||||
mjtNum* flexelem_aabb; // flex element bounding boxes (center, size) (nflexelem x 6)
|
mjtNum* flexelem_aabb; // flex element bounding boxes (center, size) (nflexelem x 6)
|
||||||
mjtNum* flexedge_J; // flex edge Jacobian (nJfe x 1)
|
mjtNum* flexedge_J; // flex edge Jacobian (nJfe x 1)
|
||||||
mjtNum* flexedge_length; // flex edge lengths (nflexedge x 1)
|
mjtNum* flexedge_length; // flex edge lengths (nflexedge x 1)
|
||||||
|
mjtNum* flexvert_J; // flex vertex Jacobian (nJfv x 2)
|
||||||
|
mjtNum* flexvert_length; // flex vertex lengths (nflexvert x 2)
|
||||||
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
|
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
|
||||||
|
|
||||||
// computed by mj_fwdPosition/mj_tendon
|
// computed by mj_fwdPosition/mj_tendon
|
||||||
@@ -1034,6 +1036,7 @@ struct mjModel_ {
|
|||||||
int nflexevpair; // number of element-vertex pairs in all flexes
|
int nflexevpair; // number of element-vertex pairs in all flexes
|
||||||
int nflextexcoord; // number of vertices with texture coordinates
|
int nflextexcoord; // number of vertices with texture coordinates
|
||||||
int nJfe; // number of non-zeros in sparse flexedge Jacobian matrix
|
int nJfe; // number of non-zeros in sparse flexedge Jacobian matrix
|
||||||
|
int nJfv; // number of non-zeros in sparse flexvert Jacobian matrix
|
||||||
int nmesh; // number of meshes
|
int nmesh; // number of meshes
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshnormal; // number of normals in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
@@ -1328,12 +1331,13 @@ struct mjModel_ {
|
|||||||
mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1)
|
mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1)
|
||||||
mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1)
|
mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1)
|
||||||
mjtNum* flex_radius; // radius around primitive element (nflex x 1)
|
mjtNum* flex_radius; // radius around primitive element (nflex x 1)
|
||||||
|
mjtNum* flex_size; // vertex bounding box half sizes in qpos0 (nflex x 3)
|
||||||
mjtNum* flex_stiffness; // finite element stiffness matrix (nflexelem x 21)
|
mjtNum* flex_stiffness; // finite element stiffness matrix (nflexelem x 21)
|
||||||
mjtNum* flex_bending; // bending stiffness (nflexedge x 17)
|
mjtNum* flex_bending; // bending stiffness (nflexedge x 17)
|
||||||
mjtNum* flex_damping; // Rayleigh's damping coefficient (nflex x 1)
|
mjtNum* flex_damping; // Rayleigh's damping coefficient (nflex x 1)
|
||||||
mjtNum* flex_edgestiffness; // edge stiffness (nflex x 1)
|
mjtNum* flex_edgestiffness; // edge stiffness (nflex x 1)
|
||||||
mjtNum* flex_edgedamping; // edge damping (nflex x 1)
|
mjtNum* flex_edgedamping; // edge damping (nflex x 1)
|
||||||
mjtByte* flex_edgeequality; // is edge equality constraint defined (nflex x 1)
|
int* flex_edgeequality; // 0: none, 1: edges, 2: vertices (nflex x 1)
|
||||||
mjtByte* flex_rigid; // are all vertices in the same body (nflex x 1)
|
mjtByte* flex_rigid; // are all vertices in the same body (nflex x 1)
|
||||||
mjtByte* flexedge_rigid; // are both edge vertices in same body (nflexedge x 1)
|
mjtByte* flexedge_rigid; // are both edge vertices in same body (nflexedge x 1)
|
||||||
mjtByte* flex_centered; // are all vertex coordinates (0,0,0) (nflex x 1)
|
mjtByte* flex_centered; // are all vertex coordinates (0,0,0) (nflex x 1)
|
||||||
@@ -1343,6 +1347,9 @@ struct mjModel_ {
|
|||||||
int* flexedge_J_rownnz; // number of non-zeros in Jacobian row (nflexedge x 1)
|
int* flexedge_J_rownnz; // number of non-zeros in Jacobian row (nflexedge x 1)
|
||||||
int* flexedge_J_rowadr; // row start address in colind array (nflexedge x 1)
|
int* flexedge_J_rowadr; // row start address in colind array (nflexedge x 1)
|
||||||
int* flexedge_J_colind; // column indices in sparse Jacobian (nJfe x 1)
|
int* flexedge_J_colind; // column indices in sparse Jacobian (nJfe x 1)
|
||||||
|
int* flexvert_J_rownnz; // number of non-zeros in Jacobian row (nflexvert x 2)
|
||||||
|
int* flexvert_J_rowadr; // row start address in colind array (nflexvert x 2)
|
||||||
|
int* flexvert_J_colind; // column indices in sparse Jacobian (nJfv x 2)
|
||||||
float* flex_rgba; // rgba when material is omitted (nflex x 4)
|
float* flex_rgba; // rgba when material is omitted (nflex x 4)
|
||||||
float* flex_texcoord; // vertex texture coordinates (nflextexcoord x 2)
|
float* flex_texcoord; // vertex texture coordinates (nflextexcoord x 2)
|
||||||
|
|
||||||
@@ -2186,6 +2193,7 @@ typedef struct mjsFlex_ { // flex specification
|
|||||||
// other properties
|
// other properties
|
||||||
int dim; // element dimensionality
|
int dim; // element dimensionality
|
||||||
double radius; // radius around primitive element
|
double radius; // radius around primitive element
|
||||||
|
double size[3]; // vertex bounding box half sizes in qpos0
|
||||||
mjtByte internal; // enable internal collisions
|
mjtByte internal; // enable internal collisions
|
||||||
mjtByte flatskin; // render flex skin with flat shading
|
mjtByte flatskin; // render flex skin with flat shading
|
||||||
int selfcollide; // mode for flex self collision
|
int selfcollide; // mode for flex self collision
|
||||||
|
|||||||
@@ -308,6 +308,8 @@ struct mjData_ {
|
|||||||
mjtNum* flexelem_aabb; // flex element bounding boxes (center, size) (nflexelem x 6)
|
mjtNum* flexelem_aabb; // flex element bounding boxes (center, size) (nflexelem x 6)
|
||||||
mjtNum* flexedge_J; // flex edge Jacobian (nJfe x 1)
|
mjtNum* flexedge_J; // flex edge Jacobian (nJfe x 1)
|
||||||
mjtNum* flexedge_length; // flex edge lengths (nflexedge x 1)
|
mjtNum* flexedge_length; // flex edge lengths (nflexedge x 1)
|
||||||
|
mjtNum* flexvert_J; // flex vertex Jacobian (nJfv x 2)
|
||||||
|
mjtNum* flexvert_length; // flex vertex lengths (nflexvert x 2)
|
||||||
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
|
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
|
||||||
|
|
||||||
// computed by mj_fwdPosition/mj_tendon
|
// computed by mj_fwdPosition/mj_tendon
|
||||||
|
|||||||
@@ -702,6 +702,7 @@ struct mjModel_ {
|
|||||||
int nflexevpair; // number of element-vertex pairs in all flexes
|
int nflexevpair; // number of element-vertex pairs in all flexes
|
||||||
int nflextexcoord; // number of vertices with texture coordinates
|
int nflextexcoord; // number of vertices with texture coordinates
|
||||||
int nJfe; // number of non-zeros in sparse flexedge Jacobian matrix
|
int nJfe; // number of non-zeros in sparse flexedge Jacobian matrix
|
||||||
|
int nJfv; // number of non-zeros in sparse flexvert Jacobian matrix
|
||||||
int nmesh; // number of meshes
|
int nmesh; // number of meshes
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshnormal; // number of normals in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
@@ -996,12 +997,13 @@ struct mjModel_ {
|
|||||||
mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1)
|
mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1)
|
||||||
mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1)
|
mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1)
|
||||||
mjtNum* flex_radius; // radius around primitive element (nflex x 1)
|
mjtNum* flex_radius; // radius around primitive element (nflex x 1)
|
||||||
|
mjtNum* flex_size; // vertex bounding box half sizes in qpos0 (nflex x 3)
|
||||||
mjtNum* flex_stiffness; // finite element stiffness matrix (nflexelem x 21)
|
mjtNum* flex_stiffness; // finite element stiffness matrix (nflexelem x 21)
|
||||||
mjtNum* flex_bending; // bending stiffness (nflexedge x 17)
|
mjtNum* flex_bending; // bending stiffness (nflexedge x 17)
|
||||||
mjtNum* flex_damping; // Rayleigh's damping coefficient (nflex x 1)
|
mjtNum* flex_damping; // Rayleigh's damping coefficient (nflex x 1)
|
||||||
mjtNum* flex_edgestiffness; // edge stiffness (nflex x 1)
|
mjtNum* flex_edgestiffness; // edge stiffness (nflex x 1)
|
||||||
mjtNum* flex_edgedamping; // edge damping (nflex x 1)
|
mjtNum* flex_edgedamping; // edge damping (nflex x 1)
|
||||||
mjtByte* flex_edgeequality; // is edge equality constraint defined (nflex x 1)
|
int* flex_edgeequality; // 0: none, 1: edges, 2: vertices (nflex x 1)
|
||||||
mjtByte* flex_rigid; // are all vertices in the same body (nflex x 1)
|
mjtByte* flex_rigid; // are all vertices in the same body (nflex x 1)
|
||||||
mjtByte* flexedge_rigid; // are both edge vertices in same body (nflexedge x 1)
|
mjtByte* flexedge_rigid; // are both edge vertices in same body (nflexedge x 1)
|
||||||
mjtByte* flex_centered; // are all vertex coordinates (0,0,0) (nflex x 1)
|
mjtByte* flex_centered; // are all vertex coordinates (0,0,0) (nflex x 1)
|
||||||
@@ -1011,6 +1013,9 @@ struct mjModel_ {
|
|||||||
int* flexedge_J_rownnz; // number of non-zeros in Jacobian row (nflexedge x 1)
|
int* flexedge_J_rownnz; // number of non-zeros in Jacobian row (nflexedge x 1)
|
||||||
int* flexedge_J_rowadr; // row start address in colind array (nflexedge x 1)
|
int* flexedge_J_rowadr; // row start address in colind array (nflexedge x 1)
|
||||||
int* flexedge_J_colind; // column indices in sparse Jacobian (nJfe x 1)
|
int* flexedge_J_colind; // column indices in sparse Jacobian (nJfe x 1)
|
||||||
|
int* flexvert_J_rownnz; // number of non-zeros in Jacobian row (nflexvert x 2)
|
||||||
|
int* flexvert_J_rowadr; // row start address in colind array (nflexvert x 2)
|
||||||
|
int* flexvert_J_colind; // column indices in sparse Jacobian (nJfv x 2)
|
||||||
float* flex_rgba; // rgba when material is omitted (nflex x 4)
|
float* flex_rgba; // rgba when material is omitted (nflex x 4)
|
||||||
float* flex_texcoord; // vertex texture coordinates (nflextexcoord x 2)
|
float* flex_texcoord; // vertex texture coordinates (nflextexcoord x 2)
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,7 @@ typedef struct mjsFlex_ { // flex specification
|
|||||||
// other properties
|
// other properties
|
||||||
int dim; // element dimensionality
|
int dim; // element dimensionality
|
||||||
double radius; // radius around primitive element
|
double radius; // radius around primitive element
|
||||||
|
double size[3]; // vertex bounding box half sizes in qpos0
|
||||||
mjtByte internal; // enable internal collisions
|
mjtByte internal; // enable internal collisions
|
||||||
mjtByte flatskin; // render flex skin with flat shading
|
mjtByte flatskin; // render flex skin with flat shading
|
||||||
int selfcollide; // mode for flex self collision
|
int selfcollide; // mode for flex self collision
|
||||||
|
|||||||
@@ -97,6 +97,7 @@
|
|||||||
X( nflexevpair ) \
|
X( nflexevpair ) \
|
||||||
X( nflextexcoord ) \
|
X( nflextexcoord ) \
|
||||||
X( nJfe ) \
|
X( nJfe ) \
|
||||||
|
X( nJfv ) \
|
||||||
X( nmesh ) \
|
X( nmesh ) \
|
||||||
X( nmeshvert ) \
|
X( nmeshvert ) \
|
||||||
X( nmeshnormal ) \
|
X( nmeshnormal ) \
|
||||||
@@ -386,12 +387,13 @@
|
|||||||
X ( mjtNum, flexedge_length0, nflexedge, 1 ) \
|
X ( mjtNum, flexedge_length0, nflexedge, 1 ) \
|
||||||
X ( mjtNum, flexedge_invweight0, nflexedge, 1 ) \
|
X ( mjtNum, flexedge_invweight0, nflexedge, 1 ) \
|
||||||
X ( mjtNum, flex_radius, nflex, 1 ) \
|
X ( mjtNum, flex_radius, nflex, 1 ) \
|
||||||
|
X ( mjtNum, flex_size, nflex, 3 ) \
|
||||||
X ( mjtNum, flex_stiffness, nflexelem, 21 ) \
|
X ( mjtNum, flex_stiffness, nflexelem, 21 ) \
|
||||||
X ( mjtNum, flex_bending, nflexedge, 17 ) \
|
X ( mjtNum, flex_bending, nflexedge, 17 ) \
|
||||||
X ( mjtNum, flex_damping, nflex, 1 ) \
|
X ( mjtNum, flex_damping, nflex, 1 ) \
|
||||||
X ( mjtNum, flex_edgestiffness, nflex, 1 ) \
|
X ( mjtNum, flex_edgestiffness, nflex, 1 ) \
|
||||||
X ( mjtNum, flex_edgedamping, nflex, 1 ) \
|
X ( mjtNum, flex_edgedamping, nflex, 1 ) \
|
||||||
X ( mjtByte, flex_edgeequality, nflex, 1 ) \
|
X ( int, flex_edgeequality, nflex, 1 ) \
|
||||||
X ( mjtByte, flex_rigid, nflex, 1 ) \
|
X ( mjtByte, flex_rigid, nflex, 1 ) \
|
||||||
X ( mjtByte, flexedge_rigid, nflexedge, 1 ) \
|
X ( mjtByte, flexedge_rigid, nflexedge, 1 ) \
|
||||||
X ( mjtByte, flex_centered, nflex, 1 ) \
|
X ( mjtByte, flex_centered, nflex, 1 ) \
|
||||||
@@ -401,6 +403,9 @@
|
|||||||
X ( int, flexedge_J_rownnz, nflexedge, 1 ) \
|
X ( int, flexedge_J_rownnz, nflexedge, 1 ) \
|
||||||
X ( int, flexedge_J_rowadr, nflexedge, 1 ) \
|
X ( int, flexedge_J_rowadr, nflexedge, 1 ) \
|
||||||
X ( int, flexedge_J_colind, nJfe, 1 ) \
|
X ( int, flexedge_J_colind, nJfe, 1 ) \
|
||||||
|
X ( int, flexvert_J_rownnz, nflexvert, 2 ) \
|
||||||
|
X ( int, flexvert_J_rowadr, nflexvert, 2 ) \
|
||||||
|
X ( int, flexvert_J_colind, nJfv, 2 ) \
|
||||||
X ( float, flex_rgba, nflex, 4 ) \
|
X ( float, flex_rgba, nflex, 4 ) \
|
||||||
X ( float, flex_texcoord, nflextexcoord, 2 )
|
X ( float, flex_texcoord, nflextexcoord, 2 )
|
||||||
|
|
||||||
@@ -736,6 +741,8 @@
|
|||||||
X ( mjtNum, flexelem_aabb, nflexelem, 6 ) \
|
X ( mjtNum, flexelem_aabb, nflexelem, 6 ) \
|
||||||
X ( mjtNum, flexedge_J, nJfe, 1 ) \
|
X ( mjtNum, flexedge_J, nJfe, 1 ) \
|
||||||
X ( mjtNum, flexedge_length, nflexedge, 1 ) \
|
X ( mjtNum, flexedge_length, nflexedge, 1 ) \
|
||||||
|
X ( mjtNum, flexvert_J, nJfv, 2 ) \
|
||||||
|
X ( mjtNum, flexvert_length, nflexvert, 2 ) \
|
||||||
X ( mjtNum, bvh_aabb_dyn, nbvhdynamic, 6 ) \
|
X ( mjtNum, bvh_aabb_dyn, nbvhdynamic, 6 ) \
|
||||||
X ( int, ten_wrapadr, ntendon, 1 ) \
|
X ( int, ten_wrapadr, ntendon, 1 ) \
|
||||||
X ( int, ten_wrapnum, ntendon, 1 ) \
|
X ( int, ten_wrapnum, ntendon, 1 ) \
|
||||||
|
|||||||
@@ -997,6 +997,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
doc='number of non-zeros in sparse flexedge Jacobian matrix',
|
doc='number of non-zeros in sparse flexedge Jacobian matrix',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='nJfv',
|
||||||
|
type=ValueType(name='int'),
|
||||||
|
doc='number of non-zeros in sparse flexvert Jacobian matrix',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='nmesh',
|
name='nmesh',
|
||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
@@ -2880,6 +2885,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='radius around primitive element',
|
doc='radius around primitive element',
|
||||||
array_extent=('nflex',),
|
array_extent=('nflex',),
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flex_size',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjtNum'),
|
||||||
|
),
|
||||||
|
doc='vertex bounding box half sizes in qpos0',
|
||||||
|
array_extent=('nflex', 3),
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='flex_stiffness',
|
name='flex_stiffness',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
@@ -2923,9 +2936,9 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='flex_edgeequality',
|
name='flex_edgeequality',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
inner_type=ValueType(name='mjtByte'),
|
inner_type=ValueType(name='int'),
|
||||||
),
|
),
|
||||||
doc='is edge equality constraint defined',
|
doc='0: none, 1: edges, 2: vertices',
|
||||||
array_extent=('nflex',),
|
array_extent=('nflex',),
|
||||||
),
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
@@ -3000,6 +3013,30 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='column indices in sparse Jacobian',
|
doc='column indices in sparse Jacobian',
|
||||||
array_extent=('nJfe',),
|
array_extent=('nJfe',),
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flexvert_J_rownnz',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='int'),
|
||||||
|
),
|
||||||
|
doc='number of non-zeros in Jacobian row',
|
||||||
|
array_extent=('nflexvert', 2),
|
||||||
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flexvert_J_rowadr',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='int'),
|
||||||
|
),
|
||||||
|
doc='row start address in colind array',
|
||||||
|
array_extent=('nflexvert', 2),
|
||||||
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flexvert_J_colind',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='int'),
|
||||||
|
),
|
||||||
|
doc='column indices in sparse Jacobian',
|
||||||
|
array_extent=('nJfv', 2),
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='flex_rgba',
|
name='flex_rgba',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
@@ -5609,6 +5646,22 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='flex edge lengths',
|
doc='flex edge lengths',
|
||||||
array_extent=('nflexedge',),
|
array_extent=('nflexedge',),
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flexvert_J',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjtNum'),
|
||||||
|
),
|
||||||
|
doc='flex vertex Jacobian',
|
||||||
|
array_extent=('nJfv', 2),
|
||||||
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='flexvert_length',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjtNum'),
|
||||||
|
),
|
||||||
|
doc='flex vertex lengths',
|
||||||
|
array_extent=('nflexvert', 2),
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='bvh_aabb_dyn',
|
name='bvh_aabb_dyn',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
@@ -7879,6 +7932,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='double'),
|
type=ValueType(name='double'),
|
||||||
doc='radius around primitive element',
|
doc='radius around primitive element',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='size',
|
||||||
|
type=ArrayType(
|
||||||
|
inner_type=ValueType(name='double'),
|
||||||
|
extents=(3,),
|
||||||
|
),
|
||||||
|
doc='vertex bounding box half sizes in qpos0',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='internal',
|
name='internal',
|
||||||
type=ValueType(name='mjtByte'),
|
type=ValueType(name='mjtByte'),
|
||||||
|
|||||||
@@ -537,6 +537,7 @@ void mj_updateDynamicBVH(const mjModel* m, mjData* d, int bvhadr, int bvhnum) {
|
|||||||
void mj_flex(const mjModel* m, mjData* d) {
|
void mj_flex(const mjModel* m, mjData* d) {
|
||||||
int nv = m->nv;
|
int nv = m->nv;
|
||||||
int* rowadr = m->flexedge_J_rowadr, *rownnz = m->flexedge_J_rownnz;
|
int* rowadr = m->flexedge_J_rowadr, *rownnz = m->flexedge_J_rownnz;
|
||||||
|
int* vrowadr = m->flexvert_J_rowadr, *vrownnz = m->flexvert_J_rownnz;
|
||||||
|
|
||||||
// skip if no flexes
|
// skip if no flexes
|
||||||
if (!m->nflex) {
|
if (!m->nflex) {
|
||||||
@@ -659,6 +660,9 @@ void mj_flex(const mjModel* m, mjData* d) {
|
|||||||
// clear Jacobian
|
// clear Jacobian
|
||||||
mju_zeroInt(rowadr, m->nflexedge);
|
mju_zeroInt(rowadr, m->nflexedge);
|
||||||
mju_zeroInt(rownnz, m->nflexedge);
|
mju_zeroInt(rownnz, m->nflexedge);
|
||||||
|
mju_zeroInt(vrowadr, 2*m->nflexvert);
|
||||||
|
mju_zeroInt(vrownnz, 2*m->nflexvert);
|
||||||
|
mju_zero(d->flexvert_J, 2*m->nJfv);
|
||||||
|
|
||||||
// compute lengths and Jacobians of edges
|
// compute lengths and Jacobians of edges
|
||||||
for (int f=0; f < m->nflex; f++) {
|
for (int f=0; f < m->nflex; f++) {
|
||||||
@@ -715,6 +719,321 @@ void mj_flex(const mjModel* m, mjData* d) {
|
|||||||
rownnz[ebase+e] = NV;
|
rownnz[ebase+e] = NV;
|
||||||
mju_copyInt(m->flexedge_J_colind + rowadr[ebase+e], chain, NV);
|
mju_copyInt(m->flexedge_J_colind + rowadr[ebase+e], chain, NV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if dim=2 and constraints are active we use the vertex-based constraint defined in
|
||||||
|
// Chen, Kry, and Vouga, "Locking-free Simulation of Isometric Thin Plates", 2019.
|
||||||
|
if (m->flex_dim[f] == 2 && m->flex_edgeequality[f] == 2) {
|
||||||
|
int nvert = m->flex_vertnum[f];
|
||||||
|
mjtNum edge1[3], edge2[3], normal[3];
|
||||||
|
mjtNum quat[4], mat[9];
|
||||||
|
int t_adr, t0, t1, t2;
|
||||||
|
|
||||||
|
mj_markStack(d);
|
||||||
|
int* buf_ind = mjSTACKALLOC(d, nv, int);
|
||||||
|
|
||||||
|
// compute normal from first element
|
||||||
|
t_adr = m->flex_elemdataadr[f];
|
||||||
|
t0 = m->flex_elem[t_adr];
|
||||||
|
t1 = m->flex_elem[t_adr+1];
|
||||||
|
t2 = m->flex_elem[t_adr+2];
|
||||||
|
|
||||||
|
mju_sub3(edge1, m->flex_vert0 + 3*(vbase+t1), m->flex_vert0 + 3*(vbase+t0));
|
||||||
|
mju_sub3(edge2, m->flex_vert0 + 3*(vbase+t2), m->flex_vert0 + 3*(vbase+t0));
|
||||||
|
mji_cross(normal, edge1, edge2);
|
||||||
|
mju_normalize3(normal);
|
||||||
|
|
||||||
|
// compute rotation to Z
|
||||||
|
mju_quatZ2Vec(quat, normal);
|
||||||
|
mju_quat2Mat(mat, quat);
|
||||||
|
|
||||||
|
// compute edge vectors
|
||||||
|
mjtNum* edge_dx = mjSTACKALLOC(d, 3*m->flex_edgenum[f], mjtNum);
|
||||||
|
mjtNum* edge_dy = mjSTACKALLOC(d, 3*m->flex_edgenum[f], mjtNum);
|
||||||
|
for (int e=0; e < m->flex_edgenum[f]; e++) {
|
||||||
|
int v1 = m->flex_edge[2*(ebase+e)];
|
||||||
|
int v2 = m->flex_edge[2*(ebase+e)+1];
|
||||||
|
mjtNum dx3[3];
|
||||||
|
mju_sub3(dx3, m->flex_vert0 + 3*(vbase+v2), m->flex_vert0 + 3*(vbase+v1));
|
||||||
|
dx3[0] *= 2*m->flex_size[3*f+0];
|
||||||
|
dx3[1] *= 2*m->flex_size[3*f+1];
|
||||||
|
dx3[2] *= 2*m->flex_size[3*f+2];
|
||||||
|
mji_mulMatTVec3(edge_dx+3*e, mat, dx3);
|
||||||
|
if (mju_abs((edge_dx+3*e)[2]) > mjMINVAL) {
|
||||||
|
mjERROR("flex vertices are not in the same plane"); // SHOULD NOT OCCUR
|
||||||
|
}
|
||||||
|
mju_sub3(edge_dy+3*e, d->flexvert_xpos+3*(vbase+v2), d->flexvert_xpos+3*(vbase+v1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// build vertex adjacency list
|
||||||
|
int* v_edge_cnt = mjSTACKALLOC(d, nvert, int);
|
||||||
|
int* v_edge_adr = mjSTACKALLOC(d, nvert, int);
|
||||||
|
int* adj_edges = mjSTACKALLOC(d, 2*m->flex_edgenum[f], int);
|
||||||
|
mju_zeroInt(v_edge_cnt, nvert);
|
||||||
|
for (int e = 0; e < m->flex_edgenum[f]; ++e) {
|
||||||
|
v_edge_cnt[m->flex_edge[2*(ebase+e)+0]]++;
|
||||||
|
v_edge_cnt[m->flex_edge[2*(ebase+e)+1]]++;
|
||||||
|
}
|
||||||
|
int total_adj_edges = 0;
|
||||||
|
for (int v = 0; v < nvert; ++v) {
|
||||||
|
v_edge_adr[v] = total_adj_edges;
|
||||||
|
total_adj_edges += v_edge_cnt[v];
|
||||||
|
}
|
||||||
|
int* v_edge_fill = mjSTACKALLOC(d, nvert, int);
|
||||||
|
mju_zeroInt(v_edge_fill, nvert);
|
||||||
|
for (int e = 0; e < m->flex_edgenum[f]; ++e) {
|
||||||
|
int v1 = m->flex_edge[2*(ebase+e)+0];
|
||||||
|
int v2 = m->flex_edge[2*(ebase+e)+1];
|
||||||
|
adj_edges[v_edge_adr[v1] + v_edge_fill[v1]] = e;
|
||||||
|
v_edge_fill[v1]++;
|
||||||
|
adj_edges[v_edge_adr[v2] + v_edge_fill[v2]] = e;
|
||||||
|
v_edge_fill[v2]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mjtNum* F_vert = mjSTACKALLOC(d, 6*nvert, mjtNum);
|
||||||
|
mjtNum* Binv_vert = mjSTACKALLOC(d, 4*nvert, mjtNum);
|
||||||
|
|
||||||
|
// compute averaged Cauchy strain tensors for each vertex
|
||||||
|
for (int v=0; v < nvert; v++) {
|
||||||
|
mjtNum A[6] = {0}, B[4] = {0};
|
||||||
|
int k, edge_idx;
|
||||||
|
|
||||||
|
for (k=0; k<v_edge_cnt[v]; k++) {
|
||||||
|
edge_idx = adj_edges[v_edge_adr[v]+k];
|
||||||
|
mjtNum* dx = edge_dx+3*edge_idx;
|
||||||
|
mjtNum* dy = edge_dy+3*edge_idx;
|
||||||
|
|
||||||
|
// get mass of neighbor vertex
|
||||||
|
mjtNum weight = 1.0;
|
||||||
|
int v1 = m->flex_edge[2 * (ebase + edge_idx)];
|
||||||
|
int v2 = m->flex_edge[2 * (ebase + edge_idx) + 1];
|
||||||
|
int neighbor_v = (v == v1) ? v2 : v1;
|
||||||
|
int b_neighbor = m->flex_vertbodyid[vbase + neighbor_v];
|
||||||
|
if (b_neighbor >= 0) {
|
||||||
|
weight = m->body_mass[b_neighbor];
|
||||||
|
if (weight < mjMINVAL) weight = mjMINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// accumulate A += w * dy * dx', B += w * dx * dx'
|
||||||
|
for (int row=0; row < 3; row++) {
|
||||||
|
for (int col=0; col < 2; col++) {
|
||||||
|
A[2 * row + col] += weight * dy[row] * dx[col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int row=0; row < 2; row++) {
|
||||||
|
for (int col=0; col < 2; col++) {
|
||||||
|
B[2 * row + col] += weight * dx[row] * dx[col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vadr = vbase+v;
|
||||||
|
mjtNum* F = F_vert + 6*v;
|
||||||
|
mjtNum* Binv = Binv_vert + 4*v;
|
||||||
|
mjtNum cauchy[2][2];
|
||||||
|
|
||||||
|
// compute Binv = B^-1
|
||||||
|
mjtNum det = B[0]*B[3] - B[1]*B[2];
|
||||||
|
if (mju_abs(det) < mjMINVAL) {
|
||||||
|
mju_zero(Binv, 4);
|
||||||
|
} else {
|
||||||
|
mjtNum invdet = 1/det;
|
||||||
|
Binv[0] = B[3]*invdet;
|
||||||
|
Binv[1] = -B[1]*invdet;
|
||||||
|
Binv[2] = -B[2]*invdet;
|
||||||
|
Binv[3] = B[0]*invdet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute deformation gradient F = A * Binv
|
||||||
|
mju_mulMatMat(F, A, Binv, 3, 2, 2);
|
||||||
|
|
||||||
|
// compute Cauchy strain tensor F^T F
|
||||||
|
cauchy[0][0] = F[0]*F[0] + F[2]*F[2] + F[4]*F[4];
|
||||||
|
cauchy[0][1] = F[0]*F[1] + F[2]*F[3] + F[4]*F[5];
|
||||||
|
cauchy[1][0] = F[1]*F[0] + F[3]*F[2] + F[5]*F[4];
|
||||||
|
cauchy[1][1] = F[1]*F[1] + F[3]*F[3] + F[5]*F[5];
|
||||||
|
|
||||||
|
// compute tensor invariants
|
||||||
|
d->flexvert_length[2*vadr+0] = cauchy[0][0] + cauchy[1][1] - 2;
|
||||||
|
d->flexvert_length[2*vadr+1] = cauchy[0][0] * cauchy[1][1] -
|
||||||
|
cauchy[0][1] * cauchy[1][0] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1st pass: compute vrownnz
|
||||||
|
int* chain1 = mjSTACKALLOC(d, nv, int);
|
||||||
|
int* chain2 = mjSTACKALLOC(d, nv, int);
|
||||||
|
|
||||||
|
// determine start address for this flex
|
||||||
|
int v0_base = 2*vbase;
|
||||||
|
int current_adr = 0;
|
||||||
|
if (v0_base > 0) {
|
||||||
|
current_adr = vrowadr[v0_base - 1] + vrownnz[v0_base - 1];
|
||||||
|
}
|
||||||
|
vrowadr[v0_base] = current_adr;
|
||||||
|
|
||||||
|
for (int v=0; v<nvert; ++v) {
|
||||||
|
// clear buf_ind
|
||||||
|
mju_zeroInt(buf_ind, nv);
|
||||||
|
int current_nnz = 0;
|
||||||
|
for (int i=0; i<v_edge_cnt[v]; ++i) {
|
||||||
|
int e = adj_edges[v_edge_adr[v]+i];
|
||||||
|
int v1 = m->flex_edge[2*(ebase+e)];
|
||||||
|
int v2 = m->flex_edge[2*(ebase+e)+1];
|
||||||
|
|
||||||
|
// chains from edge e
|
||||||
|
int b1 = m->flex_vertbodyid[vbase+v1];
|
||||||
|
int b2 = m->flex_vertbodyid[vbase+v2];
|
||||||
|
int NV1 = mj_bodyChain(m, b1, chain1);
|
||||||
|
int NV2 = mj_bodyChain(m, b2, chain2);
|
||||||
|
|
||||||
|
for (int j=0; j<NV1; ++j) {
|
||||||
|
if (!buf_ind[chain1[j]]) {
|
||||||
|
buf_ind[chain1[j]] = 1;
|
||||||
|
current_nnz++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j=0; j<NV2; ++j) {
|
||||||
|
if (!buf_ind[chain2[j]]) {
|
||||||
|
buf_ind[chain2[j]] = 1;
|
||||||
|
current_nnz++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int row0 = 2*(vbase+v);
|
||||||
|
int row1 = 2*(vbase+v)+1;
|
||||||
|
vrownnz[row0] = vrownnz[row1] = current_nnz;
|
||||||
|
|
||||||
|
// set rowadr for next rows
|
||||||
|
vrowadr[row1] = vrowadr[row0] + current_nnz;
|
||||||
|
if (row1 + 1 < 2*m->nflexvert) {
|
||||||
|
vrowadr[row1+1] = vrowadr[row1] + current_nnz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill colind
|
||||||
|
int count = 0;
|
||||||
|
for (int j=0; j<nv; j++) {
|
||||||
|
if (buf_ind[j]) {
|
||||||
|
m->flexvert_J_colind[vrowadr[row0]+count] = j;
|
||||||
|
m->flexvert_J_colind[vrowadr[row1]+count] = j;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2nd pass: clear Jacobian and assemble vertex by vertex
|
||||||
|
mjtNum* J0_dense = mjSTACKALLOC(d, nv, mjtNum);
|
||||||
|
mjtNum* J1_dense = mjSTACKALLOC(d, nv, mjtNum);
|
||||||
|
mjtNum dI1dy1[3], dI1dy2[3], FB[6];
|
||||||
|
mjtNum dI2dy1[3], dI2dy2[3];
|
||||||
|
mjtNum cauchy[4], adj[4], Fadj[6], FadjBinv[6], dI2dy[3];
|
||||||
|
|
||||||
|
for (int v=0; v<nvert; v++) {
|
||||||
|
mju_zero(J0_dense, nv);
|
||||||
|
mju_zero(J1_dense, nv);
|
||||||
|
|
||||||
|
mjtNum* F = F_vert + 6*v;
|
||||||
|
mjtNum* Binv = Binv_vert + 4*v;
|
||||||
|
|
||||||
|
// precompute for I1
|
||||||
|
mju_mulMatMat(FB, F, Binv, 3, 2, 2);
|
||||||
|
|
||||||
|
// precompute for I2
|
||||||
|
cauchy[0] = F[0]*F[0] + F[2]*F[2] + F[4]*F[4]; // c00
|
||||||
|
cauchy[1] = F[0]*F[1] + F[2]*F[3] + F[4]*F[5]; // c01
|
||||||
|
cauchy[3] = F[1]*F[1] + F[3]*F[3] + F[5]*F[5]; // c11
|
||||||
|
adj[0] = cauchy[3];
|
||||||
|
adj[1] = -cauchy[1];
|
||||||
|
adj[2] = -cauchy[1];
|
||||||
|
adj[3] = cauchy[0];
|
||||||
|
mju_mulMatMat(Fadj, F, adj, 3, 2, 2);
|
||||||
|
mju_mulMatMat(FadjBinv, Fadj, Binv, 3, 2, 2);
|
||||||
|
|
||||||
|
for (int i=0; i<v_edge_cnt[v]; ++i) {
|
||||||
|
int e = adj_edges[v_edge_adr[v]+i];
|
||||||
|
int v1 = m->flex_edge[2*(ebase+e)];
|
||||||
|
int v2 = m->flex_edge[2*(ebase+e)+1];
|
||||||
|
|
||||||
|
// reuse precomputed edge vector
|
||||||
|
mjtNum* dx = edge_dx + 3 * e;
|
||||||
|
|
||||||
|
// get mass of neighbor vertex
|
||||||
|
mjtNum weight = 1.0;
|
||||||
|
int neighbor_v = (v == v1) ? v2 : v1;
|
||||||
|
int b_neighbor = m->flex_vertbodyid[vbase + neighbor_v];
|
||||||
|
if (b_neighbor >= 0) {
|
||||||
|
weight = m->body_mass[b_neighbor];
|
||||||
|
if (weight < mjMINVAL) weight = mjMINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dI1/dy1, dI1/dy2 (scaled by weight)
|
||||||
|
mju_mulMatVec(dI1dy1, FB, dx, 3, 2);
|
||||||
|
mju_scl3(dI1dy1, dI1dy1, -2 * weight);
|
||||||
|
mju_scl3(dI1dy2, dI1dy1, -1); // dI1dy2 = -dI1dy1
|
||||||
|
|
||||||
|
// dI2/dy1, dI2/dy2 (scaled by weight)
|
||||||
|
mju_mulMatVec(dI2dy, FadjBinv, dx, 3, 2);
|
||||||
|
mju_scl3(dI2dy1, dI2dy, -2 * weight);
|
||||||
|
mju_scl3(dI2dy2, dI2dy1, -1); // dI2dy2 = -dI2dy1
|
||||||
|
|
||||||
|
// get endpoint Jacobians
|
||||||
|
int b1 = m->flex_vertbodyid[vbase+v1];
|
||||||
|
int b2 = m->flex_vertbodyid[vbase+v2];
|
||||||
|
int NV1 = mj_bodyChain(m, b1, chain1);
|
||||||
|
mj_jacSparse(m, d, jac1, NULL, d->flexvert_xpos + 3*(vbase+v1), b1, NV1, chain1);
|
||||||
|
int NV2 = mj_bodyChain(m, b2, chain2);
|
||||||
|
mj_jacSparse(m, d, jac2, NULL, d->flexvert_xpos + 3*(vbase+v2), b2, NV2, chain2);
|
||||||
|
|
||||||
|
// accumulate dense Jacobians for vertex v
|
||||||
|
for (int j=0; j<NV1; j++) {
|
||||||
|
J0_dense[chain1[j]] += dI1dy1[0]*jac1[j] + dI1dy1[1]*jac1[j+NV1] + dI1dy1[2]*jac1[j+2*NV1];
|
||||||
|
}
|
||||||
|
for (int j=0; j<NV2; j++) {
|
||||||
|
J0_dense[chain2[j]] += dI1dy2[0]*jac2[j] + dI1dy2[1]*jac2[j+NV2] + dI1dy2[2]*jac2[j+2*NV2];
|
||||||
|
}
|
||||||
|
for (int j=0; j<NV1; j++) {
|
||||||
|
J1_dense[chain1[j]] += dI2dy1[0]*jac1[j] + dI2dy1[1]*jac1[j+NV1] + dI2dy1[2]*jac1[j+2*NV1];
|
||||||
|
}
|
||||||
|
for (int j=0; j<NV2; j++) {
|
||||||
|
J1_dense[chain2[j]] += dI2dy2[0]*jac2[j] + dI2dy2[1]*jac2[j+NV2] + dI2dy2[2]*jac2[j+2*NV2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy to sparse flexvert_J
|
||||||
|
int row0 = 2*(vbase+v);
|
||||||
|
int nnz0 = vrownnz[row0];
|
||||||
|
for (int j=0; j<nnz0; j++) {
|
||||||
|
d->flexvert_J[vrowadr[row0]+j] += J0_dense[m->flexvert_J_colind[vrowadr[row0]+j]];
|
||||||
|
}
|
||||||
|
int row1 = 2*(vbase+v)+1;
|
||||||
|
int nnz1 = vrownnz[row1];
|
||||||
|
for (int j = 0; j < nnz1; j++) {
|
||||||
|
d->flexvert_J[vrowadr[row1] + j] +=
|
||||||
|
J1_dense[m->flexvert_J_colind[vrowadr[row1] + j]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// mass scaling: scale constraint by sqrt(mass) to improve condition
|
||||||
|
// number
|
||||||
|
int b = m->flex_vertbodyid[vbase + v];
|
||||||
|
if (b >= 0) {
|
||||||
|
mjtNum mass = m->body_mass[b];
|
||||||
|
if (mass > mjMINVAL) {
|
||||||
|
mjtNum scale = mju_sqrt(mass);
|
||||||
|
d->flexvert_length[2 * (vbase + v) + 0] *= scale;
|
||||||
|
d->flexvert_length[2 * (vbase + v) + 1] *= scale;
|
||||||
|
|
||||||
|
nnz0 = vrownnz[row0];
|
||||||
|
for (int j = 0; j < nnz0; j++) {
|
||||||
|
d->flexvert_J[vrowadr[row0] + j] *= scale;
|
||||||
|
}
|
||||||
|
nnz1 = vrownnz[row1];
|
||||||
|
for (int j = 0; j < nnz1; j++) {
|
||||||
|
d->flexvert_J[vrowadr[row1] + j] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mj_freeStack(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mj_freeStack(d);
|
mj_freeStack(d);
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ void mj_makeModel(mjModel** dest,
|
|||||||
int nbvhstatic, int nbvhdynamic, int noct, int njnt, int ntree,
|
int nbvhstatic, int nbvhdynamic, int noct, int njnt, int ntree,
|
||||||
int nM, int nB, int nC, int nD, int ngeom, int nsite, int ncam, int nlight,
|
int nM, int nB, int nC, int nD, int ngeom, int nsite, int ncam, int nlight,
|
||||||
int nflex, int nflexnode, int nflexvert, int nflexedge, int nflexelem, int nflexelemdata,
|
int nflex, int nflexnode, int nflexvert, int nflexedge, int nflexelem, int nflexelemdata,
|
||||||
int nflexelemedge, int nflexshelldata, int nflexevpair, int nflextexcoord, int nJfe,
|
int nflexelemedge, int nflexshelldata, int nflexevpair, int nflextexcoord, int nJfe, int nJfv,
|
||||||
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface,
|
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface,
|
||||||
int nmeshgraph, int nmeshpoly, int nmeshpolyvert, int nmeshpolymap, int nskin, int nskinvert,
|
int nmeshgraph, int nmeshpoly, int nmeshpolyvert, int nmeshpolymap, int nskin, int nskinvert,
|
||||||
int nskintexvert, int nskinface,
|
int nskintexvert, int nskinface,
|
||||||
@@ -279,6 +279,7 @@ void mj_makeModel(mjModel** dest,
|
|||||||
m->nflexevpair = nflexevpair;
|
m->nflexevpair = nflexevpair;
|
||||||
m->nflextexcoord = nflextexcoord;
|
m->nflextexcoord = nflextexcoord;
|
||||||
m->nJfe = nJfe;
|
m->nJfe = nJfe;
|
||||||
|
m->nJfv = nJfv;
|
||||||
m->nmesh = nmesh;
|
m->nmesh = nmesh;
|
||||||
m->nmeshvert = nmeshvert;
|
m->nmeshvert = nmeshvert;
|
||||||
m->nmeshnormal = nmeshnormal;
|
m->nmeshnormal = nmeshnormal;
|
||||||
@@ -406,8 +407,8 @@ mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
|||||||
src->nbvhstatic, src->nbvhdynamic, src->noct, src->njnt, src->ntree,
|
src->nbvhstatic, src->nbvhdynamic, src->noct, src->njnt, src->ntree,
|
||||||
src->nM, src->nB, src->nC, src->nD, src->ngeom, src->nsite, src->ncam,
|
src->nM, src->nB, src->nC, src->nD, src->ngeom, src->nsite, src->ncam,
|
||||||
src->nlight, src->nflex, src->nflexnode, src->nflexvert, src->nflexedge,
|
src->nlight, src->nflex, src->nflexnode, src->nflexvert, src->nflexedge,
|
||||||
src->nflexelem, src->nflexelemdata, src->nflexelemedge,
|
src->nflexelem, src->nflexelemdata, src->nflexelemedge, src->nflexshelldata,
|
||||||
src->nflexshelldata, src->nflexevpair, src->nflextexcoord, src->nJfe, src->nmesh,
|
src->nflexevpair, src->nflextexcoord, src->nJfe, src->nJfv, src->nmesh,
|
||||||
src->nmeshvert, src->nmeshnormal, src->nmeshtexcoord, src->nmeshface,
|
src->nmeshvert, src->nmeshnormal, src->nmeshtexcoord, src->nmeshface,
|
||||||
src->nmeshgraph, src->nmeshpoly, src->nmeshpolyvert, src->nmeshpolymap,
|
src->nmeshgraph, src->nmeshpoly, src->nmeshpolyvert, src->nmeshpolymap,
|
||||||
src->nskin, src->nskinvert, src->nskintexvert, src->nskinface,
|
src->nskin, src->nskinvert, src->nskintexvert, src->nskinface,
|
||||||
@@ -598,7 +599,7 @@ mjModel* mj_loadModelBuffer(const void* buffer, int buffer_sz) {
|
|||||||
ints[49], ints[50], ints[51], ints[52], ints[53], ints[54], ints[55],
|
ints[49], ints[50], ints[51], ints[52], ints[53], ints[54], ints[55],
|
||||||
ints[56], ints[57], ints[58], ints[59], ints[60], ints[61], ints[62],
|
ints[56], ints[57], ints[58], ints[59], ints[60], ints[61], ints[62],
|
||||||
ints[63], ints[64], ints[65], ints[66], ints[67], ints[68], ints[69],
|
ints[63], ints[64], ints[65], ints[66], ints[67], ints[68], ints[69],
|
||||||
ints[70], ints[71], ints[72], ints[73], ints[74], ints[75]);
|
ints[70], ints[71], ints[72], ints[73], ints[74], ints[75], ints[76]);
|
||||||
|
|
||||||
// read mjModel mjtSize fields
|
// read mjModel mjtSize fields
|
||||||
mjtSize sizes[8];
|
mjtSize sizes[8];
|
||||||
|
|||||||
@@ -51,14 +51,15 @@ void mj_makeModel(mjModel** dest,
|
|||||||
int nq, int nv, int nu, int na, int nbody, int nbvh, int nbvhstatic, int nbvhdynamic, int noct,
|
int nq, int nv, int nu, int na, int nbody, int nbvh, int nbvhstatic, int nbvhdynamic, int noct,
|
||||||
int njnt, int ntree, int nM, int nB, int nC, int nD, int ngeom, int nsite, int ncam, int nlight,
|
int njnt, int ntree, int nM, int nB, int nC, int nD, int ngeom, int nsite, int ncam, int nlight,
|
||||||
int nflex, int nflexnode, int nflexvert, int nflexedge, int nflexelem, int nflexelemdata,
|
int nflex, int nflexnode, int nflexvert, int nflexedge, int nflexelem, int nflexelemdata,
|
||||||
int nJfe, int nflexelemedge, int nflexshelldata, int nflexevpair, int nflextexcoord, int nmesh,
|
int nflexelemedge, int nflexshelldata, int nflexevpair, int nflextexcoord, int nJfe, int nJfv,
|
||||||
int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface, int nmeshgraph, int nmeshpoly,
|
int nmesh, int nmeshvert, int nmeshnormal, int nmeshtexcoord, int nmeshface, int nmeshgraph,
|
||||||
int nmeshpolyvert, int nmeshpolymap, int nskin, int nskinvert, int nskintexvert, int nskinface,
|
int nmeshpoly, int nmeshpolyvert, int nmeshpolymap, int nskin, int nskinvert, int nskintexvert,
|
||||||
int nskinbone, int nskinbonevert, int nhfield, int nhfielddata, int ntex, int ntexdata,
|
int nskinface, int nskinbone, int nskinbonevert, int nhfield, int nhfielddata, int ntex,
|
||||||
int nmat, int npair, int nexclude, int neq, int ntendon, int nwrap, int nsensor, int nnumeric,
|
int ntexdata, int nmat, int npair, int nexclude, int neq, int ntendon, int nwrap, int nsensor,
|
||||||
int nnumericdata, int ntext, int ntextdata, int ntuple, int ntupledata, int nkey, int nmocap,
|
int nnumeric, int nnumericdata, int ntext, int ntextdata, int ntuple, int ntupledata, int nkey,
|
||||||
int nplugin, int npluginattr, int nuser_body, int nuser_jnt, int nuser_geom, int nuser_site,
|
int nmocap, int nplugin, int npluginattr, int nuser_body, int nuser_jnt, int nuser_geom,
|
||||||
int nuser_cam, int nuser_tendon, int nuser_actuator, int nuser_sensor, int nnames, int npaths);
|
int nuser_site, int nuser_cam, int nuser_tendon, int nuser_actuator, int nuser_sensor,
|
||||||
|
int nnames, int npaths);
|
||||||
|
|
||||||
// copy mjModel; allocate new if dest is NULL
|
// copy mjModel; allocate new if dest is NULL
|
||||||
MJAPI mjModel* mj_copyModel(mjModel* dest, const mjModel* src);
|
MJAPI mjModel* mj_copyModel(mjModel* dest, const mjModel* src);
|
||||||
|
|||||||
@@ -4392,10 +4392,16 @@ void mjCFlex::Compile(const mjVFS* vfs) {
|
|||||||
// compute bounding box coordinates
|
// compute bounding box coordinates
|
||||||
vert0_.assign(3*nvert, 0);
|
vert0_.assign(3*nvert, 0);
|
||||||
const mjtNum* bvh = tree.Bvh().data();
|
const mjtNum* bvh = tree.Bvh().data();
|
||||||
|
size[0] = bvh[3] - radius;
|
||||||
|
size[1] = bvh[4] - radius;
|
||||||
|
size[2] = bvh[5] - radius;
|
||||||
for (int j=0; j < nvert; j++) {
|
for (int j=0; j < nvert; j++) {
|
||||||
for (int k=0; k < 3; k++) {
|
for (int k=0; k < 3; k++) {
|
||||||
double size = 2*(bvh[k+3] - radius);
|
if (size[k] > mjMINVAL) {
|
||||||
vert0_[3*j+k] = (vertxpos[3*j+k] - bvh[k]) / size + 0.5;
|
vert0_[3*j+k] = (vertxpos[3*j+k] - bvh[k]) / (2*size[k]) + 0.5;
|
||||||
|
} else {
|
||||||
|
vert0_[3*j+k] = 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-1
@@ -1155,6 +1155,7 @@ void mjCModel::Clear() {
|
|||||||
nflexevpair = 0;
|
nflexevpair = 0;
|
||||||
nflextexcoord = 0;
|
nflextexcoord = 0;
|
||||||
nJfe = 0;
|
nJfe = 0;
|
||||||
|
nJfv = 0;
|
||||||
nmeshvert = 0;
|
nmeshvert = 0;
|
||||||
nmeshnormal = 0;
|
nmeshnormal = 0;
|
||||||
nmeshtexcoord = 0;
|
nmeshtexcoord = 0;
|
||||||
@@ -2166,6 +2167,31 @@ void mjCModel::SetSizes() {
|
|||||||
nJfe += b->dofnum;
|
nJfe += b->dofnum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compute nJfv
|
||||||
|
std::vector<std::vector<int>> adj(flexes_[i]->nvert);
|
||||||
|
for (const auto& edge : flexes_[i]->edge) {
|
||||||
|
adj[edge.first].push_back(edge.second);
|
||||||
|
adj[edge.second].push_back(edge.first);
|
||||||
|
}
|
||||||
|
for (int j=0; j < flexes_[i]->nvert; j++) {
|
||||||
|
std::unordered_set<int> vert_bodies;
|
||||||
|
vert_bodies.insert(flexes_[i]->vertbodyid[j]);
|
||||||
|
for (int neighbor : adj[j]) {
|
||||||
|
vert_bodies.insert(flexes_[i]->vertbodyid[neighbor]);
|
||||||
|
}
|
||||||
|
std::unordered_set<mjCBody*> bodies_in_jac;
|
||||||
|
for (int body_id : vert_bodies) {
|
||||||
|
mjCBody* b = bodies_[body_id];
|
||||||
|
while (b) {
|
||||||
|
bodies_in_jac.insert(b);
|
||||||
|
b = b->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (mjCBody* b : bodies_in_jac) {
|
||||||
|
nJfv += b->dofnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mesh counts
|
// mesh counts
|
||||||
@@ -3288,6 +3314,7 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
mjuu_copyvec(m->flex_solref + mjNREF * i, pfl->solref, mjNREF);
|
mjuu_copyvec(m->flex_solref + mjNREF * i, pfl->solref, mjNREF);
|
||||||
mjuu_copyvec(m->flex_solimp + mjNIMP * i, pfl->solimp, mjNIMP);
|
mjuu_copyvec(m->flex_solimp + mjNIMP * i, pfl->solimp, mjNIMP);
|
||||||
m->flex_radius[i] = (mjtNum)pfl->radius;
|
m->flex_radius[i] = (mjtNum)pfl->radius;
|
||||||
|
mjuu_copyvec(m->flex_size + 3 * i, pfl->size, 3);
|
||||||
mjuu_copyvec(m->flex_friction + 3 * i, pfl->friction, 3);
|
mjuu_copyvec(m->flex_friction + 3 * i, pfl->friction, 3);
|
||||||
m->flex_margin[i] = (mjtNum)pfl->margin;
|
m->flex_margin[i] = (mjtNum)pfl->margin;
|
||||||
m->flex_gap[i] = (mjtNum)pfl->gap;
|
m->flex_gap[i] = (mjtNum)pfl->gap;
|
||||||
@@ -3363,6 +3390,7 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
m->flex_edgeequality[i] = 1;
|
m->flex_edgeequality[i] = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO: support flex_edgeequality = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy bvh data (flex aabb computed dynamically in mjData)
|
// copy bvh data (flex aabb computed dynamically in mjData)
|
||||||
@@ -4856,7 +4884,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
mj_makeModel(&m,
|
mj_makeModel(&m,
|
||||||
nq, nv, nu, na, nbody, nbvh, nbvhstatic, nbvhdynamic, noct, njnt, ntree, nM, nB, nC,
|
nq, nv, nu, na, nbody, nbvh, nbvhstatic, nbvhdynamic, noct, njnt, ntree, nM, nB, nC,
|
||||||
nD, ngeom, nsite, ncam, nlight, nflex, nflexnode, nflexvert, nflexedge, nflexelem,
|
nD, ngeom, nsite, ncam, nlight, nflex, nflexnode, nflexvert, nflexedge, nflexelem,
|
||||||
nflexelemdata, nflexelemedge, nflexshelldata, nflexevpair, nflextexcoord, nJfe,
|
nflexelemdata, nflexelemedge, nflexshelldata, nflexevpair, nflextexcoord, nJfe, nJfv,
|
||||||
nmesh, nmeshvert, nmeshnormal, nmeshtexcoord, nmeshface, nmeshgraph, nmeshpoly,
|
nmesh, nmeshvert, nmeshnormal, nmeshtexcoord, nmeshface, nmeshgraph, nmeshpoly,
|
||||||
nmeshpolyvert, nmeshpolymap, nskin, nskinvert, nskintexvert, nskinface, nskinbone,
|
nmeshpolyvert, nmeshpolymap, nskin, nskinvert, nskintexvert, nskinface, nskinbone,
|
||||||
nskinbonevert, nhfield, nhfielddata, ntex, ntexdata, nmat, npair, nexclude,
|
nskinbonevert, nhfield, nhfielddata, ntex, ntexdata, nmat, npair, nexclude,
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ class mjCModel_ : public mjsElement {
|
|||||||
int nflexshelldata; // number of shell fragment vertex ids in all flexes
|
int nflexshelldata; // number of shell fragment vertex ids in all flexes
|
||||||
int nflexevpair; // number of element-vertex pairs in all flexes
|
int nflexevpair; // number of element-vertex pairs in all flexes
|
||||||
int nflextexcoord; // number of vertex texture coordinates in all flexes
|
int nflextexcoord; // number of vertex texture coordinates in all flexes
|
||||||
int nJfe; // number of non-zeros in sparse flex constraint Jacobian
|
int nJfe; // number of non-zeros in sparse flex edge constraint Jacobian
|
||||||
|
int nJfv; // number of non-zeros in sparse flex vertex constraint Jacobian
|
||||||
int nmeshvert; // number of vertices in all meshes
|
int nmeshvert; // number of vertices in all meshes
|
||||||
int nmeshnormal; // number of normals in all meshes
|
int nmeshnormal; // number of normals in all meshes
|
||||||
int nmeshtexcoord; // number of texture coordinates in all meshes
|
int nmeshtexcoord; // number of texture coordinates in all meshes
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ using ::testing::Eq;
|
|||||||
using ::testing::Pointwise;
|
using ::testing::Pointwise;
|
||||||
using ::testing::DoubleNear;
|
using ::testing::DoubleNear;
|
||||||
using ::testing::NotNull;
|
using ::testing::NotNull;
|
||||||
|
using ::testing::Not;
|
||||||
using CoreSmoothTest = MujocoTest;
|
using CoreSmoothTest = MujocoTest;
|
||||||
|
|
||||||
|
|
||||||
@@ -876,5 +877,205 @@ TEST_F(CoreSmoothTest, FactorIs) {
|
|||||||
mj_deleteModel(m);
|
mj_deleteModel(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CoreSmoothTest, FlexVertLengthScaling) {
|
||||||
|
constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<option jacobian="sparse"/>
|
||||||
|
<worldbody>
|
||||||
|
<flexcomp name="g" type="grid" count="3 3 1" spacing=".5 .5 .5" dim="2" radius=".05">
|
||||||
|
<edge equality="true"/>
|
||||||
|
</flexcomp>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
char error[1024];
|
||||||
|
mjModel* m = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(m, NotNull()) << error;
|
||||||
|
mjData* d = mj_makeData(m);
|
||||||
|
|
||||||
|
// check that nJfv is correct:
|
||||||
|
// corner vertices: 2 * (1+3) * 3 + 2 * (1+2) * 3 = 42
|
||||||
|
// edge vertices: 4 * (1+4) * 3 = 60
|
||||||
|
// center vertex: 1 * (1+6) * 3 = 21
|
||||||
|
// nJfv = 42 + 60 + 21 = 123
|
||||||
|
EXPECT_EQ(m->nJfv, 123);
|
||||||
|
|
||||||
|
// Set edge equality to 2
|
||||||
|
m->flex_edgeequality[0] = 2;
|
||||||
|
|
||||||
|
// Run kinematics to populate xpos/xmat initially
|
||||||
|
mj_fwdKinematics(m, d);
|
||||||
|
|
||||||
|
// Check invariants for scale=1
|
||||||
|
// The constraints should be satisfied
|
||||||
|
int nvert = m->flex_vertnum[0];
|
||||||
|
ASSERT_EQ(nvert, 9);
|
||||||
|
for (int i=0; i < nvert; i++) {
|
||||||
|
EXPECT_NEAR(d->flexvert_length[2*i+0], 0.0, 1e-5);
|
||||||
|
EXPECT_NEAR(d->flexvert_length[2*i+1], 0.0, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set qvel to rigid rotation
|
||||||
|
ASSERT_EQ(m->nv, 3*nvert);
|
||||||
|
mju_zero(d->qvel, m->nv);
|
||||||
|
for (int i=0; i < nvert; i++) {
|
||||||
|
const mjtNum* p = d->xpos + 3*m->flex_vertbodyid[i];
|
||||||
|
d->qvel[3*i+0] = -p[1];
|
||||||
|
d->qvel[3*i+1] = p[0];
|
||||||
|
d->qvel[3*i+2] = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that Jacobian times velocity is zero for rigid body motion
|
||||||
|
vector<mjtNum> Jv(2*nvert, 0);
|
||||||
|
for (int i=0; i < 2*nvert; i++) {
|
||||||
|
int row_start = m->flexvert_J_rowadr[i];
|
||||||
|
int row_nnz = m->flexvert_J_rownnz[i];
|
||||||
|
for (int j=0; j < row_nnz; j++) {
|
||||||
|
Jv[i] += d->flexvert_J[row_start + j] *
|
||||||
|
d->qvel[m->flexvert_J_colind[row_start + j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_THAT(Jv, Each(DoubleNear(0.0, 1e-9)));
|
||||||
|
|
||||||
|
// check sparsity pattern
|
||||||
|
int corners[] = {0, 2, 6, 8};
|
||||||
|
int edges[] = {1, 3, 5, 7};
|
||||||
|
int center[] = {4};
|
||||||
|
for (int i : corners) {
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+0], (i == 0 || i == 8) ? 12 : 9);
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+1], (i == 0 || i == 8) ? 12 : 9);
|
||||||
|
}
|
||||||
|
for (int i : edges) {
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+0], 15);
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+1], 15);
|
||||||
|
}
|
||||||
|
for (int i : center) {
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+0], 21);
|
||||||
|
EXPECT_EQ(m->flexvert_J_rownnz[2*i+1], 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check rowadr
|
||||||
|
EXPECT_EQ(m->flexvert_J_rowadr[0], 0);
|
||||||
|
for (int i=1; i < 2*nvert; i++) {
|
||||||
|
EXPECT_EQ(m->flexvert_J_rowadr[i],
|
||||||
|
m->flexvert_J_rowadr[i-1] + m->flexvert_J_rownnz[i-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that colind are sorted and unique
|
||||||
|
int nnzJ = 0;
|
||||||
|
for (int i = 0; i < 2*nvert; i++) {
|
||||||
|
nnzJ += m->flexvert_J_rownnz[i];
|
||||||
|
}
|
||||||
|
EXPECT_EQ(nnzJ, 2*m->nJfv);
|
||||||
|
for (int i=0; i < 2*nvert; i++) {
|
||||||
|
int row_start = m->flexvert_J_rowadr[i];
|
||||||
|
int row_nnz = m->flexvert_J_rownnz[i];
|
||||||
|
for (int j=0; j < row_nnz-1; j++) {
|
||||||
|
EXPECT_LE(m->flexvert_J_colind[row_start+j],
|
||||||
|
m->flexvert_J_colind[row_start+j+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finite-difference check for flexvert_J
|
||||||
|
auto fd_check = [&](double tolerance) {
|
||||||
|
std::vector<mjtNum> qpos0(m->nq);
|
||||||
|
mju_copy(qpos0.data(), d->qpos, m->nq);
|
||||||
|
mj_kinematics(m, d);
|
||||||
|
mj_flex(m, d);
|
||||||
|
|
||||||
|
mjtNum eps = 1e-7;
|
||||||
|
int nflexvert = m->flex_vertnum[0];
|
||||||
|
std::vector<mjtNum> jac_fd(2 * nflexvert * m->nv);
|
||||||
|
std::vector<mjtNum> qpos_backup(m->nq);
|
||||||
|
mju_copy(qpos_backup.data(), d->qpos, m->nq);
|
||||||
|
|
||||||
|
for (int i=0; i < m->nv; ++i) {
|
||||||
|
std::vector<mjtNum> qvel(m->nv, 0);
|
||||||
|
qvel[i] = 1.0;
|
||||||
|
|
||||||
|
// plus
|
||||||
|
mju_copy(d->qpos, qpos_backup.data(), m->nq);
|
||||||
|
mj_integratePos(m, d->qpos, qvel.data(), eps);
|
||||||
|
mj_kinematics(m, d);
|
||||||
|
mj_flex(m, d);
|
||||||
|
std::vector<mjtNum> L_plus(2 * nflexvert);
|
||||||
|
for (int e = 0; e < 2 * nflexvert; ++e) {
|
||||||
|
L_plus[e] = d->flexvert_length[e];
|
||||||
|
}
|
||||||
|
|
||||||
|
// minus
|
||||||
|
mju_copy(d->qpos, qpos_backup.data(), m->nq);
|
||||||
|
mj_integratePos(m, d->qpos, qvel.data(), -eps);
|
||||||
|
mj_kinematics(m, d);
|
||||||
|
mj_flex(m, d);
|
||||||
|
std::vector<mjtNum> L_minus(2 * nflexvert);
|
||||||
|
for (int e = 0; e < 2 * nflexvert; ++e) {
|
||||||
|
L_minus[e] = d->flexvert_length[e];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int e = 0; e < 2 * nflexvert; ++e) {
|
||||||
|
jac_fd[e*m->nv + i] = (L_plus[e] - L_minus[e]) / (2*eps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mju_copy(d->qpos, qpos_backup.data(), m->nq);
|
||||||
|
mj_kinematics(m, d);
|
||||||
|
mj_flex(m, d);
|
||||||
|
|
||||||
|
// Compare with analytic
|
||||||
|
std::vector<mjtNum> jac_analytic(2 * nflexvert * m->nv);
|
||||||
|
mju_zero(jac_analytic.data(), 2 * nflexvert * m->nv);
|
||||||
|
for (int e = 0; e < 2 * nflexvert; ++e) {
|
||||||
|
int row_start = m->flexvert_J_rowadr[e];
|
||||||
|
int row_nnz = m->flexvert_J_rownnz[e];
|
||||||
|
for (int i = 0; i < row_nnz; ++i) {
|
||||||
|
jac_analytic[e*m->nv + m->flexvert_J_colind[row_start+i]] =
|
||||||
|
d->flexvert_J[row_start+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_THAT(jac_analytic, Not(Each(Eq(0))));
|
||||||
|
EXPECT_THAT(jac_analytic, Pointwise(DoubleNear(tolerance), jac_fd));
|
||||||
|
|
||||||
|
mju_copy(d->qpos, qpos0.data(), m->nq);
|
||||||
|
mj_kinematics(m, d);
|
||||||
|
mj_flex(m, d);
|
||||||
|
};
|
||||||
|
|
||||||
|
fd_check(5e-5);
|
||||||
|
|
||||||
|
// Set qpos to put flex in scale=2 configuration.
|
||||||
|
for (int i=0; i < nvert; i++) {
|
||||||
|
d->qpos[3*i+0] = d->xpos[3*(i+1)+0];
|
||||||
|
d->qpos[3*i+1] = d->xpos[3*(i+1)+1];
|
||||||
|
d->qpos[3*i+2] = d->xpos[3*(i+1)+2];
|
||||||
|
}
|
||||||
|
mj_fwdKinematics(m, d);
|
||||||
|
|
||||||
|
// Get mass scaling factor
|
||||||
|
mjtNum scale = 1.0;
|
||||||
|
int b = m->flex_vertbodyid[0];
|
||||||
|
if (b >= 0 && m->body_mass[b] > mjMINVAL) {
|
||||||
|
scale = mju_sqrt(m->body_mass[b]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check invariants for scale=2
|
||||||
|
// F should be [2, 2]. C = F'F = 4I.
|
||||||
|
// Strain E = C - I = 3I.
|
||||||
|
// Invariant 0: Trace(E) = 3 + 3 = 6
|
||||||
|
// Invariant 1: Det(C) - 1 = 4 * 4 - 1 = 15
|
||||||
|
for (int i=0; i < nvert; i++) {
|
||||||
|
EXPECT_NEAR(d->flexvert_length[2 * i + 0], 6.0 * scale, 1e-5);
|
||||||
|
EXPECT_NEAR(d->flexvert_length[2 * i + 1], 15.0 * scale, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perturb z-positions so configuration is not flat
|
||||||
|
for (int i=0; i < nvert; i++) {
|
||||||
|
d->qpos[3*i+2] += 0.01 * (i%2 ? 1 : -1);
|
||||||
|
}
|
||||||
|
fd_check(5e-5);
|
||||||
|
|
||||||
|
mj_deleteData(d);
|
||||||
|
mj_deleteModel(m);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
@@ -4983,6 +4983,8 @@ public unsafe struct mjData_ {
|
|||||||
public double* flexelem_aabb;
|
public double* flexelem_aabb;
|
||||||
public double* flexedge_J;
|
public double* flexedge_J;
|
||||||
public double* flexedge_length;
|
public double* flexedge_length;
|
||||||
|
public double* flexvert_J;
|
||||||
|
public double* flexvert_length;
|
||||||
public double* bvh_aabb_dyn;
|
public double* bvh_aabb_dyn;
|
||||||
public int* ten_wrapadr;
|
public int* ten_wrapadr;
|
||||||
public int* ten_wrapnum;
|
public int* ten_wrapnum;
|
||||||
@@ -5314,6 +5316,7 @@ public unsafe struct mjModel_ {
|
|||||||
public int nflexevpair;
|
public int nflexevpair;
|
||||||
public int nflextexcoord;
|
public int nflextexcoord;
|
||||||
public int nJfe;
|
public int nJfe;
|
||||||
|
public int nJfv;
|
||||||
public int nmesh;
|
public int nmesh;
|
||||||
public int nmeshvert;
|
public int nmeshvert;
|
||||||
public int nmeshnormal;
|
public int nmeshnormal;
|
||||||
@@ -5572,12 +5575,13 @@ public unsafe struct mjModel_ {
|
|||||||
public double* flexedge_length0;
|
public double* flexedge_length0;
|
||||||
public double* flexedge_invweight0;
|
public double* flexedge_invweight0;
|
||||||
public double* flex_radius;
|
public double* flex_radius;
|
||||||
|
public double* flex_size;
|
||||||
public double* flex_stiffness;
|
public double* flex_stiffness;
|
||||||
public double* flex_bending;
|
public double* flex_bending;
|
||||||
public double* flex_damping;
|
public double* flex_damping;
|
||||||
public double* flex_edgestiffness;
|
public double* flex_edgestiffness;
|
||||||
public double* flex_edgedamping;
|
public double* flex_edgedamping;
|
||||||
public byte* flex_edgeequality;
|
public int* flex_edgeequality;
|
||||||
public byte* flex_rigid;
|
public byte* flex_rigid;
|
||||||
public byte* flexedge_rigid;
|
public byte* flexedge_rigid;
|
||||||
public byte* flex_centered;
|
public byte* flex_centered;
|
||||||
@@ -5587,6 +5591,9 @@ public unsafe struct mjModel_ {
|
|||||||
public int* flexedge_J_rownnz;
|
public int* flexedge_J_rownnz;
|
||||||
public int* flexedge_J_rowadr;
|
public int* flexedge_J_rowadr;
|
||||||
public int* flexedge_J_colind;
|
public int* flexedge_J_colind;
|
||||||
|
public int* flexvert_J_rownnz;
|
||||||
|
public int* flexvert_J_rowadr;
|
||||||
|
public int* flexvert_J_colind;
|
||||||
public float* flex_rgba;
|
public float* flex_rgba;
|
||||||
public float* flex_texcoord;
|
public float* flex_texcoord;
|
||||||
public int* mesh_vertadr;
|
public int* mesh_vertadr;
|
||||||
|
|||||||
@@ -2157,6 +2157,9 @@ struct MjsFlex {
|
|||||||
void set_radius(double value) {
|
void set_radius(double value) {
|
||||||
ptr_->radius = value;
|
ptr_->radius = value;
|
||||||
}
|
}
|
||||||
|
emscripten::val size() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(3, ptr_->size));
|
||||||
|
}
|
||||||
mjtByte internal() const {
|
mjtByte internal() const {
|
||||||
return ptr_->internal;
|
return ptr_->internal;
|
||||||
}
|
}
|
||||||
@@ -3585,6 +3588,12 @@ struct MjModel {
|
|||||||
void set_nJfe(int value) {
|
void set_nJfe(int value) {
|
||||||
ptr_->nJfe = value;
|
ptr_->nJfe = value;
|
||||||
}
|
}
|
||||||
|
int nJfv() const {
|
||||||
|
return ptr_->nJfv;
|
||||||
|
}
|
||||||
|
void set_nJfv(int value) {
|
||||||
|
ptr_->nJfv = value;
|
||||||
|
}
|
||||||
int nmesh() const {
|
int nmesh() const {
|
||||||
return ptr_->nmesh;
|
return ptr_->nmesh;
|
||||||
}
|
}
|
||||||
@@ -4521,6 +4530,9 @@ struct MjModel {
|
|||||||
emscripten::val flex_radius() const {
|
emscripten::val flex_radius() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(ptr_->nflex, ptr_->flex_radius));
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflex, ptr_->flex_radius));
|
||||||
}
|
}
|
||||||
|
emscripten::val flex_size() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflex * 3, ptr_->flex_size));
|
||||||
|
}
|
||||||
emscripten::val flex_stiffness() const {
|
emscripten::val flex_stiffness() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(ptr_->nflexelem * 21, ptr_->flex_stiffness));
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflexelem * 21, ptr_->flex_stiffness));
|
||||||
}
|
}
|
||||||
@@ -4566,6 +4578,15 @@ struct MjModel {
|
|||||||
emscripten::val flexedge_J_colind() const {
|
emscripten::val flexedge_J_colind() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(ptr_->nJfe, ptr_->flexedge_J_colind));
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nJfe, ptr_->flexedge_J_colind));
|
||||||
}
|
}
|
||||||
|
emscripten::val flexvert_J_rownnz() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflexvert * 2, ptr_->flexvert_J_rownnz));
|
||||||
|
}
|
||||||
|
emscripten::val flexvert_J_rowadr() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflexvert * 2, ptr_->flexvert_J_rowadr));
|
||||||
|
}
|
||||||
|
emscripten::val flexvert_J_colind() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nJfv * 2, ptr_->flexvert_J_colind));
|
||||||
|
}
|
||||||
emscripten::val flex_rgba() const {
|
emscripten::val flex_rgba() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(ptr_->nflex * 4, ptr_->flex_rgba));
|
return emscripten::val(emscripten::typed_memory_view(ptr_->nflex * 4, ptr_->flex_rgba));
|
||||||
}
|
}
|
||||||
@@ -6306,6 +6327,12 @@ struct MjData {
|
|||||||
emscripten::val flexedge_length() const {
|
emscripten::val flexedge_length() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(model->nflexedge, ptr_->flexedge_length));
|
return emscripten::val(emscripten::typed_memory_view(model->nflexedge, ptr_->flexedge_length));
|
||||||
}
|
}
|
||||||
|
emscripten::val flexvert_J() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(model->nJfv * 2, ptr_->flexvert_J));
|
||||||
|
}
|
||||||
|
emscripten::val flexvert_length() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(model->nflexvert * 2, ptr_->flexvert_length));
|
||||||
|
}
|
||||||
emscripten::val bvh_aabb_dyn() const {
|
emscripten::val bvh_aabb_dyn() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(model->nbvhdynamic * 6, ptr_->bvh_aabb_dyn));
|
return emscripten::val(emscripten::typed_memory_view(model->nbvhdynamic * 6, ptr_->bvh_aabb_dyn));
|
||||||
}
|
}
|
||||||
@@ -11019,6 +11046,8 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("flexedge_length", &MjData::flexedge_length)
|
.property("flexedge_length", &MjData::flexedge_length)
|
||||||
.property("flexedge_velocity", &MjData::flexedge_velocity)
|
.property("flexedge_velocity", &MjData::flexedge_velocity)
|
||||||
.property("flexelem_aabb", &MjData::flexelem_aabb)
|
.property("flexelem_aabb", &MjData::flexelem_aabb)
|
||||||
|
.property("flexvert_J", &MjData::flexvert_J)
|
||||||
|
.property("flexvert_length", &MjData::flexvert_length)
|
||||||
.property("flexvert_xpos", &MjData::flexvert_xpos)
|
.property("flexvert_xpos", &MjData::flexvert_xpos)
|
||||||
.property("geom_xmat", &MjData::geom_xmat)
|
.property("geom_xmat", &MjData::geom_xmat)
|
||||||
.property("geom_xpos", &MjData::geom_xpos)
|
.property("geom_xpos", &MjData::geom_xpos)
|
||||||
@@ -11334,6 +11363,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("flex_shell", &MjModel::flex_shell)
|
.property("flex_shell", &MjModel::flex_shell)
|
||||||
.property("flex_shelldataadr", &MjModel::flex_shelldataadr)
|
.property("flex_shelldataadr", &MjModel::flex_shelldataadr)
|
||||||
.property("flex_shellnum", &MjModel::flex_shellnum)
|
.property("flex_shellnum", &MjModel::flex_shellnum)
|
||||||
|
.property("flex_size", &MjModel::flex_size)
|
||||||
.property("flex_solimp", &MjModel::flex_solimp)
|
.property("flex_solimp", &MjModel::flex_solimp)
|
||||||
.property("flex_solmix", &MjModel::flex_solmix)
|
.property("flex_solmix", &MjModel::flex_solmix)
|
||||||
.property("flex_solref", &MjModel::flex_solref)
|
.property("flex_solref", &MjModel::flex_solref)
|
||||||
@@ -11351,6 +11381,9 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("flexedge_invweight0", &MjModel::flexedge_invweight0)
|
.property("flexedge_invweight0", &MjModel::flexedge_invweight0)
|
||||||
.property("flexedge_length0", &MjModel::flexedge_length0)
|
.property("flexedge_length0", &MjModel::flexedge_length0)
|
||||||
.property("flexedge_rigid", &MjModel::flexedge_rigid)
|
.property("flexedge_rigid", &MjModel::flexedge_rigid)
|
||||||
|
.property("flexvert_J_colind", &MjModel::flexvert_J_colind)
|
||||||
|
.property("flexvert_J_rowadr", &MjModel::flexvert_J_rowadr)
|
||||||
|
.property("flexvert_J_rownnz", &MjModel::flexvert_J_rownnz)
|
||||||
.property("geom_aabb", &MjModel::geom_aabb)
|
.property("geom_aabb", &MjModel::geom_aabb)
|
||||||
.property("geom_bodyid", &MjModel::geom_bodyid)
|
.property("geom_bodyid", &MjModel::geom_bodyid)
|
||||||
.property("geom_conaffinity", &MjModel::geom_conaffinity)
|
.property("geom_conaffinity", &MjModel::geom_conaffinity)
|
||||||
@@ -11477,6 +11510,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("nC", &MjModel::nC, &MjModel::set_nC, reference())
|
.property("nC", &MjModel::nC, &MjModel::set_nC, reference())
|
||||||
.property("nD", &MjModel::nD, &MjModel::set_nD, reference())
|
.property("nD", &MjModel::nD, &MjModel::set_nD, reference())
|
||||||
.property("nJfe", &MjModel::nJfe, &MjModel::set_nJfe, reference())
|
.property("nJfe", &MjModel::nJfe, &MjModel::set_nJfe, reference())
|
||||||
|
.property("nJfv", &MjModel::nJfv, &MjModel::set_nJfv, reference())
|
||||||
.property("nJmom", &MjModel::nJmom, &MjModel::set_nJmom, reference())
|
.property("nJmom", &MjModel::nJmom, &MjModel::set_nJmom, reference())
|
||||||
.property("nM", &MjModel::nM, &MjModel::set_nM, reference())
|
.property("nM", &MjModel::nM, &MjModel::set_nM, reference())
|
||||||
.property("na", &MjModel::na, &MjModel::set_na, reference())
|
.property("na", &MjModel::na, &MjModel::set_na, reference())
|
||||||
@@ -12048,6 +12082,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("radius", &MjsFlex::radius, &MjsFlex::set_radius, reference())
|
.property("radius", &MjsFlex::radius, &MjsFlex::set_radius, reference())
|
||||||
.property("rgba", &MjsFlex::rgba)
|
.property("rgba", &MjsFlex::rgba)
|
||||||
.property("selfcollide", &MjsFlex::selfcollide, &MjsFlex::set_selfcollide, reference())
|
.property("selfcollide", &MjsFlex::selfcollide, &MjsFlex::set_selfcollide, reference())
|
||||||
|
.property("size", &MjsFlex::size)
|
||||||
.property("solimp", &MjsFlex::solimp)
|
.property("solimp", &MjsFlex::solimp)
|
||||||
.property("solmix", &MjsFlex::solmix, &MjsFlex::set_solmix, reference())
|
.property("solmix", &MjsFlex::solmix, &MjsFlex::set_solmix, reference())
|
||||||
.property("solref", &MjsFlex::solref)
|
.property("solref", &MjsFlex::solref)
|
||||||
|
|||||||
Reference in New Issue
Block a user