Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exposure controls to UsdGeomCamera #3085

Open
wants to merge 30 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
22437dc
Add exposure controls to UsdGeomCamera
anderslanglands May 14, 2024
8ae7ff8
feed calculated exposure scale to HdCamera::GetExposure() via UsdImag…
anderslanglands May 14, 2024
0dea7ef
add additional doc comments explaining the exposure attributes and th…
anderslanglands May 16, 2024
dc65e05
docs clarifications
anderslanglands May 28, 2024
c3ad145
rename f-number to f-stop
anderslanglands Jun 10, 2024
cdbe0c5
add definition of nits
anderslanglands Jun 11, 2024
f9a8c8c
add units for imaging ratio
anderslanglands Jun 11, 2024
29f6b34
fix dimensions and further clarify exposure scale
anderslanglands Jun 16, 2024
aa9e5f1
fix spelling on steradian
anderslanglands Jun 24, 2024
c75aea4
fix formatting to backticks and format fStop reference
anderslanglands Jun 24, 2024
50cea0a
convert exposure scale to logarithmic exposure in adapter.
anderslanglands Jul 26, 2024
1d5c60a
replace f-number with f-stop
anderslanglands Sep 6, 2024
4ab55da
add note pointing to physLight doc and explaning the form of the equa…
anderslanglands Sep 6, 2024
425382e
update generated schema
anderslanglands Sep 6, 2024
3749e6b
add initialization for exposure fields
anderslanglands Sep 6, 2024
21d8899
Pixar schema tweaks: rename 'GetExposureScale' to 'ComputeLinearExpos…
Nov 22, 2024
2f668a6
Add exposure parameters to hydra camera schema
Nov 22, 2024
a33a85a
Add UsdImaging 2.0 support for exposure, update UsdImaging usage of U…
Nov 22, 2024
92cd975
Merge pull request #1 from tcauchois/usdGeomCamera-exposure
pmolodo Dec 9, 2024
b5d9f08
add missing camera exposure documentation in usdGeom/generatedSchema.…
pmolodo Dec 9, 2024
f574fd4
rename 'GetExposureScale' to 'ComputeLinearExposureScale' - python wr…
pmolodo Dec 9, 2024
43b89cd
Merge remote-tracking branch 'origin/dev' into usdGeomCamera-exposure
pmolodo Dec 10, 2024
4a929d4
Exposure: simplify hydra-USD mapping
pmolodo Dec 10, 2024
e916b3e
testUsdGeomCamera.test_ComputeLinearExposureScale fixes
pmolodo Dec 10, 2024
0ae21ac
bugfix for UsdImagingCameraAdapter::Get(exposureScale)
pmolodo Dec 11, 2024
7e94c68
avoid copying TfToken in loop
pmolodo Dec 11, 2024
95e2cad
undo accidental cmake version bump
pmolodo Dec 11, 2024
36becba
fix initial value of HdCamera::_exposureScale (1.0, not 0.0)
pmolodo Dec 18, 2024
846dd7f
rename tokens from exposureScale to linearExposureScale
pmolodo Dec 18, 2024
07496b0
change all instances of "exposureScale" to "linearExposureScale"
pmolodo Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pxr/imaging/hd/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,41 @@ HdCamera::Sync(HdSceneDelegate * sceneDelegate,
_exposure = vExposure.Get<float>();
}

const VtValue vExposureCompensation =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add initialization for all of these member variables in the HdCamera constructor (following the pattern for _exposure).

sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->exposureCompensation);
if (!vExposureCompensation.IsEmpty()) {
_exposureCompensation = vExposureCompensation.Get<float>();
}

const VtValue vExposureTime =
sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->exposureTime);
if (!vExposureTime.IsEmpty()) {
_exposureTime = vExposureTime.Get<float>();
}

const VtValue vExposureIso =
sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->exposureIso);
if (!vExposureIso.IsEmpty()) {
_exposureIso = vExposureIso.Get<float>();
}

const VtValue vExposureFNumber =
sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->exposureFNumber);
if (!vExposureFNumber.IsEmpty()) {
_exposureFNumber = vExposureFNumber.Get<float>();
}

const VtValue vExposureResponsivity =
sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->exposureResponsivity);
if (!vExposureResponsivity.IsEmpty()) {
_exposureResponsivity = vExposureResponsivity.Get<float>();
}

