Skip to content

Commit fe62c0b

Browse files
Fabien Servantservantftransperfect
authored andcommitted
Create USD Exporter
1 parent 91ead56 commit fe62c0b

File tree

9 files changed

+708
-316
lines changed

9 files changed

+708
-316
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ Production
8080
/vcpkg_installed/
8181
/export/
8282
/.cache/
83-
/compile_commands.json
83+
/compile_commands.json
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
__version__ = "1.0"
2+
3+
from meshroom.core import desc
4+
from meshroom.core.utils import VERBOSE_LEVEL
5+
6+
7+
class exportMeshUSD(desc.AVCommandLineNode):
8+
commandLine = "aliceVision_exportMeshUSD {allParams}"
9+
size = desc.DynamicNodeSize("input")
10+
11+
category = "Utils"
12+
documentation = """ Export a mesh (OBJ file) to USD format. """
13+
14+
inputs = [
15+
desc.File(
16+
name="input",
17+
label="Input",
18+
description="Input mesh file.",
19+
value="",
20+
),
21+
desc.ChoiceParam(
22+
name="fileType",
23+
label="USD File Format",
24+
description="Output USD file format.",
25+
value="usda",
26+
values=["usda", "usdc", "usdz"]
27+
),
28+
desc.ChoiceParam(
29+
name="verboseLevel",
30+
label="Verbose Level",
31+
description="Verbosity level (fatal, error, warning, info, debug, trace).",
32+
values=VERBOSE_LEVEL,
33+
value="info",
34+
),
35+
]
36+
37+
outputs = [
38+
desc.File(
39+
name="output",
40+
label="Output",
41+
description="Path to the output file.",
42+
value="{nodeCacheFolder}/output.{fileTypeValue}",
43+
),
44+
]

meshroom/aliceVision/ExportUSD.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,25 @@ class ExportUSD(desc.AVCommandLineNode):
88
commandLine = "aliceVision_exportUSD {allParams}"
99
size = desc.DynamicNodeSize("input")
1010

11-
category = "Utils"
12-
documentation = """ Export a mesh (OBJ file) to USD format. """
11+
category = "Export"
12+
documentation = """
13+
Convert cameras from an SfM scene into an animated cameras in USD file format.
14+
Based on the input image filenames, it will recognize the input video sequence to create an animated camera.
15+
"""
1316

