diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 77a9b896..2fe975b4 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -3222,11 +3222,14 @@ void mjCLight::CopyFromSpec() { void mjCLight::Compile(void) { CopyFromSpec(); - double quat[4]= {1, 0, 0, 0}; - // frame if (frame) { - mjuu_frameaccumChild(frame->pos, frame->quat, pos, quat); + // apply frame transform to pos, qunit is unused + double qunit[4]= {1, 0, 0, 0}; + mjuu_frameaccumChild(frame->pos, frame->quat, pos, qunit); + + // rotate dir + mjuu_rotVecQuat(dir, dir, frame->quat); } // normalize direction, make sure it is not zero diff --git a/test/user/user_objects_test.cc b/test/user/user_objects_test.cc index a23d937e..6cd6fabf 100644 --- a/test/user/user_objects_test.cc +++ b/test/user/user_objects_test.cc @@ -2086,7 +2086,6 @@ TEST_F(MujocoTest, Frame) { - )"; constexpr mjtNum eps = 1e-14; std::array error; @@ -2142,6 +2141,34 @@ TEST_F(MujocoTest, Frame) { mj_deleteData(d); } +TEST_F(MujocoTest, FrameTransformsLight) { + static constexpr char xml[] = R"( + + + + + + + + )"; + std::array error; + mjModel* m = LoadModelFromString(xml, error.data(), error.size()); + EXPECT_THAT(m, testing::NotNull()) << error.data(); + EXPECT_EQ(m->nlight, 1); + + constexpr mjtNum eps = 1e-14; + EXPECT_NEAR(m->light_pos[0], -mju_sqrt(.5), eps); + EXPECT_NEAR(m->light_pos[1], 0, eps); + EXPECT_NEAR(m->light_pos[2], 1 + mju_sqrt(.5), eps); + + EXPECT_NEAR(m->light_dir[0], 0, eps); + EXPECT_NEAR(m->light_dir[1], 0, eps); + EXPECT_NEAR(m->light_dir[2], -1, eps); + + mj_deleteModel(m); +} + + // ------------- test bvh ------------------------------------------------------ TEST_F(MujocoTest, RobustBVH) { static constexpr char xml1[] = R"(