const VtValue vLensDistortionType =
sceneDelegate->GetCameraParamValue(
id, HdCameraTokens->lensDistortionType);
Expand Down
14 changes: 13 additions & 1 deletion pxr/imaging/hd/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ PXR_NAMESPACE_OPEN_SCOPE
(shutterOpen) \
(shutterClose) \
(exposure) \
(exposureTime) \
(exposureIso) \
(exposureFNumber) \
(exposureResponsivity) \
(exposureCompensation) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new params are missing from the hydra camera schema: https://github.com/PixarAnimationStudios/OpenUSD/blob/release/pxr/imaging/hd/cameraSchema.h ... as well as the two modes of scene index emulation:
https://github.com/PixarAnimationStudios/OpenUSD/blob/release/pxr/imaging/hd/dataSourceLegacyPrim.cpp#L1036
... and ...
https://github.com/PixarAnimationStudios/OpenUSD/blob/release/pxr/imaging/hd/sceneIndexAdapterSceneDelegate.cpp#L1237

... although it looks like for those, since you aren't doing any weird type conversion, the fallbacks might be ok and if you just add the names to dataSourceLegacyPrim.cpp that'll be enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tcauchois - since I see you've already implemented some of the other related stuff, I'm guessing you've already made the changes to hd/hdSchemaDefs.py that would address this? If not, I'm happy to push these fixes myself.

One note - while testing this, I noticed that hdGenSchema.py requires jinja2 >= 3.0 - I'll make a separate PR updating that in VERSIONS.md.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the separate PR to update the jinja2 req:

#3314

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the schemaDefs changes already; I think modulo the discussions downthread about ComputeLinearExposureScale and changing the transport tokens, this is almost ready to go. Thanks for the VERSIONS.md update!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tcauchois just to be really clear here: are you saying the only update to this PR you require from us is the rework of the exposure scale calculation to be moved to a separate function on HdCamera that gives the (linear) value from UsdGeomCamera::ComputeExposureScale(), and return HdCamera::GetExposure() to its original behaviour?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pulled this down and added the Hydra 2 functionality and started reconciling issues with closed source code. My plan was to take the PR with my additions, plus the changes mentioned (ComputeExposureScale and the different tokens), if that's ok with you, in which case there's no further action required on your part. If you'd like me to upload my changes as a new PR instead, for you all to look at or iterate on, let me know.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great if you could just so we can all see what’s actually going in

\
/* how to match window with different aspect */ \
(windowPolicy) \
Expand Down Expand Up @@ -330,10 +335,17 @@ class HdCamera : public HdSprim
float _splitDiopterWidth2;
float _splitDiopterFocusDistance2;

// shutter/lighting
// shutter
double _shutterOpen;
double _shutterClose;

// exposure
float _exposure;
float _exposureCompensation;
float _exposureTime;
float _exposureIso;
float _exposureFNumber;
float _exposureResponsivity;

// lens distortion
TfToken _lensDistortionType;
Expand Down
91 changes: 91 additions & 0 deletions pxr/usd/usdGeom/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,74 @@ UsdGeomCamera::CreateExposureAttr(VtValue const &defaultValue, bool writeSparsel
writeSparsely);
}

UsdAttribute
UsdGeomCamera::GetExposureIsoAttr() const
{
return GetPrim().GetAttribute(UsdGeomTokens->exposureIso);
}

UsdAttribute
UsdGeomCamera::CreateExposureIsoAttr(VtValue const &defaultValue, bool writeSparsely) const
{
return UsdSchemaBase::_CreateAttr(UsdGeomTokens->exposureIso,
SdfValueTypeNames->Float,
/* custom = */ false,
SdfVariabilityVarying,
defaultValue,
writeSparsely);
}

UsdAttribute
UsdGeomCamera::GetExposureTimeAttr() const
{
return GetPrim().GetAttribute(UsdGeomTokens->exposureTime);
}

UsdAttribute
UsdGeomCamera::CreateExposureTimeAttr(VtValue const &defaultValue, bool writeSparsely) const
{
return UsdSchemaBase::_CreateAttr(UsdGeomTokens->exposureTime,
SdfValueTypeNames->Float,
/* custom = */ false,
SdfVariabilityVarying,
defaultValue,
writeSparsely);
}

UsdAttribute
UsdGeomCamera::GetExposureFNumberAttr() const
{
return GetPrim().GetAttribute(UsdGeomTokens->exposureFNumber);
}

UsdAttribute
UsdGeomCamera::CreateExposureFNumberAttr(VtValue const &defaultValue, bool writeSparsely) const
{
return UsdSchemaBase::_CreateAttr(UsdGeomTokens->exposureFNumber,
SdfValueTypeNames->Float,
/* custom = */ false,
SdfVariabilityVarying,
defaultValue,
writeSparsely);
}

UsdAttribute
UsdGeomCamera::GetExposureResponsivityAttr() const
{
return GetPrim().GetAttribute(UsdGeomTokens->exposureResponsivity);
}

