Add mujoco/experimental and move USD work there.
PiperOrigin-RevId: 740730698 Change-Id: If9c68798cda502d6d7632906a034437e2557802e
This commit is contained in:
committed by
Copybara-Service
parent
5c955b8fe2
commit
644b42bee3
@@ -0,0 +1,64 @@
|
||||
// Copyright 2025 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/experimental/usd/plugins/mjcf/fixture.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <absl/log/check.h>
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/declareHandles.h>
|
||||
#include <pxr/usd/sdf/fileFormat.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usd/modelAPI.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usdGeom/mesh.h>
|
||||
#include <pxr/usd/usdGeom/primvarsAPI.h>
|
||||
namespace mujoco {
|
||||
|
||||
using pxr::SdfPath;
|
||||
|
||||
pxr::SdfLayerRefPtr LoadLayer(const std::string& xml) {
|
||||
auto layer = pxr::SdfLayer::CreateAnonymous(
|
||||
"test_layer", pxr::SdfFileFormat::FindByExtension("xml"));
|
||||
layer->ImportFromString(xml);
|
||||
EXPECT_THAT(layer, testing::NotNull());
|
||||
return layer;
|
||||
}
|
||||
|
||||
template <>
|
||||
void ExpectAttributeEqual<pxr::SdfAssetPath>(pxr::UsdStageRefPtr stage,
|
||||
const char* path,
|
||||
const pxr::SdfAssetPath& value) {
|
||||
auto attr = stage->GetAttributeAtPath(pxr::SdfPath(path));
|
||||
EXPECT_TRUE(attr.IsValid());
|
||||
pxr::SdfAssetPath attr_value;
|
||||
attr.Get(&attr_value);
|
||||
EXPECT_EQ(attr_value.GetAssetPath(), value.GetAssetPath());
|
||||
}
|
||||
|
||||
void ExpectAttributeHasConnection(pxr::UsdStageRefPtr stage, const char* path,
|
||||
const char* connection_path) {
|
||||
auto attr = stage->GetAttributeAtPath(SdfPath(path));
|
||||
EXPECT_TRUE(attr.IsValid());
|
||||
pxr::SdfPathVector sources;
|
||||
attr.GetConnections(&sources);
|
||||
EXPECT_EQ(sources.size(), 1);
|
||||
EXPECT_EQ(sources[0], SdfPath(connection_path));
|
||||
}
|
||||
//
|
||||
} // namespace mujoco
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2025 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MUJOCO_TEST_EXPERIMENTAL_USD_PLUGINS_MJCF_FIXTURE_H_
|
||||
#define MUJOCO_TEST_EXPERIMENTAL_USD_PLUGINS_MJCF_FIXTURE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "test/fixture.h"
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/declareHandles.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usd/modelAPI.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
|
||||
#define EXPECT_PRIM_VALID(stage, path) \
|
||||
EXPECT_TRUE((stage)->GetPrimAtPath(SdfPath(path)).IsValid());
|
||||
|
||||
#define EXPECT_PRIM_KIND(stage, path, kind) \
|
||||
{ \
|
||||
pxr::TfToken prim_kind; \
|
||||
pxr::UsdModelAPI::Get(stage, SdfPath(path)).GetKind(&prim_kind); \
|
||||
EXPECT_EQ(kind, prim_kind); \
|
||||
}
|
||||
namespace mujoco {
|
||||
|
||||
pxr::SdfLayerRefPtr LoadLayer(const std::string& xml);
|
||||
|
||||
template <typename T>
|
||||
void ExpectAttributeEqual(pxr::UsdStageRefPtr stage, const char* path,
|
||||
const T& value) {
|
||||
auto attr = stage->GetAttributeAtPath(pxr::SdfPath(path));
|
||||
EXPECT_TRUE(attr.IsValid());
|
||||
T attr_value;
|
||||
attr.Get(&attr_value);
|
||||
EXPECT_EQ(attr_value, value);
|
||||
}
|
||||
|
||||
// Specialization for SdfAssetPath, so that we can compare only the asset path
|
||||
// and not care about whatever the resolved path is.
|
||||
// Otherwise the default operator== would fail because it tests for equality of
|
||||
// the asset path AND the resolved path.
|
||||
template <>
|
||||
void ExpectAttributeEqual<pxr::SdfAssetPath>(pxr::UsdStageRefPtr stage,
|
||||
const char* path,
|
||||
const pxr::SdfAssetPath& value);
|
||||
|
||||
void ExpectAttributeHasConnection(pxr::UsdStageRefPtr stage, const char* path,
|
||||
const char* connection_path);
|
||||
|
||||
using MjcfSdfFileFormatPluginTest = MujocoTest;
|
||||
|
||||
} // namespace mujoco
|
||||
#endif // MUJOCO_TEST_EXPERIMENTAL_USD_PLUGINS_MJCF_FIXTURE_H_
|
||||
@@ -0,0 +1,387 @@
|
||||
// Copyright 2025 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <absl/strings/string_view.h>
|
||||
#include "test/experimental/usd/plugins/mjcf/fixture.h"
|
||||
#include "test/fixture.h"
|
||||
#include <pxr/base/gf/vec2f.h>
|
||||
#include <pxr/base/gf/vec3f.h>
|
||||
#include <pxr/base/tf/staticData.h>
|
||||
#include <pxr/base/tf/staticTokens.h>
|
||||
#include <pxr/base/tf/token.h>
|
||||
#include <pxr/base/vt/array.h>
|
||||
#include <pxr/pxr.h>
|
||||
#include <pxr/usd/kind/registry.h>
|
||||
#include <pxr/usd/sdf/assetPath.h>
|
||||
#include <pxr/usd/sdf/declareHandles.h>
|
||||
#include <pxr/usd/sdf/fileFormat.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
#include <pxr/usd/usd/common.h>
|
||||
#include <pxr/usd/usd/modelAPI.h>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usd/usdGeom/mesh.h>
|
||||
#include <pxr/usd/usdGeom/primvar.h>
|
||||
#include <pxr/usd/usdGeom/primvarsAPI.h>
|
||||
|
||||
PXR_NAMESPACE_OPEN_SCOPE
|
||||
// clang-format off
|
||||
TF_DEFINE_PRIVATE_TOKENS(_tokens,
|
||||
(st)
|
||||
);
|
||||
// clang-format on
|
||||
PXR_NAMESPACE_CLOSE_SCOPE
|
||||
|
||||
namespace mujoco {
|
||||
namespace {
|
||||
|
||||
using pxr::SdfPath;
|
||||
|
||||
static const char* kMaterialsPath =
|
||||
"experimental/usd/plugins/mjcf/testdata/materials.xml";
|
||||
static const char* kMeshObjPath =
|
||||
"experimental/usd/plugins/mjcf/testdata/mesh_obj.xml";
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestClassAuthored) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="test">
|
||||
<default>
|
||||
<default class="test">
|
||||
</default>
|
||||
</default>
|
||||
<worldbody>
|
||||
<body name="test_body" pos="0 0 0">
|
||||
<geom class="test" type="sphere" size="2 2 2"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_VALID(stage, "/__class__");
|
||||
EXPECT_PRIM_VALID(stage, "/__class__/test");
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestBasicMeshSources) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="mesh test">
|
||||
<asset>
|
||||
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="test_body">
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/test_body/test_body/tetrahedron");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/test_body/test_body/tetrahedron/Mesh");
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestMaterials) {
|
||||
const std::string xml_path = GetTestDataFilePath(kMaterialsPath);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(xml_path);
|
||||
EXPECT_THAT(stage, testing::NotNull());
|
||||
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials");
|
||||
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials/material_red");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials/material_red/PreviewSurface");
|
||||
ExpectAttributeEqual(
|
||||
stage,
|
||||
"/mesh_test/Materials/material_red/PreviewSurface.inputs:diffuseColor",
|
||||
pxr::GfVec3f(0.8, 0, 0));
|
||||
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials/material_texture");
|
||||
EXPECT_PRIM_VALID(stage,
|
||||
"/mesh_test/Materials/material_texture/PreviewSurface");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials/material_texture/uvmap");
|
||||
EXPECT_PRIM_VALID(stage, "/mesh_test/Materials/material_texture/texture");
|
||||
ExpectAttributeHasConnection(
|
||||
stage,
|
||||
"/mesh_test/Materials/material_texture/"
|
||||
"PreviewSurface.inputs:diffuseColor",
|
||||
"/mesh_test/Materials/material_texture/texture.outputs:rgb");
|
||||
ExpectAttributeEqual(
|
||||
stage, "/mesh_test/Materials/material_texture/texture.inputs:file",
|
||||
pxr::SdfAssetPath("textures/cube.png"));
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestFaceVaryingMeshSourcesSimpleMjcfMesh) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="mesh test">
|
||||
<asset>
|
||||
<mesh
|
||||
name="tetrahedron"
|
||||
face="0 3 2 0 1 3 0 2 1 1 2 3"
|
||||
vertex="0 1 0 0 0 0 1 0 1 1 0 -1"
|
||||
normal="1 0 0 0 1 0 0 0 1 -1 0 0"
|
||||
texcoord="0.5 0.5 0 0.5 1 1 1 0"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="test_body">
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
|
||||
auto mesh = pxr::UsdGeomMesh::Get(
|
||||
stage, SdfPath("/mesh_test/test_body/test_body/tetrahedron/Mesh"));
|
||||
ASSERT_TRUE(mesh);
|
||||
pxr::VtArray<int> face_vertex_counts;
|
||||
mesh.GetFaceVertexCountsAttr().Get(&face_vertex_counts);
|
||||
EXPECT_EQ(face_vertex_counts.size(), 4);
|
||||
EXPECT_EQ(face_vertex_counts, pxr::VtArray<int>({3, 3, 3, 3}));
|
||||
|
||||
pxr::VtArray<int> face_vertex_indices;
|
||||
mesh.GetFaceVertexIndicesAttr().Get(&face_vertex_indices);
|
||||
EXPECT_EQ(face_vertex_indices.size(), 12);
|
||||
EXPECT_EQ(face_vertex_indices,
|
||||
pxr::VtArray<int>({0, 3, 2, 0, 1, 3, 0, 2, 1, 1, 2, 3}));
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> normals;
|
||||
mesh.GetNormalsAttr().Get(&normals);
|
||||
EXPECT_EQ(normals.size(), face_vertex_indices.size());
|
||||
// We can't directly check the normals values because they are altered by
|
||||
// Mujoco's compiling step. So we at least check that normals with the same
|
||||
// original index are the same.
|
||||
for (int i = 0; i < face_vertex_indices.size(); ++i) {
|
||||
for (int j = i + 1; j < face_vertex_indices.size(); ++j) {
|
||||
if (face_vertex_indices[i] == face_vertex_indices[j]) {
|
||||
EXPECT_EQ(normals[i], normals[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto primvars_api = pxr::UsdGeomPrimvarsAPI(mesh.GetPrim());
|
||||
|
||||
pxr::VtArray<pxr::GfVec2f> texcoords;
|
||||
EXPECT_TRUE(primvars_api.HasPrimvar(pxr::_tokens->st));
|
||||
auto primvar_st = primvars_api.GetPrimvar(pxr::_tokens->st);
|
||||
primvar_st.Get(&texcoords);
|
||||
EXPECT_EQ(texcoords.size(), face_vertex_indices.size());
|
||||
|
||||
// Check the faceVarying texcoords against the manually indexed source
|
||||
// texcoords.
|
||||
pxr::VtArray<pxr::GfVec2f> source_texcoords{
|
||||
{0.5, 0.5}, {0, 0.5}, {1, 0}, {1, 1}};
|
||||
for (int i = 0; i < face_vertex_indices.size(); ++i) {
|
||||
EXPECT_EQ(texcoords[i], source_texcoords[face_vertex_indices[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest,
|
||||
TestFaceVaryingMeshSourcesObjWithIndexedNormals) {
|
||||
const std::string xml_path = GetTestDataFilePath(kMeshObjPath);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(xml_path);
|
||||
EXPECT_THAT(stage, testing::NotNull());
|
||||
|
||||
auto mesh = pxr::UsdGeomMesh::Get(
|
||||
stage, SdfPath("/mesh_test/test_body/test_body/mesh/Mesh"));
|
||||
ASSERT_TRUE(mesh);
|
||||
pxr::VtArray<int> face_vertex_counts;
|
||||
mesh.GetFaceVertexCountsAttr().Get(&face_vertex_counts);
|
||||
EXPECT_EQ(face_vertex_counts.size(), 4);
|
||||
EXPECT_EQ(face_vertex_counts, pxr::VtArray<int>({3, 3, 3, 3}));
|
||||
|
||||
pxr::VtArray<int> face_vertex_indices;
|
||||
mesh.GetFaceVertexIndicesAttr().Get(&face_vertex_indices);
|
||||
EXPECT_EQ(face_vertex_indices.size(), 12);
|
||||
EXPECT_EQ(face_vertex_indices,
|
||||
pxr::VtArray<int>({0, 3, 2, 0, 1, 3, 0, 2, 1, 1, 2, 3}));
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> normals;
|
||||
mesh.GetNormalsAttr().Get(&normals);
|
||||
EXPECT_EQ(normals.size(), face_vertex_indices.size());
|
||||
// We can't directly check the normals values because they are altered by
|
||||
// Mujoco's compiling step.
|
||||
// We also can't access the normals indexing data, and can't use the vertex
|
||||
// indexing data here because they are separate.
|
||||
// So we check that the first half of the normals are the same, then the
|
||||
// second half, as set in the OBJ file.
|
||||
pxr::GfVec3f first_half_normal = normals[0];
|
||||
pxr::GfVec3f second_half_normal = normals[face_vertex_indices.size() / 2];
|
||||
EXPECT_NE(first_half_normal, second_half_normal);
|
||||
int i = 0;
|
||||
for (; i < face_vertex_indices.size() / 2; ++i) {
|
||||
EXPECT_EQ(normals[i], first_half_normal);
|
||||
}
|
||||
for (; i < face_vertex_indices.size(); ++i) {
|
||||
EXPECT_EQ(normals[i], second_half_normal);
|
||||
}
|
||||
|
||||
auto primvars_api = pxr::UsdGeomPrimvarsAPI(mesh.GetPrim());
|
||||
|
||||
pxr::VtArray<pxr::GfVec2f> texcoords;
|
||||
EXPECT_TRUE(primvars_api.HasPrimvar(pxr::_tokens->st));
|
||||
auto primvar_st = primvars_api.GetPrimvar(pxr::_tokens->st);
|
||||
primvar_st.Get(&texcoords);
|
||||
EXPECT_EQ(texcoords.size(), face_vertex_indices.size());
|
||||
|
||||
// Check the faceVarying texcoords against the manually indexed source
|
||||
// texcoords.
|
||||
// NOTE: For OBJ we must use different indices for the texcoords than for the
|
||||
// vertices!
|
||||
std::vector<int> source_face_texcoord_indices{0, 1, 2, 1, 2, 3,
|
||||
2, 3, 0, 3, 0, 1};
|
||||
pxr::VtArray<pxr::GfVec2f> source_texcoords{
|
||||
{0.5, 0.5}, {0, 0.5}, {1, 0}, {1, 1}};
|
||||
// NOTE: The v component of the texcoords is flipped when Mujoco loads the
|
||||
// OBJ.
|
||||
for (auto& uv : source_texcoords) {
|
||||
uv[1] = 1 - uv[1];
|
||||
}
|
||||
for (int i = 0; i < source_face_texcoord_indices.size(); ++i) {
|
||||
EXPECT_EQ(texcoords[i], source_texcoords[source_face_texcoord_indices[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestBody) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="body test">
|
||||
<asset>
|
||||
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="test_body" pos="0 1 0">
|
||||
<joint type="free" />
|
||||
<frame pos="0 0 1">
|
||||
<frame pos="0 0 1">
|
||||
<body name="test_body_2" pos="1 0 0">
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</frame>
|
||||
</frame>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_VALID(stage, "/body_test");
|
||||
EXPECT_PRIM_VALID(stage, "/body_test/test_body");
|
||||
EXPECT_PRIM_VALID(stage, "/body_test/test_body/test_body");
|
||||
EXPECT_PRIM_VALID(stage, "/body_test/test_body/test_body_2");
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestBasicParenting) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="test">
|
||||
<worldbody>
|
||||
<body name="root" pos="0 1 0">
|
||||
<body name="root/body_1" pos="1 0 0" />
|
||||
<body name="root/body_2" pos="1 0 0">
|
||||
<body name="root/body_3" pos="1 0 0" />
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_VALID(stage, "/test/root");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/root");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/root_body_1");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/root_body_2");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/root_body_3");
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestJointsDoNotAffectParenting) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="test">
|
||||
<asset>
|
||||
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="root" pos="0 1 0">
|
||||
<joint type="free" />
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
<body name="middle">
|
||||
<body name="tet">
|
||||
<joint type="hinge" />
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_VALID(stage, "/test/root");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/root");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/middle");
|
||||
EXPECT_PRIM_VALID(stage, "/test/root/tet");
|
||||
}
|
||||
|
||||
TEST_F(MjcfSdfFileFormatPluginTest, TestKindAuthoring) {
|
||||
static constexpr char kXml[] = R"(
|
||||
<mujoco model="test">
|
||||
<asset>
|
||||
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="root" pos="0 1 0">
|
||||
<joint type="free" />
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
<body name="middle">
|
||||
<body name="tet">
|
||||
<joint type="hinge" />
|
||||
<geom type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
pxr::SdfLayerRefPtr layer = LoadLayer(kXml);
|
||||
|
||||
auto stage = pxr::UsdStage::Open(layer);
|
||||
EXPECT_PRIM_KIND(stage, "/test", pxr::KindTokens->group);
|
||||
EXPECT_PRIM_KIND(stage, "/test/root", pxr::KindTokens->component);
|
||||
EXPECT_PRIM_KIND(stage, "/test/root/root", pxr::KindTokens->subcomponent);
|
||||
EXPECT_PRIM_KIND(stage, "/test/root/middle", pxr::KindTokens->subcomponent);
|
||||
EXPECT_PRIM_KIND(stage, "/test/root/tet", pxr::KindTokens->subcomponent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mujoco
|
||||
@@ -0,0 +1,15 @@
|
||||
<mujoco model="mesh test">
|
||||
<asset>
|
||||
<texture name="texture" file="textures/cube.png" type="2d" />
|
||||
<material name="material_red" rgba="0.8 0 0 1" />
|
||||
<material name="material_texture" texture="texture" />
|
||||
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="test_body">
|
||||
<geom material="material_red" type="mesh" mesh="tetrahedron"/>
|
||||
<geom material="material_texture" type="mesh" mesh="tetrahedron"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<mujoco model="mesh test">
|
||||
<asset>
|
||||
<mesh name="mesh" file="meshes/tetrahedron.obj"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="test_body">
|
||||
<geom type="mesh" mesh="mesh"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
@@ -0,0 +1,16 @@
|
||||
v 0 1 0
|
||||
v 0 0 0
|
||||
v 1 0 1
|
||||
v 1 0 -1
|
||||
vn 1 0 0
|
||||
vn -1 0 0
|
||||
vt 0.5 0.5
|
||||
vt 0 0.5
|
||||
vt 1 1
|
||||
vt 1 0
|
||||
|
||||
f 1/1/1 4/2/1 3/3/1
|
||||
f 1/2/1 2/3/1 4/4/1
|
||||
f 1/3/2 3/4/2 2/1/2
|
||||
f 2/4/2 3/1/2 4/2/2
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
Reference in New Issue
Block a user