1417
inputs = [
1518
desc.File(
1619
name="input",
17-
label="Input",
18-
description="Input mesh file.",
20+
label="Input SfMData",
21+
description="SfMData file containing a complete SfM.",
1922
value="",
2023
),
21-
desc.ChoiceParam(
22-
name="fileType",
23-
label="USD File Format",
24-
description="Output USD file format.",
25-
value="usda",
26-
values=["usda", "usdc", "usdz"]
24+
desc.FloatParam(
25+
name="frameRate",
26+
label="Camera Frame Rate",
27+
description="Define the camera's Frames per seconds.",
28+
value=24.0,
29+
range=(1.0, 60.0, 1.0),
2730
),
2831
desc.ChoiceParam(
2932
name="verboseLevel",
@@ -37,8 +40,8 @@ class ExportUSD(desc.AVCommandLineNode):
3740
outputs = [
3841
desc.File(
3942
name="output",
40-
label="Output",
41-
description="Path to the output file.",
42-
value="{nodeCacheFolder}/output.{fileTypeValue}",
43-
),
43+
label="USD filename",
44+
description="Output usd filename",
45+
value="{nodeCacheFolder}/animated.usda",
46+
)
4447
]

src/aliceVision/sfmDataIO/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ if (ALICEVISION_HAVE_ALEMBIC)
3737
)
3838
endif()
3939

40+
if (ALICEVISION_HAVE_USD)
41+
42+
list(APPEND sfmDataIO_files_headers
43+
UsdExporter.hpp
44+
)
45+
list(APPEND sfmDataIO_files_sources
46+
UsdExporter.cpp
47+
)
48+
endif()
49+
4050
alicevision_add_library(aliceVision_sfmDataIO
4151
SOURCES ${sfmDataIO_files_headers} ${sfmDataIO_files_sources}
4252
PUBLIC_LINKS
@@ -60,6 +70,17 @@ if (ALICEVISION_HAVE_ALEMBIC)
6070
)
6171
endif()
6272

73+
if (ALICEVISION_HAVE_USD)
74+
target_link_libraries(aliceVision_sfmDataIO
75+
PRIVATE usd
76+
usdGeom
77+
gf
78+
tf
79+
vt
80+
sdf
81+
)
82+
endif()
83+
6384
# Unit tests
6485

6586
alicevision_add_test(sfmDataIO_test.cpp
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#include <aliceVision/sfmDataIO/UsdExporter.hpp>
8+
#include <aliceVision/camera/IntrinsicScaleOffset.hpp>
9+
#include <aliceVision/system/Logger.hpp>
10+
11+
#include <pxr/usd/usd/stage.h>
12+
13+
#include <pxr/usd/usdGeom/xform.h>
14+
#include <pxr/usd/usdGeom/points.h>
15+
#include <pxr/usd/usdGeom/camera.h>
16+
17+
#include <pxr/base/gf/vec3f.h>
18+
#include <pxr/base/vt/array.h>
19+
20+
21+
PXR_NAMESPACE_USING_DIRECTIVE
22+
23+
namespace aliceVision {
24+
namespace sfmDataIO {
25+
26+
27+
UsdExporter::UsdExporter(const std::string & filename, double frameRate)
28+
{
29+
_stage = UsdStage::CreateNew(filename);
30+
31+
UsdGeomXform worldPrim = UsdGeomXform::Define(_stage, SdfPath("/World"));
32+
33+
_stage->SetTimeCodesPerSecond(frameRate);
34+
_stage->SetFramesPerSecond(frameRate);
35+
_startTimeCode = std::numeric_limits<IndexT>::max();
36+
_endTimeCode = 0;
37+
}
38+
39+
void UsdExporter::terminate()
40+
{
41+
_stage->SetStartTimeCode(_startTimeCode);
42+
_stage->SetEndTimeCode(_endTimeCode);
43+
44+
_stage->Save();
45+
}
46+
47+
void UsdExporter::createNewCamera(const std::string & cameraName)
48+
{
49+
SdfPath cameraPath("/World/" + cameraName);
50+
UsdGeomCamera camera = UsdGeomCamera::Define(_stage, cameraPath);
51+
52+
UsdAttribute projectionAttr = camera.GetProjectionAttr();
53+
projectionAttr.Set(UsdGeomTokens->perspective);
54+
55+
UsdGeomXformable xformable(camera);
56+
UsdGeomXformOp motion = xformable.MakeMatrixXform();
57+
GfMatrix4d identity(1.0);
58+
motion.Set(identity);
59+
}
60+
61+
void UsdExporter::addFrame(const std::string & cameraName, const sfmData::CameraPose & pose, const camera::Pinhole & intrinsic, IndexT frameId)
62+
{
63+
SdfPath cameraPath("/World/" + cameraName);
64+
UsdGeomCamera camera = UsdGeomCamera::Get(_stage, cameraPath);
65+
66+
_startTimeCode = std::min(_startTimeCode, frameId);
67+
_endTimeCode = std::max(_endTimeCode, frameId);
68+
69+
UsdAttribute focalLengthAttr = camera.GetFocalLengthAttr();
70+
UsdAttribute horizontalApertureAttr = camera.GetHorizontalApertureAttr();
71+
UsdAttribute verticalApertureAttr = camera.GetVerticalApertureAttr();
72+
UsdAttribute horizontalApertureOffsetAttr = camera.GetHorizontalApertureOffsetAttr();
73+
UsdAttribute verticalApertureOffsetAttr = camera.GetVerticalApertureOffsetAttr();
74+
75+
horizontalApertureAttr.Set(static_cast<float>(intrinsic.sensorWidth()));
76+
verticalApertureAttr.Set(static_cast<float>(intrinsic.sensorHeight()));
77+
78+
UsdTimeCode t(frameId);
79+
double pixToMillimeters = intrinsic.sensorWidth() / intrinsic.w();
80+
81+
horizontalApertureOffsetAttr.Set(static_cast<float>(intrinsic.getOffset().x() * pixToMillimeters), t);
82+
verticalApertureOffsetAttr.Set(static_cast<float>(intrinsic.getOffset().y() * pixToMillimeters), t);
83+
focalLengthAttr.Set(static_cast<float>(intrinsic.getFocalLength()), t);
84+
85+
86+
87+
//Transform sfmData pose to usd pose
88+
Eigen::Matrix4d glTransform = Eigen::Matrix4d::Identity();
89+
glTransform(1, 1) = -1.0;
90+
glTransform(2, 2) = -1.0;
91+
92+
// Inverse the pose and change the geometric frame
93+
Eigen::Matrix4d camera_T_world = pose.getTransform().getHomogeneous();
94+
Eigen::Matrix4d world_T_camera = camera_T_world.inverse();
95+
Eigen::Matrix4d world_gl_T_camera_gl = glTransform * world_T_camera * glTransform;
96+
97+
//Copy element by element while transposing
98+
GfMatrix4d usdT;
99+
for (int i = 0; i < 4; i++)
100+
{
101+
for (int j = 0; j < 4; j++)
102+
{
103+
usdT[j][i] = world_gl_T_camera_gl(i, j);
104+
}
105+
}
106+
107+
//Assign pose to motion
108+
UsdGeomXformable xformable(camera);
109+
bool dummy = false;
110+
std::vector<UsdGeomXformOp> xformOps = xformable.GetOrderedXformOps(&dummy);
111+
112+
113+
if (!xformOps.empty()) {
114+
UsdGeomXformOp motion = xformOps[0];
115+
motion.Set(usdT, t);
116+
}
117+
}
118+
119+
} // namespace sfmDataIO
120+
} // namespace aliceVision
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#pragma once
8+
9+
#include <aliceVision/sfmData/SfMData.hpp>
10+
#include <aliceVision/camera/Pinhole.hpp>
11+
#include <pxr/usd/usd/stage.h>
12+
13+
namespace aliceVision {
14+
namespace sfmDataIO {
15+
16+
class UsdExporter
17+
{
18+
public:
19+
UsdExporter(const std::string & filename, double frameRate);
20+
21+
void createNewCamera(const std::string & cameraName);
22+
23+
void addFrame(const std::string & cameraName, const sfmData::CameraPose & pose, const camera::Pinhole & camera, IndexT frameId);
24+
25+
void terminate();
26+
27+
private:
28+
pxr::UsdStageRefPtr _stage;
29+
IndexT _startTimeCode;
30+
IndexT _endTimeCode;
31+
};
32+
33+
} // namespace sfmDataIO
34+
} // namespace aliceVision

src/software/export/CMakeLists.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ if (ALICEVISION_BUILD_SFM)
202202

203203
# Export geometry and textures as USD
204204
if (ALICEVISION_HAVE_USD)
205-
alicevision_add_software(aliceVision_exportUSD
206-
SOURCE main_exportUSD.cpp
205+
alicevision_add_software(aliceVision_exportMeshUSD
206+
SOURCE main_exportMeshUSD.cpp
207207
FOLDER ${FOLDER_SOFTWARE_EXPORT}
208208
LINKS aliceVision_system
209209
aliceVision_cmdline
@@ -214,6 +214,18 @@ if (ALICEVISION_BUILD_SFM)
214214
usdImaging
215215
usdShade
216216
)
217+
218+
alicevision_add_software(aliceVision_exportUSD
219+
SOURCE main_exportUSD.cpp
220+
FOLDER ${FOLDER_SOFTWARE_EXPORT}
221+
LINKS aliceVision_system
222+
aliceVision_cmdline
223+
aliceVision_sfmData
224+
aliceVision_sfmDataIO
225+
Boost::program_options
226+
Boost::boost
227+
usd
228+
)
217229
endif()
218230

219231
# Export distortion to be used in external tools

0 commit comments

Comments
 (0)