UsdAttribute
UsdGeomCamera::CreateExposureResponsivityAttr(VtValue const &defaultValue, bool writeSparsely) const
{
return UsdSchemaBase::_CreateAttr(UsdGeomTokens->exposureResponsivity,
SdfValueTypeNames->Float,
/* custom = */ false,
SdfVariabilityVarying,
defaultValue,
writeSparsely);
}

namespace {
static inline TfTokenVector
_ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right)
Expand Down Expand Up @@ -372,6 +440,10 @@ UsdGeomCamera::GetSchemaAttributeNames(bool includeInherited)
UsdGeomTokens->shutterOpen,
UsdGeomTokens->shutterClose,
UsdGeomTokens->exposure,
UsdGeomTokens->exposureIso,
UsdGeomTokens->exposureTime,
UsdGeomTokens->exposureFNumber,
UsdGeomTokens->exposureResponsivity,
};
static TfTokenVector allNames =
_ConcatenateAttributeNames(
Expand Down Expand Up @@ -581,4 +653,23 @@ UsdGeomCamera::SetFromCamera(const GfCamera &camera, const UsdTimeCode &time)
GetFocusDistanceAttr().Set(camera.GetFocusDistance(), time);
}

float
UsdGeomCamera::GetExposureScale(UsdTimeCode time) const
anderslanglands marked this conversation as resolved.
Show resolved Hide resolved
{
float exposureTime = 1.0f;
float exposureIso = 100.0f;
float exposureFNumber = 1.0f;
float exposureResponsivity = 1.0f;
float exposureCompensation = 0.0f;

GetExposureTimeAttr().Get(&exposureTime, time);
GetExposureIsoAttr().Get(&exposureIso, time);
GetExposureFNumberAttr().Get(&exposureFNumber, time);
GetExposureResponsivityAttr().Get(&exposureResponsivity, time);
GetExposureAttr().Get(&exposureCompensation, time);

return (exposureTime * exposureIso * powf(2.0f, exposureCompensation) *
exposureResponsivity) / (100.0f * exposureFNumber * exposureFNumber);
}

PXR_NAMESPACE_CLOSE_SCOPE
111 changes: 108 additions & 3 deletions pxr/usd/usdGeom/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ class UsdGeomCamera : public UsdGeomXformable
// --------------------------------------------------------------------- //
// FSTOP
// --------------------------------------------------------------------- //
/// Lens aperture. Defaults to 0.0, which turns off focusing.
/// Lens aperture. Defaults to 0.0, which turns off depth of field effects.
///
/// | ||
/// | -- | -- |
Expand Down Expand Up @@ -491,7 +491,7 @@ class UsdGeomCamera : public UsdGeomXformable
/// Frame relative shutter close time, analogous comments from
/// shutter:open apply. A value greater or equal to shutter:open
/// should be authored, otherwise there is no exposure and a
/// renderer should produce a black image.
/// renderer should produce a black image. Used for motion blur.
///
/// | ||
/// | -- | -- |
Expand All @@ -513,7 +513,7 @@ class UsdGeomCamera : public UsdGeomXformable
// --------------------------------------------------------------------- //
// EXPOSURE
// --------------------------------------------------------------------- //
/// Exposure adjustment, as a log base-2 value. The default
/// Exposure compensation, as a log base-2 value. The default
/// of 0.0 has no effect. A value of 1.0 will double the
/// image-plane intensities in a rendered image; a value of
/// -1.0 will halve them.
Expand All @@ -534,6 +534,99 @@ class UsdGeomCamera : public UsdGeomXformable
USDGEOM_API
UsdAttribute CreateExposureAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const;

public:
// --------------------------------------------------------------------- //
// EXPOSUREISO
// --------------------------------------------------------------------- //
/// The speed rating of the sensor or film when calculating exposure.
/// Higher numbers give a brighter image, lower numbers darker.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float exposure:iso = 100` |
/// | C++ Type | float |
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float |
USDGEOM_API
UsdAttribute GetExposureIsoAttr() const;

/// See GetExposureIsoAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
USDGEOM_API
UsdAttribute CreateExposureIsoAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const;

public:
// --------------------------------------------------------------------- //
// EXPOSURETIME
// --------------------------------------------------------------------- //
/// Time in seconds that the sensor is exposed to light when calculating exposure.
/// Longer exposure times create a brighter image, shorter times darker.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float exposure:time = 1` |
/// | C++ Type | float |
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float |
USDGEOM_API
UsdAttribute GetExposureTimeAttr() const;

/// See GetExposureTimeAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
USDGEOM_API
UsdAttribute CreateExposureTimeAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const;

