Skip to content

Commit 2d69610

Browse files
quaglacopybara-github
authored andcommitted
Use the geom frame for SDF collisions.
Also disables mesh reorientation for meshes autogenerated with marching cubes from analytic SDFs. PiperOrigin-RevId: 781487195 Change-Id: I36b66384f240a764823c489f78f22ba9fe32f15f
1 parent 7e57a6b commit 2d69610

File tree

4 files changed

+52
-79
lines changed

4 files changed

+52
-79
lines changed

src/engine/engine_collision_sdf.c

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -480,24 +480,6 @@ static void mapPose(const mjtNum xpos1[3], const mjtNum xquat1[4],
480480
mju_quat2Mat(mat12, quat12);
481481
}
482482

483-
// subtract mesh position from sdf transformation
484-
static void undoTransformation(const mjModel* m, const mjData* d, int g,
485-
mjtNum sdf_xpos[3], mjtNum sdf_quat[4]) {
486-
mjtNum* xpos = d->geom_xpos + 3 * g;
487-
mjtNum* xmat = d->geom_xmat + 9 * g;
488-
if (m->geom_type[g] == mjGEOM_MESH || m->geom_type[g] == mjGEOM_SDF) {
489-
mjtNum negpos[3], negquat[4], xquat[4];
490-
mjtNum* pos = m->mesh_pos + 3 * m->geom_dataid[g];
491-
mjtNum* quat = m->mesh_quat + 4 * m->geom_dataid[g];
492-
mju_mat2Quat(xquat, xmat);
493-
mju_negPose(negpos, negquat, pos, quat);
494-
mju_mulPose(sdf_xpos, sdf_quat, xpos, xquat, negpos, negquat);
495-
} else {
496-
mju_copy3(sdf_xpos, xpos);
497-
mju_mat2Quat(sdf_quat, xmat);
498-
}
499-
}
500-
501483
//---------------------------- narrow phase -----------------------------------------------
502484

503485
// comparison function for contact sorting
@@ -767,8 +749,7 @@ int mjc_HFieldSDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int
767749

