Skip to content

Commit 576f9bd

Browse files
committed
usd -> sdf: Read transforms
Signed-off-by: ahcorde <ahcorde@gmail.com>
1 parent 3a9b349 commit 576f9bd

File tree

4 files changed

+577
-0
lines changed

4 files changed

+577
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (C) 2022 Open Source Robotics Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
#ifndef SDF_USD_USD_PARSER_UTILS_HH_
19+
#define SDF_USD_USD_PARSER_UTILS_HH_
20+
21+
#include <string>
22+
#include <vector>
23+
24+
#include <ignition/math/Pose3.hh>
25+
#include <ignition/math/Vector3.hh>
26+
27+
// TODO(ahcorde):this is to remove deprecated "warnings" in usd, these warnings
28+
// are reported using #pragma message so normal diagnostic flags cannot remove
29+
// them. This workaround requires this block to be used whenever usd is
30+
// included.
31+
#pragma push_macro ("__DEPRECATED")
32+
#undef __DEPRECATED
33+
#include <pxr/usd/usdGeom/gprim.h>
34+
#pragma pop_macro ("__DEPRECATED")
35+
36+
#include "sdf/sdf_config.h"
37+
#include "sdf/system_util.hh"
38+
#include "sdf/usd/Export.hh"
39+
#include "sdf/usd/UsdError.hh"
40+
41+
#include "USDData.hh"
42+
43+
namespace sdf
44+
{
45+
// Inline bracke to help doxygen filtering.
46+
inline namespace SDF_VERSION_NAMESPACE {
47+
//
48+
namespace usd
49+
{
50+
/// \brief This class stores the transforms of a schema
51+
/// This might contains scale, translate or rotation operations
52+
/// The booleans are used to check if there is a transform defined
53+
/// in the schema
54+
/// Rotation is splitted in a vector because this might be defined
55+
/// as a rotation of 3 angles (ZYX, XYZ, etc).
56+
class IGNITION_SDFORMAT_USD_VISIBLE UDSTransforms
57+
{
58+
public:
59+
/// \brief Scale of the schema
60+
ignition::math::Vector3d scale{1, 1, 1};
61+
62+
/// \brief Rotation of the schema
63+
std::vector<ignition::math::Quaterniond> q;
64+
65+
/// \brief Translatio of the schema
66+
ignition::math::Vector3d translate{0, 0, 0};
67+
68+
/// \brief True if there is a rotation ZYX definedor false otherwise
69+
bool isRotationZYX = false;
70+
71+
/// \brief True if there is a rotation (as a quaterion) defined
72+
/// or false otherwise
73+
bool isRotation = false;
74+
75+
/// \brief True if there is a translation defined or false otherwise
76+
bool isTranslate = false;
77+
};
78+
79+
/// \brief This function will parse all the parents transforms of a prim
80+
/// This will stop when the name of the parent is the same as _schemaToStop
81+
/// \param[in] _prim Initial prim to read the transform
82+
/// \param[in] _usdData USDData structure to get info about the prim, for
83+
/// example: metersperunit
84+
/// \param[out] _tfs A vector with all the transforms
85+
/// \param[out] _scale The scale of the prims
86+
/// \param[in] _schemaToStop Name of the prim where the loop will stop
87+
/// reading transforms
88+
void IGNITION_SDFORMAT_USD_VISIBLE GetAllTransforms(
89+
const pxr::UsdPrim &_prim,
90+
USDData &_usdData,
91+
std::vector<ignition::math::Pose3d> &_tfs,
92+
ignition::math::Vector3d &_scale,
93+
const std::string &_schemaToStop);
94+
95+
/// \brief This function get the transform from a prim to the specified
96+
/// schemaToStop variable
97+
/// This will stop when the name of the parent is the same as _schemaToStop
98+
/// \param[in] _prim Initial prim to read the transform
99+
/// \param[in] _usdData USDData structure to get info about the prim, for
100+
/// example: metersperunit
101+
/// \param[out] _pose Pose of the prim
102+
/// \param[out] _scale The scale of the prim
103+
/// \param[in] _schemaToStop Name of the prim where the loop will stop
104+
/// reading transforms
105+
void IGNITION_SDFORMAT_USD_VISIBLE GetTransform(
106+
const pxr::UsdPrim &_prim,
107+
USDData &_usdData,
108+
ignition::math::Pose3d &_pose,
109+
ignition::math::Vector3d &_scale,
110+
const std::string &_schemaToStop);
111+
112+
/// \brief Read the usd prim transforms. Scale, rotation or transform might
113+
/// be defined as float or doubles
114+
/// \param[in] _prim Prim where the transforms are read
115+
UDSTransforms IGNITION_SDFORMAT_USD_VISIBLE ParseUSDTransform(
116+
const pxr::UsdPrim &_prim);
117+
}
118+
}
119+
}
120+
#endif