public:
// --------------------------------------------------------------------- //
// EXPOSUREFNUMBER
// --------------------------------------------------------------------- //
/// f-number of the aperture when calculating exposure. Smaller numbers
/// create a brighter image, larger numbers darker.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float exposure:fNumber = 1` |
/// | C++ Type | float |
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float |
USDGEOM_API
UsdAttribute GetExposureFNumberAttr() const;

/// See GetExposureFNumberAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
USDGEOM_API
UsdAttribute CreateExposureFNumberAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const;

public:
// --------------------------------------------------------------------- //
// EXPOSURERESPONSIVITY
// --------------------------------------------------------------------- //
/// Scalar multiplier representing overall responsivity of the
/// sensor system to light when calculating exposure. Intended to be
/// used as a per camera/lens system measured scaling value.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float exposure:responsivity = 1` |
/// | C++ Type | float |
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float |
USDGEOM_API
UsdAttribute GetExposureResponsivityAttr() const;

/// See GetExposureResponsivityAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
USDGEOM_API
UsdAttribute CreateExposureResponsivityAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const;

public:
// ===================================================================== //
// Feel free to add custom code below this line, it will be preserved by
Expand Down Expand Up @@ -574,6 +667,18 @@ class UsdGeomCamera : public UsdGeomXformable
///
USDGEOM_API
void SetFromCamera(const GfCamera &camera, const UsdTimeCode &time);

/// Computes the imaging ratio, i.e. the ratio between incident luminance and
/// photometric exposure (in lux-seconds), given the exposure, exposure:iso,
/// exposure:fnumber, exposure:time and exposure:responsivity attributes.
///
/// This is expected to be applied as a multiplier to the brightness of the
/// image generated by the renderer, and given physically meaningful lighting
/// values in the scene, allows the exposure controls on UsdGeomCamera to behave
/// like those of a real camera.
///
USDGEOM_API
float GetExposureScale(UsdTimeCode time=UsdTimeCode::Default()) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anderslanglands I'm going to change this to "Compute". I was wondering a bit about the fact that it's linear, when at least hydra is expecting something log-scale. Is it valuable to have a linear result, or would it be better to put the log inside the function for consistency? (If there's a use for it in linear that would lose precision from the exp2(log2(*)) that's a compelling reason to leave it as is).

If we leave it linear, I might go a step further and call it ComputeLinearExposureScale... Anyway, thoughts?

(Don't worry about updating this, I've pulled it and it's marked up a bunch for compatibility with internal code so it's easier for me to push the last few changes through).

};

PXR_NAMESPACE_CLOSE_SCOPE
Expand Down
23 changes: 20 additions & 3 deletions pxr/usd/usdGeom/generatedSchema.usda
Original file line number Diff line number Diff line change
Expand Up @@ -4210,11 +4210,28 @@ class Camera "Camera" (
."""
)
float exposure = 0 (
doc = """Exposure adjustment, as a log base-2 value. The default
doc = """Exposure compensation, as a log base-2 value. The default
of 0.0 has no effect. A value of 1.0 will double the
image-plane intensities in a rendered image; a value of
-1.0 will halve them."""
)
float exposure:fNumber = 1 (
doc = """f-number of the aperture when calculating exposure. Smaller numbers
create a brighter image, larger numbers darker."""
)
float exposure:iso = 100 (
doc = """The speed rating of the sensor or film when calculating exposure.
Higher numbers give a brighter image, lower numbers darker."""
)
float exposure:responsivity = 1 (
doc = """Scalar multiplier representing overall responsivity of the
sensor system to light when calculating exposure. Intended to be
used as a per camera/lens system measured scaling value."""
)
float exposure:time = 1 (
doc = """Time in seconds that the sensor is exposed to light when calculating exposure.
Longer exposure times create a brighter image, shorter times darker."""
)
float focalLength = 50 (
doc = """Perspective focal length in tenths of a scene unit; see
."""
Expand All @@ -4224,7 +4241,7 @@ class Camera "Camera" (
."""
)
float fStop = 0 (
doc = "Lens aperture. Defaults to 0.0, which turns off focusing."
doc = "Lens aperture. Defaults to 0.0, which turns off depth of field effects."
)
float horizontalAperture = 20.955 (
doc = """Horizontal aperture in tenths of a scene unit; see
Expand Down Expand Up @@ -4273,7 +4290,7 @@ class Camera "Camera" (
doc = """Frame relative shutter close time, analogous comments from
shutter:open apply. A value greater or equal to shutter:open
should be authored, otherwise there is no exposure and a
renderer should produce a black image."""
renderer should produce a black image. Used for motion blur."""
)
double shutter:open = 0 (
doc = """Frame relative shutter open time in UsdTimeCode units (negative
Expand Down
Loading