768750
// collision between a mesh and a signed distance field
769751
int mjc_MeshSDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, mjtNum margin) {
770-
mjtNum* pos1 = d->geom_xpos + 3 * g1;
771-
mjtNum* mat1 = d->geom_xmat + 9 * g1;
752+
mjGETINFO;
772753

773754
mjtNum offset[3], rotation[9], corners[9], x[3], depth;
774755
mjtNum points[3*MAXSDFFACE], dist[MAXMESHPNT], candidate[3*MAXMESHPNT];
@@ -790,10 +771,10 @@ int mjc_MeshSDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g
790771
sdf.geomtype = &geomtype;
791772

792773
// compute transformation from g1 to g2
793-
mjtNum pos2true[3], sdf_quat[4], quat1[4];
774+
mjtNum sdf_quat[4], quat1[4];
794775
mju_mat2Quat(quat1, mat1);
795-
undoTransformation(m, d, g2, pos2true, sdf_quat);
796-
mapPose(pos1, quat1, pos2true, sdf_quat, offset, rotation);
776+
mju_mat2Quat(sdf_quat, mat2);
777+
mapPose(pos1, quat1, pos2, sdf_quat, offset, rotation);
797778

798779
// binary tree search
799780
collideBVH(m, (mjData*)d, g1, offset, rotation, faces, &npoints, &n0, &sdf);
@@ -845,7 +826,7 @@ int mjc_MeshSDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g
845826

846827
// add only the first mjMAXCONPAIR pairs
847828
for (int i=0; i < mju_min(ncandidate, mjMAXCONPAIR); i++) {
848-
cnt = addContact(points, con, candidate + 3*index[i], pos2true, sdf_quat,
829+
cnt = addContact(points, con, candidate + 3*index[i], pos2, sdf_quat,
849830
dist[index[i]], cnt, m, &sdf, (mjData*)d);
850831
}
851832

@@ -871,17 +852,13 @@ int mjc_SDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, m
871852

872853
// compute transformations from/to g1 to/from g2
873854
mjtNum quat1[4], quat2[4];
874-
mjtNum pos1true[3], offset21[3], rotation21[9], rotation12[9];
875-
mjtNum pos2true[3], offset1[3], rotation1[9], offset12[3];
876-
mjtNum offset2[3], rotation2[9], squat1[4], squat2[4];
877-
undoTransformation(m, d, g1, pos1true, squat1);
878-
undoTransformation(m, d, g2, pos2true, squat2);
855+
mjtNum offset21[3], rotation21[9], rotation12[9];
856+
mjtNum offset12[3], offset2[3], rotation2[9];
879857
mju_mat2Quat(quat1, mat1);
880858
mju_mat2Quat(quat2, mat2);
881-
mapPose(pos2, quat2, pos1, quat1, offset1, rotation1);
882-
mapPose(pos1, quat1, pos1true, squat1, offset2, rotation2);
883-
mapPose(pos2true, squat2, pos1true, squat1, offset21, rotation21);
884-
mapPose(pos1true, squat1, pos2true, squat2, offset12, rotation12);
859+
mapPose(pos1, quat1, pos1, quat1, offset2, rotation2);
860+
mapPose(pos2, quat2, pos1, quat1, offset21, rotation21);
861+
mapPose(pos1, quat1, pos2, quat2, offset12, rotation12);
885862

886863
// axis-aligned bounding boxes in g1 frame
887864
for (int i=0; i < 8; i++) {
@@ -893,8 +870,8 @@ int mjc_SDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, m
893870
vec2[1] = (i&2 ? size2[1]+size2[4] : size2[1]-size2[4]);
894871
vec2[2] = (i&4 ? size2[2]+size2[5] : size2[2]-size2[5]);
895872

896-
mju_mulMatVec3(vec2, rotation1, vec2);
897-
mju_addTo3(vec2, offset1);
873+
mju_mulMatVec3(vec2, rotation21, vec2);
874+
mju_addTo3(vec2, offset21);
898875

899876
for (int k=0; k < 3; k++) {
900877
aabb1[0+k] = mju_min(aabb1[0+k], vec1[k]);
@@ -983,7 +960,7 @@ int mjc_SDF(const mjModel* m, const mjData* d, mjContact* con, int g1, int g2, m
983960

984961
// contact point and normal - we use the midsurface where SDF1=SDF2 as zero level set
985962
sdf.type = mjSDFTYPE_MIDSURFACE;
986-
cnt = addContact(contacts, con, x, pos2true, squat2, dist, cnt, m, &sdf, (mjData*)d);
963+
cnt = addContact(contacts, con, x, pos2, quat2, dist, cnt, m, &sdf, (mjData*)d);
987964

988965
// SHOULD NOT OCCUR
989966
if (cnt > mjMAXCONPAIR) {

src/engine/engine_ray.c

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <mujoco/mjmodel.h>
2323
#include <mujoco/mjsan.h> // IWYU pragma: keep
2424
#include <mujoco/mjvisualize.h>
25+
#include "engine/engine_collision_sdf.h"
2526
#include "engine/engine_io.h"
2627
#include "engine/engine_plugin.h"
2728
#include "engine/engine_util_blas.h"
@@ -743,41 +744,35 @@ mjtNum ray_sdf(const mjModel* m, const mjData* d, int g,
743744
return -1;
744745
}
745746

746-
// get sdf
747+
// get sdf plugin
747748
int instance = m->geom_plugin[g];
748-
const int nslot = mjp_pluginCount();
749-
const int slot = m->plugin[instance];
750-
const mjpPlugin* sdf = mjp_getPluginAtSlotUnsafe(slot, nslot);
751-
if (!sdf) mjERROR("invalid plugin slot: %d", slot);
752-
if (!(sdf->capabilityflags & mjPLUGIN_SDF)) {
753-
mjERROR("Plugin is not a sign distance field at slot %d", slot);
754-
}
749+
const mjpPlugin* sdf_ptr = instance == -1 ? NULL : mjc_getSDF(m, g);
750+
instance = instance == -1 ? m->geom_dataid[g] : instance;
751+
mjtGeom geomtype = mjGEOM_SDF;
752+
753+
// construct sdf struct
754+
mjSDF sdf;
755+
sdf.id = &instance;
756+
sdf.type = mjSDFTYPE_SINGLE;
757+
sdf.plugin = &sdf_ptr;
758+
sdf.geomtype = &geomtype;
755759

756760
// reset counter
757-
sdf->reset(m, NULL, (void*)(d->plugin_data[instance]), instance);
758-
759-
// compute transformation
760-
mjtNum sdf_quat[4], sdf_xmat[9], sdf_xpos[9];
761-
mjtNum negpos[3], negquat[4], xquat[4];
762-
mjtNum* xpos = d->geom_xpos + 3*g;
763-
mjtNum* pos = m->mesh_pos + 3*m->geom_dataid[g];
764-
mjtNum* quat = m->mesh_quat + 4*m->geom_dataid[g];
765-
mju_mat2Quat(xquat, d->geom_xmat + 9*g);
766-
mju_negPose(negpos, negquat, pos, quat);
767-
mju_mulPose(sdf_xpos, sdf_quat, xpos, xquat, negpos, negquat);
768-
mju_quat2Mat(sdf_xmat, sdf_quat);
761+
if (sdf_ptr) {
762+
sdf_ptr->reset(m, NULL, (void*)(d->plugin_data[instance]), instance);
763+
}
769764

770765
// map to local frame
771766
mjtNum lpnt[3], lvec[3];
772-
ray_map(sdf_xpos, sdf_xmat, pnt, vec, lpnt, lvec);
767+
ray_map(d->geom_xpos + 3*g, d->geom_xmat + 9*g, pnt, vec, lpnt, lvec);
773768

774769
// unit direction
775770
mju_normalize3(lvec);
776771

777772
// ray marching, see e.g. https://en.wikipedia.org/wiki/Ray_marching
778773
for (int i=0; i < 40; i++) {
779774
mju_addScl3(p, lpnt, lvec, distance_total);
780-
mjtNum distance = sdf->sdf_distance(p, (mjData*)d, instance);
775+
mjtNum distance = mjc_distance(m, d, &sdf, p);
781776
distance_total += distance;
782777
if (mju_abs(distance) < kMinDist) {
783778
return distance_total;
@@ -789,7 +784,9 @@ mjtNum ray_sdf(const mjModel* m, const mjData* d, int g,
789784
}
790785

791786
// reset counter
792-
sdf->reset(m, NULL, (void*)(d->plugin_data[instance]), instance);
787+
if (sdf_ptr) {
788+
sdf_ptr->reset(m, NULL, (void*)(d->plugin_data[instance]), instance);
789+
}
793790

794791
return -1;
795792
}

src/user/user_mesh.cc

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
141141
processed_ = false;
142142
visual_ = true;
143143
needoct_ = false;
144+
needreorient_ = true;
144145

145146
// reset to default if given
146147
if (_def) {
@@ -360,6 +361,7 @@ void mjCMesh::LoadSDF() {
360361
userface.push_back(index);
361362
}
362363

364+
needreorient_ = false;
363365
normal_ = std::move(usernormal);
364366
face_ = std::move(userface);
365367
ProcessVertices(uservert);
@@ -1533,22 +1535,26 @@ void mjCMesh::Process() {
15331535
boxsz_[1] = 0.5 * std::sqrt(6*(eigval[0] + eigval[2] - eigval[1])/volume);
15341536
boxsz_[2] = 0.5 * std::sqrt(6*(eigval[0] + eigval[1] - eigval[2])/volume);
15351537

1536-
// make octree in the geom frame
1537-
// TODO: make octree in the mesh frame, update engine_collision_sdf
1538+
// prevent reorientation if the mesh was autogenerated using marching cubes
1539+
if (!needreorient_) {
1540+
mjuu_setvec(CoM, 0, 0, 0);
1541+
mjuu_setvec(quattmp, 1, 0, 0, 0);
1542+
}
1543+
1544+
// transform CoM to origin
1545+
for (int i=0; i < nvert(); i++) {
1546+
vert_[3*i + 0] -= CoM[0];
1547+
vert_[3*i + 1] -= CoM[1];
1548+
vert_[3*i + 2] -= CoM[2];
1549+
}
1550+
Rotate(quattmp);
1551+
1552+
// make octree in mesh frame
15381553
if (!needoct_) {
15391554
octree_.Clear();
15401555
} else if (octree_.Nodes().empty()) {
1541-
double aamm[6] = {mjMAXVAL, mjMAXVAL, mjMAXVAL, -mjMAXVAL, -mjMAXVAL, -mjMAXVAL};
1542-
for (int i = 0; i < nvert(); i++) {
1543-
aamm[0] = std::min(aamm[0], vert_[3*i + 0]);
1544-
aamm[3] = std::max(aamm[3], vert_[3*i + 0]);
1545-
aamm[1] = std::min(aamm[1], vert_[3*i + 1]);
1546-
aamm[4] = std::max(aamm[4], vert_[3*i + 1]);
1547-
aamm[2] = std::min(aamm[2], vert_[3*i + 2]);
1548-
aamm[5] = std::max(aamm[5], vert_[3*i + 2]);
1549-
}
15501556
octree_.SetFace(vert_, face_);
1551-
octree_.CreateOctree(aamm);
1557+
octree_.CreateOctree(aamm_);
15521558

15531559
// compute sdf coefficients
15541560
if (!plugin.active) {
@@ -1569,14 +1575,6 @@ void mjCMesh::Process() {
15691575
}
15701576
}
15711577

1572-
// transform CoM to origin
1573-
for (int i=0; i < nvert(); i++) {
1574-
vert_[3*i + 0] -= CoM[0];
1575-
vert_[3*i + 1] -= CoM[1];
1576-
vert_[3*i + 2] -= CoM[2];
1577-
}
1578-
Rotate(quattmp);
1579-
15801578
// save the pos and quat that was used to transform the mesh
15811579
mjuu_copyvec(pos_, CoM, 3);
15821580
mjuu_copyvec(quat_, quattmp, 4);

src/user/user_objects.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ class mjCMesh_ : public mjCBase {
10031003
std::vector<int> spec_facetexcoord_;
10041004

10051005
// used by the compiler
1006+
bool needreorient_; // needs reorientation
10061007
bool needoct_; // needs octree
10071008
bool visual_; // true: the mesh is only visual
10081009
std::vector< std::pair<int, int> > halfedge_; // half-edge data

0 commit comments

Comments
 (0)