usd/src/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ set(sources
1717
usd_parser/USDData.cc
1818
usd_parser/USDMaterial.cc
1919
usd_parser/USDStage.cc
20+
usd_parser/USDTransforms.cc
2021
)
2122

2223
ign_add_component(usd SOURCES ${sources} GET_TARGET_NAME usd_target)
@@ -46,6 +47,7 @@ set(gtest_sources
4647
sdf_parser/World_Sdf2Usd_TEST.cc
4748
usd_parser/USDData_TEST.cc
4849
usd_parser/USDStage_TEST.cc
50+
usd_parser/USDTransforms_TEST.cc
4951
Conversions_TEST.cc
5052
UsdError_TEST.cc
5153
UsdUtils_TEST.cc

usd/src/usd_parser/USDTransforms.cc

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Copyright (C) 2022 Open Source Robotics Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
#include "sdf/usd/usd_parser/USDTransforms.hh"
19+
#include "sdf/usd/usd_parser/USDData.hh"
20+
21+
#include <ignition/math/Pose3.hh>
22+
#include <ignition/math/Vector3.hh>
23+
24+
namespace sdf
25+
{
26+
// Inline bracke to help doxygen filtering.
27+
inline namespace SDF_VERSION_NAMESPACE {
28+
//
29+
namespace usd
30+
{
31+
32+
void GetAllTransforms(
33+
const pxr::UsdPrim &_prim,
34+
USDData &_usdData,
35+
std::vector<ignition::math::Pose3d> &_tfs,
36+
ignition::math::Vector3d &_scale,
37+
const std::string &_schemaToStop)
38+
{
39+
pxr::UsdPrim parent = _prim;
40+
double metersPerUnit = 1.0;
41+
std::string upAxis = "Y";
42+
43+
// this assumes that there can only be one stage
44+
auto stageData = _usdData.FindStage(parent.GetPath().GetName());
45+
if (stageData.second != nullptr) {
46+
metersPerUnit = stageData.second->MetersPerUnit();
47+
upAxis = stageData.second->UpAxis();
48+
}
49+
50+
while (parent)
51+
{
52+
if (pxr::TfStringify(parent.GetPath()) == _schemaToStop)
53+
{
54+
return;
55+
}
56+
57+
UDSTransforms t = ParseUSDTransform(parent);
58+
59+
ignition::math::Pose3d pose;
60+
_scale *= t.scale;
61+
62+
pose.Pos() = t.translate * metersPerUnit;
63+
// scaling is lost when we convert to pose, so we pre-scale the translation
64+
// to make them match the scaled values.
65+
if (!_tfs.empty()) {
66+
auto& child = _tfs.back();
67+
child.Pos().Set(
68+
child.Pos().X() * t.scale[0],
69+
child.Pos().Y() * t.scale[1],
70+
child.Pos().Z() * t.scale[2]);
71+
}
72+
73+
if (!t.isRotationZYX)
74+
{
75+
if (t.isRotation)
76+
{
77+
pose.Rot() = t.q[0];
78+
}
79+
_tfs.push_back(pose);
80+
}
81+
else
82+
{
83+
ignition::math::Pose3d poseZ = ignition::math::Pose3d(
84+
ignition::math::Vector3d(0 ,0 ,0), t.q[2]);
85+
ignition::math::Pose3d poseY = ignition::math::Pose3d(
86+
ignition::math::Vector3d(0 ,0 ,0), t.q[1]);
87+
ignition::math::Pose3d poseX = ignition::math::Pose3d(
88+
ignition::math::Vector3d(0 ,0 ,0), t.q[0]);
89+
90+
ignition::math::Pose3d poseT = ignition::math::Pose3d(
91+
t.translate * metersPerUnit,
92+
ignition::math::Quaterniond(1, 0, 0, 0));
93+
94+
_tfs.push_back(poseZ);
95+
_tfs.push_back(poseY);
96+
_tfs.push_back(poseX);
97+
_tfs.push_back(poseT);
98+
}
99+
parent = parent.GetParent();
100+
}
101+
102+
if (upAxis == "Y")
103+
{
104+
ignition::math::Pose3d poseUpAxis = ignition::math::Pose3d(
105+
ignition::math::Vector3d(0 ,0 ,0),
106+
ignition::math::Quaterniond(IGN_PI_2, 0, 0));
107+
_tfs.push_back(poseUpAxis);
108+
}
109+
}
110+
111+
void GetTransform(
112+
const pxr::UsdPrim &_prim,
113+
USDData &_usdData,
114+
ignition::math::Pose3d &_pose,
115+
ignition::math::Vector3d &_scale,
116+
const std::string &_schemaToStop)
117+
{
118+
std::vector<ignition::math::Pose3d> tfs;
119+
GetAllTransforms(_prim, _usdData, tfs, _scale, _schemaToStop);
120+
for (auto & rt : tfs)
121+
{
122+
_pose = rt * _pose;
123+
}
124+
}
125+
126+
UDSTransforms ParseUSDTransform(const pxr::UsdPrim &_prim)
127+
{
128+
auto variant_geom = pxr::UsdGeomGprim(_prim);
129+
auto transforms = variant_geom.GetXformOpOrderAttr();
130+
131+
pxr::GfVec3f scale(1, 1, 1);
132+
pxr::GfVec3f translate(0, 0, 0);
133+
pxr::GfQuatf rotationQuad(1, 0, 0, 0);
134+
135+
UDSTransforms t;
136+
137+
pxr::VtTokenArray xformOpOrder;
138+
transforms.Get(&xformOpOrder);
139+
for (auto & op: xformOpOrder)
140+
{
141+
if (op == "xformOp:scale")
142+
{
143+
auto attribute = _prim.GetAttribute(pxr::TfToken("xformOp:scale"));
144+
if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3f")
145+
{
146+
attribute.Get(&scale);
147+
}
148+
else if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3d")
149+
{
150+
pxr::GfVec3d scaleTmp(1, 1, 1);
151+
attribute.Get(&scaleTmp);
152+
scale[0] = scaleTmp[0];
153+
scale[1] = scaleTmp[1];
154+
scale[2] = scaleTmp[2];
155+
}
156+
t.scale = ignition::math::Vector3d(scale[0], scale[1], scale[2]);
157+
}
158+
else if (op == "xformOp:rotateZYX" || op == "xformOp:rotateXYZ")
159+
{
160+
pxr::GfVec3f rotationEuler(0, 0, 0);
161+
auto attribute = _prim.GetAttribute(pxr::TfToken("xformOp:rotateZYX"));
162+
if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3f")
163+
{
164+
attribute.Get(&rotationEuler);
165+
}
166+
else if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3d")
167+
{
168+
pxr::GfVec3d rotationEulerTmp(0, 0, 0);
169+
attribute.Get(&rotationEulerTmp);
170+
rotationEuler[0] = rotationEulerTmp[0];
171+
rotationEuler[1] = rotationEulerTmp[1];
172+
rotationEuler[2] = rotationEulerTmp[2];
173+
}
174+
ignition::math::Quaterniond qX, qY, qZ;
175+
ignition::math::Angle angleX(rotationEuler[0] * IGN_PI / 180.0);
176+
ignition::math::Angle angleY(rotationEuler[1] * IGN_PI / 180.0);
177+
ignition::math::Angle angleZ(rotationEuler[2] * IGN_PI / 180.0);
178+
qX = ignition::math::Quaterniond(angleX.Normalized().Radian(), 0, 0);
179+
qY = ignition::math::Quaterniond(0, angleY.Normalized().Radian(), 0);
180+
qZ = ignition::math::Quaterniond(0, 0, angleZ.Normalized().Radian());
181+
182+
t.q.push_back(qX);
183+
t.q.push_back(qY);
184+
t.q.push_back(qZ);
185+
t.isRotationZYX = true;
186+
t.isRotation = true;
187+
}
188+
else if (op == "xformOp:translate")
189+
{
190+
auto attribute = _prim.GetAttribute(pxr::TfToken("xformOp:translate"));
191+
if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3f")
192+
{
193+
attribute.Get(&translate);
194+
}
195+
else if (attribute.GetTypeName().GetCPPTypeName() == "GfVec3d")
196+
{
197+
pxr::GfVec3d translateTmp(0, 0, 0);
198+
attribute.Get(&translateTmp);
199+
translate[0] = translateTmp[0];
200+
translate[1] = translateTmp[1];
201+
translate[2] = translateTmp[2];
202+
}
203+
t.translate = ignition::math::Vector3d(translate[0], translate[1], translate[2]);
204+
t.isTranslate = true;
205+
}
206+
else if (op == "xformOp:orient")
207+
{
208+
auto attribute = _prim.GetAttribute(pxr::TfToken("xformOp:orient"));
209+
if (attribute.GetTypeName().GetCPPTypeName() == "GfQuatf")
210+
{
211+
attribute.Get(&rotationQuad);
212+
}
213+
else if (attribute.GetTypeName().GetCPPTypeName() == "GfQuatd")
214+
{
215+
pxr::GfQuatd rotationQuadTmp;
216+
attribute.Get(&rotationQuadTmp);
217+
rotationQuad.SetImaginary(
218+
rotationQuadTmp.GetImaginary()[0],
219+
rotationQuadTmp.GetImaginary()[1],
220+
rotationQuadTmp.GetImaginary()[2]);
221+
rotationQuad.SetReal(rotationQuadTmp.GetReal());
222+
}
223+
ignition::math::Quaterniond q(
224+
rotationQuad.GetReal(),
225+
rotationQuad.GetImaginary()[0],
226+
rotationQuad.GetImaginary()[1],
227+
rotationQuad.GetImaginary()[2]);
228+
t.q.push_back(q);
229+
t.isRotation = true;
230+
}
231+
232+
if (op == "xformOp:transform")
233+
{
234+
// FIXME: Shear is lost (does sdformat support it?).
235+
pxr::GfMatrix4d transform;
236+
_prim.GetAttribute(pxr::TfToken("xformOp:transform")).Get(&transform);
237+
const auto rot = transform.RemoveScaleShear();
238+
const auto scaleShear = transform * rot.GetInverse();
239+
240+
t.scale[0] = scaleShear[0][0];
241+
t.scale[1] = scaleShear[1][1];
242+
t.scale[2] = scaleShear[2][2];
243+
244+
const auto rotQuat = rot.ExtractRotationQuat();
245+
t.translate = ignition::math::Vector3d(transform[3][0], transform[3][1], transform[3][2]);
246+
ignition::math::Quaterniond q(
247+
rotQuat.GetReal(),
248+
rotQuat.GetImaginary()[0],
249+
rotQuat.GetImaginary()[1],
250+
rotQuat.GetImaginary()[2]
251+
);
252+
t.q.push_back(q);
253+
t.isTranslate = true;
254+
t.isRotation = true;
255+
}
256+
}
257+
return t;
258+
}
259+
}
260+
}
261+
}

0 commit comments

Comments
 (0)