From b973fb22e93f04a9a964456ef35cd210975ab991 Mon Sep 17 00:00:00 2001 From: Denis Kovacs Date: Tue, 26 Sep 2023 19:51:42 +0900 Subject: [PATCH 1/2] fixes to USD camera export/import for correct round-tripping. --- .../io/usd/intern/usd_reader_camera.cc | 25 +++++++----- .../io/usd/intern/usd_writer_camera.cc | 40 ++++++++++--------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/source/blender/io/usd/intern/usd_reader_camera.cc b/source/blender/io/usd/intern/usd_reader_camera.cc index 748eeca7025..65a7dd3e342 100644 --- a/source/blender/io/usd/intern/usd_reader_camera.cc +++ b/source/blender/io/usd/intern/usd_reader_camera.cc @@ -60,22 +60,27 @@ void USDCameraReader::read_object_data(Main *bmain, const double motionSampleTim /* * For USD, these camera properties are in tenths of a world unit. * https://graphics.pixar.com/usd/release/api/class_usd_geom_camera.html#UsdGeom_CameraUnits - * tenth_of_unit = stage_meters_per_unit / 10 - * val_in_meters = val.Get() * tenth_of_unit - * val_in_millimeters = val_in_meters * 1000 + * + * tenth_unit_to_meters = stage_meters_per_unit / 10 + * tenth_unit_to_millimeters = 1000 * unit_to_tenth_unit + * = 100 * stage_meters_per_unit */ - const double scale_to_mm = 100.0 * settings_->stage_meters_per_unit; - bcam->lens = val.Get() * scale_to_mm; - bcam->sensor_x = horAp.Get() * scale_to_mm; - bcam->sensor_y = verAp.Get() * scale_to_mm; - bcam->shiftx = verApOffset.Get() * scale_to_mm; - bcam->shifty = horApOffset.Get() * scale_to_mm; + const double tenth_unit_to_millimeters = 100.0 * settings_->stage_meters_per_unit; + bcam->lens = val.Get() * tenth_unit_to_millimeters; + bcam->sensor_x = horAp.Get() * tenth_unit_to_millimeters; + bcam->sensor_y = verAp.Get() * tenth_unit_to_millimeters; + + bcam->sensor_fit = bcam->sensor_x >= bcam->sensor_y ? CAMERA_SENSOR_FIT_HOR : CAMERA_SENSOR_FIT_VERT; + + float sensor_size = bcam->sensor_x >= bcam->sensor_y ? bcam->sensor_x : bcam->sensor_y; + bcam->shiftx = (horApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; + bcam->shifty = (verApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; bcam->type = (projectionVal.Get().GetString() == "perspective") ? CAM_PERSP : CAM_ORTHO; /* Calling UncheckedGet() to silence compiler warnings. */ - bcam->clip_start = max_ff(0.1f, clippingRangeVal.UncheckedGet()[0]); + bcam->clip_start = max_ff(1e-6f, clippingRangeVal.UncheckedGet()[0]); // see rna_camera.cc, "clip_start": RNA_def_property_range(prop, 1e-6f, FLT_MAX) bcam->clip_end = clippingRangeVal.UncheckedGet()[1]; bcam->dof.focus_distance = focalDistanceVal.Get(); diff --git a/source/blender/io/usd/intern/usd_writer_camera.cc b/source/blender/io/usd/intern/usd_writer_camera.cc index a913e93aa9a..2a43ec88e05 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.cc +++ b/source/blender/io/usd/intern/usd_writer_camera.cc @@ -25,6 +25,7 @@ bool USDCameraWriter::is_supported(const HierarchyContext *context) const static void camera_sensor_size_for_render(const Camera *camera, const RenderData *rd, + float *r_sensor, float *r_sensor_x, float *r_sensor_y) { @@ -33,15 +34,17 @@ static void camera_sensor_size_for_render(const Camera *camera, float sizey = rd->ysch * rd->yasp; int sensor_fit = BKE_camera_sensor_fit(camera->sensor_fit, sizex, sizey); + float sensor_size = BKE_camera_sensor_size(camera->sensor_fit, camera->sensor_x, camera->sensor_y); + *r_sensor = sensor_size; switch (sensor_fit) { case CAMERA_SENSOR_FIT_HOR: - *r_sensor_x = camera->sensor_x; - *r_sensor_y = camera->sensor_x * sizey / sizex; + *r_sensor_x = sensor_size; + *r_sensor_y = sensor_size * sizey / sizex; break; case CAMERA_SENSOR_FIT_VERT: - *r_sensor_x = camera->sensor_y * sizex / sizey; - *r_sensor_y = camera->sensor_y; + *r_sensor_x = sensor_size * sizex / sizey; + *r_sensor_y = sensor_size; break; case CAMERA_SENSOR_FIT_AUTO: BLI_assert_msg(0, "Camera fit should be either horizontal or vertical"); @@ -60,21 +63,21 @@ void USDCameraWriter::do_write(HierarchyContext &context) usd_camera.CreateProjectionAttr().Set(pxr::UsdGeomTokens->perspective); - /* USD stores the focal length in "millimeters or tenths of world units", because at some point - * they decided world units might be centimeters. Quite confusing, as the USD Viewer shows the - * correct FoV when we write millimeters and not "tenths of world units". - */ - usd_camera.CreateFocalLengthAttr().Set(camera->lens, timecode); + /* + * tenth_unit_to_meters = stage_meters_per_unit / 10 + * tenth_unit_to_millimeters = 1000 * unit_to_tenth_unit + * = 100 * stage_meters_per_unit + */ + const float tenth_unit_to_mm = 100.0f * scene->unit.scale_length; - float aperture_x, aperture_y; - camera_sensor_size_for_render(camera, &scene->r, &aperture_x, &aperture_y); + float sensor_size, aperture_x, aperture_y; + camera_sensor_size_for_render(camera, &scene->r, &sensor_size, &aperture_x, &aperture_y); - float film_aspect = aperture_x / aperture_y; - usd_camera.CreateHorizontalApertureAttr().Set(aperture_x, timecode); - usd_camera.CreateVerticalApertureAttr().Set(aperture_y, timecode); - usd_camera.CreateHorizontalApertureOffsetAttr().Set(aperture_x * camera->shiftx, timecode); - usd_camera.CreateVerticalApertureOffsetAttr().Set(aperture_y * camera->shifty * film_aspect, - timecode); + usd_camera.CreateFocalLengthAttr().Set(camera->lens / tenth_unit_to_mm, timecode); + usd_camera.CreateHorizontalApertureAttr().Set(aperture_x / tenth_unit_to_mm, timecode); + usd_camera.CreateVerticalApertureAttr().Set(aperture_y / tenth_unit_to_mm, timecode); + usd_camera.CreateHorizontalApertureOffsetAttr().Set(sensor_size * camera->shiftx / tenth_unit_to_mm, timecode); + usd_camera.CreateVerticalApertureOffsetAttr().Set(sensor_size * camera->shifty / tenth_unit_to_mm, timecode); usd_camera.CreateClippingRangeAttr().Set( pxr::VtValue(pxr::GfVec2f(camera->clip_start, camera->clip_end)), timecode); @@ -83,8 +86,7 @@ void USDCameraWriter::do_write(HierarchyContext &context) if (camera->dof.flag & CAM_DOF_ENABLED) { usd_camera.CreateFStopAttr().Set(camera->dof.aperture_fstop, timecode); - float focus_distance = scene->unit.scale_length * - BKE_camera_object_dof_distance(context.object); + float focus_distance = BKE_camera_object_dof_distance(context.object); usd_camera.CreateFocusDistanceAttr().Set(focus_distance, timecode); } } -- 2.30.2 From 1461b1fc3ab8e301939084d247ca8ef782bfaf16 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 4 Oct 2023 19:29:37 +0200 Subject: [PATCH 2/2] clang-format, tweak comments, update test --- .../io/usd/intern/usd_reader_camera.cc | 11 +++++----- .../io/usd/intern/usd_writer_camera.cc | 22 ++++++++++++------- tests/python/bl_usd_import_test.py | 8 +++---- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/source/blender/io/usd/intern/usd_reader_camera.cc b/source/blender/io/usd/intern/usd_reader_camera.cc index 093fd8021ef..24cc22449e0 100644 --- a/source/blender/io/usd/intern/usd_reader_camera.cc +++ b/source/blender/io/usd/intern/usd_reader_camera.cc @@ -70,17 +70,18 @@ void USDCameraReader::read_object_data(Main *bmain, const double motionSampleTim bcam->sensor_x = horAp.Get() * tenth_unit_to_millimeters; bcam->sensor_y = verAp.Get() * tenth_unit_to_millimeters; - bcam->sensor_fit = bcam->sensor_x >= bcam->sensor_y ? CAMERA_SENSOR_FIT_HOR : CAMERA_SENSOR_FIT_VERT; + bcam->sensor_fit = bcam->sensor_x >= bcam->sensor_y ? CAMERA_SENSOR_FIT_HOR : + CAMERA_SENSOR_FIT_VERT; float sensor_size = bcam->sensor_x >= bcam->sensor_y ? bcam->sensor_x : bcam->sensor_y; - bcam->shiftx = (horApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; - bcam->shifty = (verApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; + bcam->shiftx = (horApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; + bcam->shifty = (verApOffset.Get() * tenth_unit_to_millimeters) / sensor_size; bcam->type = (projectionVal.Get().GetString() == "perspective") ? CAM_PERSP : CAM_ORTHO; - /* Calling UncheckedGet() to silence compiler warnings. */ - bcam->clip_start = max_ff(1e-6f, clippingRangeVal.UncheckedGet()[0]); // see rna_camera.cc, "clip_start": RNA_def_property_range(prop, 1e-6f, FLT_MAX) + /* Call UncheckedGet() to silence compiler warnings. + * Clamp to 1e-6 matching range defined in RNA. */ bcam->clip_end = clippingRangeVal.UncheckedGet()[1]; bcam->dof.focus_distance = focalDistanceVal.Get(); diff --git a/source/blender/io/usd/intern/usd_writer_camera.cc b/source/blender/io/usd/intern/usd_writer_camera.cc index 2a43ec88e05..173ea4c4fc4 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.cc +++ b/source/blender/io/usd/intern/usd_writer_camera.cc @@ -34,7 +34,8 @@ static void camera_sensor_size_for_render(const Camera *camera, float sizey = rd->ysch * rd->yasp; int sensor_fit = BKE_camera_sensor_fit(camera->sensor_fit, sizex, sizey); - float sensor_size = BKE_camera_sensor_size(camera->sensor_fit, camera->sensor_x, camera->sensor_y); + float sensor_size = BKE_camera_sensor_size( + camera->sensor_fit, camera->sensor_x, camera->sensor_y); *r_sensor = sensor_size; switch (sensor_fit) { @@ -63,11 +64,14 @@ void USDCameraWriter::do_write(HierarchyContext &context) usd_camera.CreateProjectionAttr().Set(pxr::UsdGeomTokens->perspective); - /* - * tenth_unit_to_meters = stage_meters_per_unit / 10 - * tenth_unit_to_millimeters = 1000 * unit_to_tenth_unit - * = 100 * stage_meters_per_unit - */ + /* + * For USD, these camera properties are in tenths of a world unit. + * https://graphics.pixar.com/usd/release/api/class_usd_geom_camera.html#UsdGeom_CameraUnits + * + * tenth_unit_to_meters = stage_meters_per_unit / 10 + * tenth_unit_to_millimeters = 1000 * unit_to_tenth_unit + * = 100 * stage_meters_per_unit + */ const float tenth_unit_to_mm = 100.0f * scene->unit.scale_length; float sensor_size, aperture_x, aperture_y; @@ -76,8 +80,10 @@ void USDCameraWriter::do_write(HierarchyContext &context) usd_camera.CreateFocalLengthAttr().Set(camera->lens / tenth_unit_to_mm, timecode); usd_camera.CreateHorizontalApertureAttr().Set(aperture_x / tenth_unit_to_mm, timecode); usd_camera.CreateVerticalApertureAttr().Set(aperture_y / tenth_unit_to_mm, timecode); - usd_camera.CreateHorizontalApertureOffsetAttr().Set(sensor_size * camera->shiftx / tenth_unit_to_mm, timecode); - usd_camera.CreateVerticalApertureOffsetAttr().Set(sensor_size * camera->shifty / tenth_unit_to_mm, timecode); + usd_camera.CreateHorizontalApertureOffsetAttr().Set( + sensor_size * camera->shiftx / tenth_unit_to_mm, timecode); + usd_camera.CreateVerticalApertureOffsetAttr().Set( + sensor_size * camera->shifty / tenth_unit_to_mm, timecode); usd_camera.CreateClippingRangeAttr().Set( pxr::VtValue(pxr::GfVec2f(camera->clip_start, camera->clip_end)), timecode); diff --git a/tests/python/bl_usd_import_test.py b/tests/python/bl_usd_import_test.py index 8aee8e6073b..ad3fbd31ec0 100644 --- a/tests/python/bl_usd_import_test.py +++ b/tests/python/bl_usd_import_test.py @@ -183,8 +183,8 @@ class USDImportTest(AbstractUSDTest): self.assertAlmostEqual(43.12, test_cam.lens, 2) self.assertAlmostEqual(24.89, test_cam.sensor_width, 2) self.assertAlmostEqual(14.00, test_cam.sensor_height, 2) - self.assertAlmostEqual(12.34, test_cam.shift_x, 2) - self.assertAlmostEqual(56.78, test_cam.shift_y, 2) + self.assertAlmostEqual(2.281, test_cam.shift_x, 2) + self.assertAlmostEqual(0.496, test_cam.shift_y, 2) bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() @@ -200,8 +200,8 @@ class USDImportTest(AbstractUSDTest): self.assertAlmostEqual(4.312, test_cam.lens, 3) self.assertAlmostEqual(2.489, test_cam.sensor_width, 3) self.assertAlmostEqual(1.400, test_cam.sensor_height, 3) - self.assertAlmostEqual(1.234, test_cam.shift_x, 3) - self.assertAlmostEqual(5.678, test_cam.shift_y, 3) + self.assertAlmostEqual(2.281, test_cam.shift_x, 3) + self.assertAlmostEqual(0.496, test_cam.shift_y, 3) def test_import_shader_varname_with_connection(self): """Test importing USD shader where uv primvar is a connection""" -- 2.30.2