Copy face_ into facetexcoord_ if not specified and needed.

PiperOrigin-RevId: 601732448
Change-Id: Iffe01076db22201dba2611ea36174f808ae00c1e
This commit is contained in:
Alessio Quaglino
2024-01-26 04:53:37 -08:00
committed by Copybara-Service
parent 4f53d9a0d7
commit 076db5d366
2 changed files with 87 additions and 13 deletions
+12
View File
@@ -463,6 +463,12 @@ void mjCMesh::Compile(const mjVFS* vfs) {
throw mjCError(this, "texcoord must be a multiple of 2");
}
// check size if no face texcoord indices are given
if (usertexcoord_.size() != 2*nvert_ && userfacetexcoord_.empty()) {
throw mjCError(this,
"texcoord must be 2*nv if face texcoord indices are not provided in an OBJ file");
}
// copy from user
ntexcoord_ = (int)usertexcoord_.size()/2;
texcoord_ = VecToArray(usertexcoord_, !file_.empty());
@@ -570,6 +576,12 @@ void mjCMesh::Compile(const mjVFS* vfs) {
facetexcoord_ = VecToArray(userfacetexcoord_, !file_.empty());
}
// no facetexcoord: copy from faces
if (!facetexcoord_ && texcoord_) {
facetexcoord_ = (int*) mju_malloc(3*nface_*sizeof(int));
memcpy(facetexcoord_, face_, 3*nface_*sizeof(int));
}
// facenormal might not exist if usernormal was specified
if (!facenormal_) {
facenormal_ = (int*) mju_malloc(3*nface_*sizeof(int));
+75 -13
View File
@@ -60,6 +60,7 @@ static const char* const kMalformedFaceOBJPath =
using ::testing::HasSubstr;
using ::testing::IsNull;
using ::testing::NotNull;
// ------------- test invalid filenames ----------------------------------------
@@ -315,7 +316,7 @@ TEST_F(MjCMeshTest, LoadMSH) {
char error[1024];
size_t error_sz = 1024;
mjModel* model = mj_loadXML(xml_path.c_str(), 0, error, error_sz);
ASSERT_THAT(model, testing::NotNull()) << error;
ASSERT_THAT(model, NotNull()) << error;
ASSERT_EQ(model->nmeshvert, 36);
mj_deleteModel(model);
}
@@ -395,7 +396,7 @@ TEST_F(MjCMeshTest, TinyMeshLoads) {
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, testing::NotNull());
ASSERT_THAT(model, NotNull());
mj_deleteModel(model);
}
@@ -415,7 +416,7 @@ TEST_F(MjCMeshTest, FaceNormalAutogenerated) {
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, testing::NotNull());
ASSERT_THAT(model, NotNull());
mj_deleteModel(model);
}
@@ -437,7 +438,7 @@ TEST_F(MjCMeshTest, SmallInertiaLoads) {
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, testing::NotNull());
ASSERT_THAT(model, NotNull());
mj_deleteModel(model);
}
@@ -526,7 +527,7 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedWorld) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
CheckTetrahedronWasRescaled(model);
mj_deleteModel(model);
}
@@ -548,7 +549,7 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedNoMass) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
CheckTetrahedronWasRescaled(model);
mj_deleteModel(model);
}
@@ -571,7 +572,7 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedInertial) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
CheckTetrahedronWasRescaled(model);
mj_deleteModel(model);
}
@@ -593,7 +594,7 @@ TEST_F(MjCMeshTest, FlippedFaceAllowedNegligibleArea) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
CheckTetrahedronWasRescaled(model);
mj_deleteModel(model);
}
@@ -649,7 +650,7 @@ TEST_F(MjCMeshTest, AreaTooSmallAllowedWorld) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
mj_deleteModel(model);
}
@@ -692,7 +693,7 @@ TEST_F(MjCMeshTest, VolumeSmallAllowedShell) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, testing::NotNull());
ASSERT_THAT(model, NotNull());
EXPECT_LE(mju_abs(model->geom_size[0]), 1);
EXPECT_LE(mju_abs(model->geom_size[1]), 1);
EXPECT_LE(mju_abs(model->geom_size[2]), 1);
@@ -717,7 +718,7 @@ TEST_F(MjCMeshTest, VolumeNegativeDefaultsLegacy) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
EXPECT_LE(mju_abs(model->geom_size[0]), 1);
EXPECT_LE(mju_abs(model->geom_size[1]), 1);
EXPECT_LE(mju_abs(model->geom_size[2]), 1);
@@ -740,7 +741,7 @@ TEST_F(MjCMeshTest, VolumeTooSmallAllowedWorld) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::NotNull());
EXPECT_THAT(model, NotNull());
mj_deleteModel(model);
}
@@ -818,7 +819,7 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, testing::NotNull());
ASSERT_THAT(model, NotNull());
// Loading the mesh results in an offset of the geom's pos and quat due to the
// fact that the geom's center is not the volumetric center of the mesh. To
// recover the geom's originally specified pose, the offset used is stored in
@@ -862,5 +863,66 @@ TEST_F(MjCMeshTest, MeshPosQuat) {
mj_deleteModel(model);
}
// ----------------------------- texcoord -------------------------------------
TEST_F(MjCMeshTest, CreateFaceTexCoord) {
static constexpr char xml[] = R"(
<mujoco>
<asset>
<mesh name="mesh" vertex="0 0 0 1 0 0 0 1 0 0 0 1"
texcoord="0 0 0 0 0 0 0 0"/>
</asset>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, NotNull()) << error.data();
mj_deleteModel(model);
}
TEST_F(MjCMeshTest, UseFaceTexCoord) {
static constexpr char xml[] = R"(
<mujoco>
<asset>
<mesh name="mesh" vertex="0 0 0 1 0 0 0 1 0 0 0 1"
face="0 2 1 0 1 3 2 0 3 1 2 3"
texcoord="0 0 .1 .1 .2 .2 .3 .3"/>
</asset>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, NotNull()) << error.data();
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 0]], .0);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 1]], .2);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 2]], .1);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 3]], .0);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 4]], .1);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 5]], .3);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 6]], .2);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 7]], .0);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 8]], .3);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[ 9]], .1);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[10]], .2);
EXPECT_FLOAT_EQ(model->mesh_texcoord[2*model->mesh_facetexcoord[11]], .3);
mj_deleteModel(model);
}
TEST_F(MjCMeshTest, MissingTexCoord) {
static constexpr char xml[] = R"(
<mujoco>
<asset>
<mesh name="mesh" vertex="0 0 0 1 0 0 0 1 0 0 0 1"
texcoord="0 0"/>
</asset>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(model, testing::IsNull());
EXPECT_THAT(error.data(), HasSubstr("texcoord must be 2*nv"));
}
} // namespace
} // namespace mujoco