Consolidate ray normal functions.

PiperOrigin-RevId: 842300829
Change-Id: Ic5e921084710cb044a4f49ea9b566d277838aaa1
This commit is contained in:
Yuval Tassa
2025-12-09 10:35:10 -08:00
committed by Copybara-Service
parent 85e6f6de3c
commit f06aa45ea6
3 changed files with 50 additions and 72 deletions
+43 -24
View File
@@ -197,6 +197,7 @@ mjtNum ray_triangle(mjtNum v[][3], const mjtNum lpnt[3], const mjtNum lvec[3],
return x; return x;
} }
//---------------------------- geom-specific intersection functions -------------------------------- //---------------------------- geom-specific intersection functions --------------------------------
// plane // plane
@@ -558,8 +559,8 @@ static mjtNum ray_box(const mjtNum pos[3], const mjtNum mat[9], const mjtNum siz
// intersect ray with hfield, compute normal if given // intersect ray with hfield, compute normal if given
mjtNum mj_rayHfieldNormal(const mjModel* m, const mjData* d, int geomid, static mjtNum mj_rayHfieldNormal(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]) { const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]) {
// clear normal if given // clear normal if given
if (normal) mju_zero3(normal); if (normal) mju_zero3(normal);
@@ -736,6 +737,7 @@ mjtNum mj_rayHfieldNormal(const mjModel* m, const mjData* d, int geomid,
return x; return x;
} }
// intersect ray with hfield // intersect ray with hfield
mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid, mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3]) { const mjtNum pnt[3], const mjtNum vec[3]) {
@@ -885,10 +887,11 @@ mjtNum mju_rayTree(const mjModel* m, const mjData* d, int id, const mjtNum pnt[3
return x; return x;
} }
// intersect ray with signed distance field, compute normal if given // intersect ray with signed distance field, compute normal if given
mjtNum mj_raySdfNormal(const mjModel* m, const mjData* d, int g, static mjtNum mj_raySdfNormal(const mjModel* m, const mjData* d, int g,
const mjtNum pnt[3], const mjtNum vec[3], const mjtNum pnt[3], const mjtNum vec[3],
mjtNum normal[3]) { mjtNum normal[3]) {
if (normal) mju_zero3(normal); if (normal) mju_zero3(normal);
mjtNum distance_total = 0; mjtNum distance_total = 0;
@@ -953,15 +956,17 @@ mjtNum mj_raySdfNormal(const mjModel* m, const mjData* d, int g,
return -1; return -1;
} }
// intersect ray with signed distance field // intersect ray with signed distance field
static mjtNum ray_sdf(const mjModel* m, const mjData* d, int g, static mjtNum ray_sdf(const mjModel* m, const mjData* d, int g,
const mjtNum pnt[3], const mjtNum vec[3]) { const mjtNum pnt[3], const mjtNum vec[3]) {
return mj_raySdfNormal(m, d, g, pnt, vec, NULL); return mj_raySdfNormal(m, d, g, pnt, vec, NULL);
} }
// intersect ray with mesh, compute normal if given // intersect ray with mesh, compute normal if given
mjtNum mj_rayMeshNormal(const mjModel* m, const mjData* d, int id, const mjtNum pnt[3], static mjtNum mj_rayMeshNormal(const mjModel* m, const mjData* d, int id, const mjtNum pnt[3],
const mjtNum vec[3], mjtNum normal[3]) { const mjtNum vec[3], mjtNum normal[3]) {
// clear normal if given // clear normal if given
if (normal) mju_zero3(normal); if (normal) mju_zero3(normal);
@@ -978,15 +983,18 @@ mjtNum mj_rayMeshNormal(const mjModel* m, const mjData* d, int id, const mjtNum
return mju_rayTree(m, d, id, pnt, vec, normal); return mju_rayTree(m, d, id, pnt, vec, normal);
} }
// intersect ray with mesh // intersect ray with mesh
mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int id, const mjtNum pnt[3], mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int id, const mjtNum pnt[3],
const mjtNum vec[3]) { const mjtNum vec[3]) {
return mj_rayMeshNormal(m, d, id, pnt, vec, NULL); return mj_rayMeshNormal(m, d, id, pnt, vec, NULL);
} }
// intersect ray and find normal with primitive geom, no meshes or hfields, compute normal if given // intersect ray and find normal with primitive geom, no meshes or hfields, compute normal if given
mjtNum mju_rayGeomNormal(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3], mjtNum mju_rayGeomNormal(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3],
const mjtNum pnt[3], const mjtNum vec[3], int geomtype, mjtNum normal[3]) { const mjtNum pnt[3], const mjtNum vec[3], int geomtype,
mjtNum normal[3]) {
switch ((mjtGeom) geomtype) { switch ((mjtGeom) geomtype) {
case mjGEOM_PLANE: case mjGEOM_PLANE:
return ray_plane(pos, mat, size, pnt, vec, normal); return ray_plane(pos, mat, size, pnt, vec, normal);
@@ -1019,6 +1027,7 @@ mjtNum mju_rayGeom(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3
return mju_rayGeomNormal(pos, mat, size, pnt, vec, geomtype, NULL); return mju_rayGeomNormal(pos, mat, size, pnt, vec, geomtype, NULL);
} }
// intersect ray with flex, return nearest vertex id // intersect ray with flex, return nearest vertex id
mjtNum mju_rayFlex(const mjModel* m, const mjData* d, int flex_layer, mjtByte flg_vert, mjtNum mju_rayFlex(const mjModel* m, const mjData* d, int flex_layer, mjtByte flg_vert,
mjtByte flg_edge, mjtByte flg_face, mjtByte flg_skin, int flexid, mjtByte flg_edge, mjtByte flg_face, mjtByte flg_skin, int flexid,
@@ -1314,9 +1323,13 @@ static int point_in_box(const mjtNum aabb[6], const mjtNum xpos[3],
// intersect ray (pnt+x*vec, x>=0) with visible geoms, except geoms on bodyexclude // intersect ray (pnt+x*vec, x>=0) with visible geoms, except geoms on bodyexclude
// return geomid and distance (x) to nearest surface, or -1 if no intersection // return geomid and distance (x) to nearest surface, or -1 if no intersection
// geomgroup, flg_static are as in mjvOption; geomgroup==NULL skips group exclusion // geomgroup, flg_static are as in mjvOption; geomgroup==NULL skips group exclusion
mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3], mjtNum mj_rayNormal(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude, int geomid[1]) { const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude,
int geomid[1], mjtNum normal[3]) {
int ngeom = m->ngeom;
mjtNum dist, newdist; mjtNum dist, newdist;
mjtNum normal_local[3];
mjtNum* p_normal = normal ? normal_local : NULL;
// check vector length // check vector length
if (mju_norm3(vec) < mjMINVAL) { if (mju_norm3(vec) < mjMINVAL) {
@@ -1326,29 +1339,28 @@ mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtN
// clear result // clear result
dist = -1; dist = -1;
if (geomid) *geomid = -1; if (geomid) *geomid = -1;
if (normal) mju_zero3(normal);
// loop over geoms not eliminated by mask and bodyexclude // loop over geoms not eliminated by mask and bodyexclude
for (int i=0; i < m->ngeom; i++) { for (int i=0; i < ngeom; i++) {
if (!ray_eliminate(m, d, i, geomgroup, flg_static, bodyexclude)) { if (!ray_eliminate(m, d, i, geomgroup, flg_static, bodyexclude)) {
// handle mesh and hfield separately int type = m->geom_type[i];
if (m->geom_type[i] == mjGEOM_MESH) { if (type == mjGEOM_MESH) {
newdist = mj_rayMesh(m, d, i, pnt, vec); newdist = mj_rayMeshNormal(m, d, i, pnt, vec, p_normal);
} else if (m->geom_type[i] == mjGEOM_HFIELD) { } else if (type == mjGEOM_HFIELD) {
newdist = mj_rayHfield(m, d, i, pnt, vec); newdist = mj_rayHfieldNormal(m, d, i, pnt, vec, p_normal);
} else if (m->geom_type[i] == mjGEOM_SDF) { } else if (type == mjGEOM_SDF) {
newdist = ray_sdf(m, d, i, pnt, vec); newdist = mj_raySdfNormal(m, d, i, pnt, vec, p_normal);
} } else {
newdist = mju_rayGeomNormal(d->geom_xpos+3*i, d->geom_xmat+9*i,
// otherwise general dispatch m->geom_size+3*i, pnt, vec, type, p_normal);
else {
newdist = mju_rayGeom(d->geom_xpos+3*i, d->geom_xmat+9*i,
m->geom_size+3*i, pnt, vec, m->geom_type[i]);
} }
// update if closer intersection found // update if closer intersection found
if (newdist >= 0 && (newdist < dist || dist < 0)) { if (newdist >= 0 && (newdist < dist || dist < 0)) {
dist = newdist; dist = newdist;
if (geomid) *geomid = i; if (geomid) *geomid = i;
if (normal) mju_copy3(normal, normal_local);
} }
} }
} }
@@ -1357,6 +1369,13 @@ mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtN
} }
// intersect ray
mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude, int geomid[1]) {
return mj_rayNormal(m, d, pnt, vec, geomgroup, flg_static, bodyexclude, geomid, NULL);
}
// Initializes spherical bounding angles (geom_ba) and flag vector for a given source // Initializes spherical bounding angles (geom_ba) and flag vector for a given source
void mju_multiRayPrepare(const mjModel* m, const mjData* d, const mjtNum pnt[3], void mju_multiRayPrepare(const mjModel* m, const mjData* d, const mjtNum pnt[3],
const mjtNum ray_xmat[9], const mjtByte* geomgroup, mjtByte flg_static, const mjtNum ray_xmat[9], const mjtByte* geomgroup, mjtByte flg_static,
+4 -16
View File
@@ -46,10 +46,6 @@ MJAPI mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], cons
MJAPI mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid, MJAPI mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3]); const mjtNum pnt[3], const mjtNum vec[3]);
// intersect ray with hfield, compute normal if given
MJAPI mjtNum mj_rayHfieldNormal(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]);
// intersect ray with triangle // intersect ray with triangle
MJAPI mjtNum ray_triangle(mjtNum v[][3], const mjtNum lpnt[3], const mjtNum lvec[3], MJAPI mjtNum ray_triangle(mjtNum v[][3], const mjtNum lpnt[3], const mjtNum lvec[3],
const mjtNum b0[3], const mjtNum b1[3], mjtNum normal[3]); const mjtNum b0[3], const mjtNum b1[3], mjtNum normal[3]);
@@ -58,22 +54,14 @@ MJAPI mjtNum ray_triangle(mjtNum v[][3], const mjtNum lpnt[3], const mjtNum lvec
MJAPI mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int geomid, MJAPI mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3]); const mjtNum pnt[3], const mjtNum vec[3]);
// intersect ray with mesh, compute normal if given
MJAPI mjtNum mj_rayMeshNormal(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]);
// intersect ray with signed distance field, compute normal if given
MJAPI mjtNum mj_raySdfNormal(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]);
// intersect ray with primitive geom, no meshes or hfields // intersect ray with primitive geom, no meshes or hfields
MJAPI mjtNum mju_rayGeom(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3], MJAPI mjtNum mju_rayGeom(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3],
const mjtNum pnt[3], const mjtNum vec[3], int geomtype); const mjtNum pnt[3], const mjtNum vec[3], int geomtype);
// intersect ray with primitive geom, no meshes or hfields, compute normal if given // intersect ray with geom, compute normal if given
MJAPI mjtNum mju_rayGeomNormal(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3], MJAPI mjtNum mj_rayNormal(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
const mjtNum pnt[3], const mjtNum vec[3], int geomtype, const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude,
mjtNum normal[3]); int geomid[1], mjtNum normal[3]);
// intersect ray with flex, return nearest vertex id // intersect ray with flex, return nearest vertex id
MJAPI mjtNum mju_rayFlex(const mjModel* m, const mjData* d, int flex_layer, mjtByte flg_vert, MJAPI mjtNum mju_rayFlex(const mjModel* m, const mjData* d, int flex_layer, mjtByte flg_vert,
+3 -32
View File
@@ -510,31 +510,14 @@ TEST_F(RayTest, GeomNormal) {
continue; continue;
} }
// geom info
const mjtNum* pos = d->geom_xpos;
const mjtNum* mat = d->geom_xmat;
const mjtNum* size = m->geom_size;
int type = m->geom_type[0];
// site info // site info
const mjtNum* pnt = d->site_xpos; const mjtNum* pnt = d->site_xpos;
const mjtNum vec[3] = {d->site_xmat[2], d->site_xmat[5], d->site_xmat[8]}; const mjtNum vec[3] = {d->site_xmat[2], d->site_xmat[5], d->site_xmat[8]};
// compute ray length and normal // compute ray length and normal
mjtNum r, normal[3]; mjtNum r, normal[3];
switch (type) { int geomid;
case mjGEOM_MESH: r = mj_rayNormal(m, d, pnt, vec, NULL, 1, -1, &geomid, normal);
r = mj_rayMeshNormal(m, d, 0, pnt, vec, normal);
break;
case mjGEOM_SDF:
r = mj_raySdfNormal(m, d, 0, pnt, vec, normal);
break;
case mjGEOM_HFIELD:
r = mj_rayHfieldNormal(m, d, 0, pnt, vec, normal);
break;
default:
r = mju_rayGeomNormal(pos, mat, size, pnt, vec, type, normal);
}
// compare with sensor // compare with sensor
EXPECT_EQ(r, d->sensordata[0]) << path << ", time " << d->time; EXPECT_EQ(r, d->sensordata[0]) << path << ", time " << d->time;
@@ -559,19 +542,7 @@ TEST_F(RayTest, GeomNormal) {
d->site_xmat[6 + i]}; d->site_xmat[6 + i]};
mjtNum dr, dpnt[3]; mjtNum dr, dpnt[3];
mju_addScl3(dpnt, pnt, nudge, eps); mju_addScl3(dpnt, pnt, nudge, eps);
switch (type) { dr = mj_rayNormal(m, d, dpnt, vec, NULL, 1, -1, nullptr, nullptr);
case mjGEOM_MESH:
dr = mj_rayMeshNormal(m, d, 0, dpnt, vec, nullptr);
break;
case mjGEOM_SDF:
dr = mj_raySdfNormal(m, d, 0, dpnt, vec, nullptr);
break;
case mjGEOM_HFIELD:
dr = mj_rayHfieldNormal(m, d, 0, dpnt, vec, nullptr);
break;
default:
dr = mju_rayGeomNormal(pos, mat, size, dpnt, vec, type, nullptr);
}
mju_addScl3(ds[i], dpnt, vec, dr); mju_addScl3(ds[i], dpnt, vec, dr);
} }