Copy face_ into facetexcoord_ if not specified and needed.
PiperOrigin-RevId: 601732448 Change-Id: Iffe01076db22201dba2611ea36174f808ae00c1e
This commit is contained in:
committed by
Copybara-Service
parent
4f53d9a0d7
commit
076db5d366
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user