diff --git a/pxr/imaging/hd/camera.cpp b/pxr/imaging/hd/camera.cpp index 151e1c982e..330b819db9 100644 --- a/pxr/imaging/hd/camera.cpp +++ b/pxr/imaging/hd/camera.cpp @@ -41,6 +41,11 @@ HdCamera::HdCamera(SdfPath const &id) , _shutterOpen(0.0) , _shutterClose(0.0) , _exposure(0.0f) + , _exposureTime(1.0f) + , _exposureIso(100.0f) + , _exposureFStop(1.0f) + , _exposureResponsivity(1.0f) + , _linearExposureScale(1.0f) , _lensDistortionType(HdCameraTokens->standard) , _lensDistortionK1(0.0f) , _lensDistortionK2(0.0f) @@ -238,6 +243,41 @@ HdCamera::Sync(HdSceneDelegate * sceneDelegate, _exposure = vExposure.Get(); } + const VtValue vExposureTime = + sceneDelegate->GetCameraParamValue( + id, HdCameraTokens->exposureTime); + if (!vExposureTime.IsEmpty()) { + _exposureTime = vExposureTime.Get(); + } + + const VtValue vExposureIso = + sceneDelegate->GetCameraParamValue( + id, HdCameraTokens->exposureIso); + if (!vExposureIso.IsEmpty()) { + _exposureIso = vExposureIso.Get(); + } + + const VtValue vExposureFStop = + sceneDelegate->GetCameraParamValue( + id, HdCameraTokens->exposureFStop); + if (!vExposureFStop.IsEmpty()) { + _exposureFStop = vExposureFStop.Get(); + } + + const VtValue vExposureResponsivity = + sceneDelegate->GetCameraParamValue( + id, HdCameraTokens->exposureResponsivity); + if (!vExposureResponsivity.IsEmpty()) { + _exposureResponsivity = vExposureResponsivity.Get(); + } + + const VtValue vLinearExposureScale = + sceneDelegate->GetCameraParamValue( + id, HdCameraTokens->linearExposureScale); + if (!vLinearExposureScale.IsEmpty()) { + _linearExposureScale = vLinearExposureScale.Get(); + } + const VtValue vLensDistortionType = sceneDelegate->GetCameraParamValue( id, HdCameraTokens->lensDistortionType); diff --git a/pxr/imaging/hd/camera.h b/pxr/imaging/hd/camera.h index 9a4cc88d76..1f24fad50a 100644 --- a/pxr/imaging/hd/camera.h +++ b/pxr/imaging/hd/camera.h @@ -57,6 +57,11 @@ PXR_NAMESPACE_OPEN_SCOPE (shutterOpen) \ (shutterClose) \ (exposure) \ + (exposureTime) \ + (exposureIso) \ + (exposureFStop) \ + (exposureResponsivity) \ + (linearExposureScale) \ \ /* how to match window with different aspect */ \ (windowPolicy) \ @@ -236,10 +241,26 @@ class HdCamera : public HdSprim return _shutterClose; } + /// Get the raw exposure exponent value. + /// + /// This the same as the value stored in the exposure attribute on the + /// underlying camera. Note that in most cases, you will want to use + /// GetLinearExposureScale() instead of this method, as it is the computed + /// end result of all related exposure attributes. + /// GetExposure() is retained as-is for backward compatibility. float GetExposure() const { return _exposure; } + /// Get the computed linear exposure scale from the underlying camera. + /// + /// Scaling the image brightness by this value will cause the various + /// exposure controls on \ref UsdGeomCamera to behave like those of a real + /// camera to control the exposure of the image. + float GetLinearExposureScale() const { + return _linearExposureScale; + } + TfToken GetLensDistortionType() const { return _lensDistortionType; } @@ -313,10 +334,17 @@ class HdCamera : public HdSprim float _splitDiopterWidth2; float _splitDiopterFocusDistance2; - // shutter/lighting + // shutter double _shutterOpen; double _shutterClose; + + // exposure float _exposure; + float _exposureTime; + float _exposureIso; + float _exposureFStop; + float _exposureResponsivity; + float _linearExposureScale; // lens distortion TfToken _lensDistortionType; diff --git a/pxr/imaging/hd/cameraSchema.cpp b/pxr/imaging/hd/cameraSchema.cpp index 06e4e1c3de..b1b20af282 100644 --- a/pxr/imaging/hd/cameraSchema.cpp +++ b/pxr/imaging/hd/cameraSchema.cpp @@ -123,6 +123,41 @@ HdCameraSchema::GetExposure() const HdCameraSchemaTokens->exposure); } +HdFloatDataSourceHandle +HdCameraSchema::GetExposureTime() const +{ + return _GetTypedDataSource( + HdCameraSchemaTokens->exposureTime); +} + +HdFloatDataSourceHandle +HdCameraSchema::GetExposureIso() const +{ + return _GetTypedDataSource( + HdCameraSchemaTokens->exposureIso); +} + +HdFloatDataSourceHandle +HdCameraSchema::GetExposureFStop() const +{ + return _GetTypedDataSource( + HdCameraSchemaTokens->exposureFStop); +} + +HdFloatDataSourceHandle +HdCameraSchema::GetExposureResponsivity() const +{ + return _GetTypedDataSource( + HdCameraSchemaTokens->exposureResponsivity); +} + +HdFloatDataSourceHandle +HdCameraSchema::GetLinearExposureScale() const +{ + return _GetTypedDataSource( + HdCameraSchemaTokens->linearExposureScale); +} + HdBoolDataSourceHandle HdCameraSchema::GetFocusOn() const { @@ -174,6 +209,11 @@ HdCameraSchema::BuildRetained( const HdDoubleDataSourceHandle &shutterOpen, const HdDoubleDataSourceHandle &shutterClose, const HdFloatDataSourceHandle &exposure, + const HdFloatDataSourceHandle &exposureTime, + const HdFloatDataSourceHandle &exposureIso, + const HdFloatDataSourceHandle &exposureFStop, + const HdFloatDataSourceHandle &exposureResponsivity, + const HdFloatDataSourceHandle &linearExposureScale, const HdBoolDataSourceHandle &focusOn, const HdFloatDataSourceHandle &dofAspect, const HdContainerDataSourceHandle &splitDiopter, @@ -181,8 +221,8 @@ HdCameraSchema::BuildRetained( const HdContainerDataSourceHandle &namespacedProperties ) { - TfToken _names[18]; - HdDataSourceBaseHandle _values[18]; + TfToken _names[23]; + HdDataSourceBaseHandle _values[23]; size_t _count = 0; @@ -251,6 +291,31 @@ HdCameraSchema::BuildRetained( _values[_count++] = exposure; } + if (exposureTime) { + _names[_count] = HdCameraSchemaTokens->exposureTime; + _values[_count++] = exposureTime; + } + + if (exposureIso) { + _names[_count] = HdCameraSchemaTokens->exposureIso; + _values[_count++] = exposureIso; + } + + if (exposureFStop) { + _names[_count] = HdCameraSchemaTokens->exposureFStop; + _values[_count++] = exposureFStop; + } + + if (exposureResponsivity) { + _names[_count] = HdCameraSchemaTokens->exposureResponsivity; + _values[_count++] = exposureResponsivity; + } + + if (linearExposureScale) { + _names[_count] = HdCameraSchemaTokens->linearExposureScale; + _values[_count++] = linearExposureScale; + } + if (focusOn) { _names[_count] = HdCameraSchemaTokens->focusOn; _values[_count++] = focusOn; @@ -382,6 +447,46 @@ HdCameraSchema::Builder::SetExposure( return *this; } +HdCameraSchema::Builder & +HdCameraSchema::Builder::SetExposureTime( + const HdFloatDataSourceHandle &exposureTime) +{ + _exposureTime = exposureTime; + return *this; +} + +HdCameraSchema::Builder & +HdCameraSchema::Builder::SetExposureIso( + const HdFloatDataSourceHandle &exposureIso) +{ + _exposureIso = exposureIso; + return *this; +} + +HdCameraSchema::Builder & +HdCameraSchema::Builder::SetExposureFStop( + const HdFloatDataSourceHandle &exposureFStop) +{ + _exposureFStop = exposureFStop; + return *this; +} + +HdCameraSchema::Builder & +HdCameraSchema::Builder::SetExposureResponsivity( + const HdFloatDataSourceHandle &exposureResponsivity) +{ + _exposureResponsivity = exposureResponsivity; + return *this; +} + +HdCameraSchema::Builder & +HdCameraSchema::Builder::SetLinearExposureScale( + const HdFloatDataSourceHandle &linearExposureScale) +{ + _linearExposureScale = linearExposureScale; + return *this; +} + HdCameraSchema::Builder & HdCameraSchema::Builder::SetFocusOn( const HdBoolDataSourceHandle &focusOn) @@ -439,6 +544,11 @@ HdCameraSchema::Builder::Build() _shutterOpen, _shutterClose, _exposure, + _exposureTime, + _exposureIso, + _exposureFStop, + _exposureResponsivity, + _linearExposureScale, _focusOn, _dofAspect, _splitDiopter, @@ -494,6 +604,66 @@ HdCameraSchema::GetShutterCloseLocator() return locator; } +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetExposureLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->exposure); + return locator; +} + +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetExposureTimeLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->exposureTime); + return locator; +} + +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetExposureIsoLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->exposureIso); + return locator; +} + +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetExposureFStopLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->exposureFStop); + return locator; +} + +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetExposureResponsivityLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->exposureResponsivity); + return locator; +} + +/* static */ +const HdDataSourceLocator & +HdCameraSchema::GetLinearExposureScaleLocator() +{ + static const HdDataSourceLocator locator = + GetDefaultLocator().Append( + HdCameraSchemaTokens->linearExposureScale); + return locator; +} + /* static */ const HdDataSourceLocator & HdCameraSchema::GetNamespacedPropertiesLocator() diff --git a/pxr/imaging/hd/cameraSchema.h b/pxr/imaging/hd/cameraSchema.h index 8af0a4f6f8..edfe673d1f 100644 --- a/pxr/imaging/hd/cameraSchema.h +++ b/pxr/imaging/hd/cameraSchema.h @@ -50,6 +50,11 @@ PXR_NAMESPACE_OPEN_SCOPE (shutterOpen) \ (shutterClose) \ (exposure) \ + (exposureTime) \ + (exposureIso) \ + (exposureFStop) \ + (exposureResponsivity) \ + (linearExposureScale) \ (focusOn) \ (dofAspect) \ (splitDiopter) \ @@ -129,6 +134,21 @@ class HdCameraSchema : public HdSchema HD_API HdFloatDataSourceHandle GetExposure() const; + HD_API + HdFloatDataSourceHandle GetExposureTime() const; + + HD_API + HdFloatDataSourceHandle GetExposureIso() const; + + HD_API + HdFloatDataSourceHandle GetExposureFStop() const; + + HD_API + HdFloatDataSourceHandle GetExposureResponsivity() const; + + HD_API + HdFloatDataSourceHandle GetLinearExposureScale() const; + HD_API HdBoolDataSourceHandle GetFocusOn() const; @@ -178,6 +198,30 @@ class HdCameraSchema : public HdSchema HD_API static const HdDataSourceLocator &GetShutterCloseLocator(); + /// Prim-level relative data source locator to locate exposure. + HD_API + static const HdDataSourceLocator &GetExposureLocator(); + + /// Prim-level relative data source locator to locate exposureTime. + HD_API + static const HdDataSourceLocator &GetExposureTimeLocator(); + + /// Prim-level relative data source locator to locate exposureIso. + HD_API + static const HdDataSourceLocator &GetExposureIsoLocator(); + + /// Prim-level relative data source locator to locate exposureFStop. + HD_API + static const HdDataSourceLocator &GetExposureFStopLocator(); + + /// Prim-level relative data source locator to locate exposureResponsivity. + HD_API + static const HdDataSourceLocator &GetExposureResponsivityLocator(); + + /// Prim-level relative data source locator to locate linearExposureScale. + HD_API + static const HdDataSourceLocator &GetLinearExposureScaleLocator(); + /// Prim-level relative data source locator to locate namespacedProperties. HD_API static const HdDataSourceLocator &GetNamespacedPropertiesLocator(); @@ -209,6 +253,11 @@ class HdCameraSchema : public HdSchema const HdDoubleDataSourceHandle &shutterOpen, const HdDoubleDataSourceHandle &shutterClose, const HdFloatDataSourceHandle &exposure, + const HdFloatDataSourceHandle &exposureTime, + const HdFloatDataSourceHandle &exposureIso, + const HdFloatDataSourceHandle &exposureFStop, + const HdFloatDataSourceHandle &exposureResponsivity, + const HdFloatDataSourceHandle &linearExposureScale, const HdBoolDataSourceHandle &focusOn, const HdFloatDataSourceHandle &dofAspect, const HdContainerDataSourceHandle &splitDiopter, @@ -265,6 +314,21 @@ class HdCameraSchema : public HdSchema Builder &SetExposure( const HdFloatDataSourceHandle &exposure); HD_API + Builder &SetExposureTime( + const HdFloatDataSourceHandle &exposureTime); + HD_API + Builder &SetExposureIso( + const HdFloatDataSourceHandle &exposureIso); + HD_API + Builder &SetExposureFStop( + const HdFloatDataSourceHandle &exposureFStop); + HD_API + Builder &SetExposureResponsivity( + const HdFloatDataSourceHandle &exposureResponsivity); + HD_API + Builder &SetLinearExposureScale( + const HdFloatDataSourceHandle &linearExposureScale); + HD_API Builder &SetFocusOn( const HdBoolDataSourceHandle &focusOn); HD_API @@ -298,6 +362,11 @@ class HdCameraSchema : public HdSchema HdDoubleDataSourceHandle _shutterOpen; HdDoubleDataSourceHandle _shutterClose; HdFloatDataSourceHandle _exposure; + HdFloatDataSourceHandle _exposureTime; + HdFloatDataSourceHandle _exposureIso; + HdFloatDataSourceHandle _exposureFStop; + HdFloatDataSourceHandle _exposureResponsivity; + HdFloatDataSourceHandle _linearExposureScale; HdBoolDataSourceHandle _focusOn; HdFloatDataSourceHandle _dofAspect; HdContainerDataSourceHandle _splitDiopter; diff --git a/pxr/imaging/hd/dataSourceLegacyPrim.cpp b/pxr/imaging/hd/dataSourceLegacyPrim.cpp index 3c31d2fdf1..683f36d9ca 100644 --- a/pxr/imaging/hd/dataSourceLegacyPrim.cpp +++ b/pxr/imaging/hd/dataSourceLegacyPrim.cpp @@ -1043,6 +1043,11 @@ class Hd_DataSourceCamera : public HdContainerDataSource HdCameraSchemaTokens->shutterOpen, HdCameraSchemaTokens->shutterClose, HdCameraSchemaTokens->exposure, + HdCameraSchemaTokens->exposureTime, + HdCameraSchemaTokens->exposureIso, + HdCameraSchemaTokens->exposureFStop, + HdCameraSchemaTokens->exposureResponsivity, + HdCameraSchemaTokens->linearExposureScale, HdCameraSchemaTokens->focusOn, HdCameraSchemaTokens->dofAspect, HdCameraSchemaTokens->splitDiopter, diff --git a/pxr/imaging/hd/hdSchemaDefs.py b/pxr/imaging/hd/hdSchemaDefs.py index a4cc0ebfda..b87640d924 100644 --- a/pxr/imaging/hd/hdSchemaDefs.py +++ b/pxr/imaging/hd/hdSchemaDefs.py @@ -1047,7 +1047,12 @@ ('focusDistance', T_FLOAT, {}), ('shutterOpen', T_DOUBLE, dict(ADD_LOCATOR = True)), ('shutterClose', T_DOUBLE, dict(ADD_LOCATOR = True)), - ('exposure', T_FLOAT, {}), + ('exposure', T_FLOAT, dict(ADD_LOCATOR = True)), + ('exposureTime', T_FLOAT, dict(ADD_LOCATOR = True)), + ('exposureIso', T_FLOAT, dict(ADD_LOCATOR = True)), + ('exposureFStop', T_FLOAT, dict(ADD_LOCATOR = True)), + ('exposureResponsivity', T_FLOAT, dict(ADD_LOCATOR = True)), + ('linearExposureScale', T_FLOAT, dict(ADD_LOCATOR = True)), ('focusOn', T_BOOL, {}), ('dofAspect', T_FLOAT, {}), ('splitDiopter', 'HdSplitDiopterSchema', {}), diff --git a/pxr/usd/usdGeom/camera.cpp b/pxr/usd/usdGeom/camera.cpp index 643fafa25e..29f12c07a6 100644 --- a/pxr/usd/usdGeom/camera.cpp +++ b/pxr/usd/usdGeom/camera.cpp @@ -324,6 +324,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::GetExposureFStopAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->exposureFStop); +} + +UsdAttribute +UsdGeomCamera::CreateExposureFStopAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->exposureFStop, + 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) @@ -355,6 +423,10 @@ UsdGeomCamera::GetSchemaAttributeNames(bool includeInherited) UsdGeomTokens->shutterOpen, UsdGeomTokens->shutterClose, UsdGeomTokens->exposure, + UsdGeomTokens->exposureIso, + UsdGeomTokens->exposureTime, + UsdGeomTokens->exposureFStop, + UsdGeomTokens->exposureResponsivity, }; static TfTokenVector allNames = _ConcatenateAttributeNames( @@ -564,4 +636,23 @@ UsdGeomCamera::SetFromCamera(const GfCamera &camera, const UsdTimeCode &time) GetFocusDistanceAttr().Set(camera.GetFocusDistance(), time); } +float +UsdGeomCamera::ComputeLinearExposureScale(UsdTimeCode time) const +{ + float exposureTime = 1.0f; + float exposureIso = 100.0f; + float exposureFStop = 1.0f; + float exposureResponsivity = 1.0f; + float exposureExponent = 0.0f; + + GetExposureTimeAttr().Get(&exposureTime, time); + GetExposureIsoAttr().Get(&exposureIso, time); + GetExposureFStopAttr().Get(&exposureFStop, time); + GetExposureResponsivityAttr().Get(&exposureResponsivity, time); + GetExposureAttr().Get(&exposureExponent, time); + + return (exposureTime * exposureIso * powf(2.0f, exposureExponent) * + exposureResponsivity) / (100.0f * exposureFStop * exposureFStop); +} + PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/usd/usdGeom/camera.h b/pxr/usd/usdGeom/camera.h index b8877d75ca..44705cb145 100644 --- a/pxr/usd/usdGeom/camera.h +++ b/pxr/usd/usdGeom/camera.h @@ -81,6 +81,42 @@ class SdfAssetPath; /// However, it follows that if even one property is authored in the correct /// scene units, then they all must be. /// +/// \section UsdGeom_CameraExposure Camera Exposure Model +/// +/// UsdGeomCamera models exposure by a camera in terms of exposure time, ISO, +/// f-stop, and exposure compensation, mirroring the controls on a real camera. +/// These parameters are provided by \ref UsdGeomCamera::GetExposureTimeAttr(), +/// \ref UsdGeomCamera::GetExposureIsoAttr(), +/// \ref UsdGeomCamera::GetExposureFStopAttr(), +/// and \ref UsdGeomCamera::GetExposureAttr(), respectively. +/// \ref UsdGeomCamera::GetExposureResponsivityAttr() provides an additional +/// scaling factor to model the overall responsivity of the system, +/// including response of the sensor and loss by the lens. +/// +/// The calculated scaling factor can be obtained from +/// \ref UsdGeomCamera::ComputeLinearExposureScale(). It is computed as: +/// \code +/// linearExposureScale = exposureResponsivity * +/// (exposureTime * (exposureIso/100) * pow(2, exposure)) +/// / (exposureFStop * exposureFStop) +/// \endcode +/// +/// This scaling factor is combined from two parts: The first, known as the +/// __imaging ratio__ (in _steradian-second_), converts from incident luminance +/// at the front of the lens system, in _nit_ (_cd/m^2_), to photometric +/// exposure at the sensor in _lux-second_. The second, `exposureResponsivity` +/// (in _inverse lux-second_), converts from photometric exposure at the sensor, +/// in _lux-second_, to a unitless output signal. +/// +/// For a thorough treatment of this topic, see +/// https://github.com/wetadigital/physlight/blob/main/docs/physLight-v1.3-1bdb6ec3-20230805.pdf, +/// Section 2.2. Note that we are essentially implementing Equation 2.7, but are +/// choosing C such that it exactly cancels with the factor of pi in the +/// numerator, replacing it with a responsivity factor that defaults to 1. +/// +/// Renderers should simply multiply the brightness of the image by the exposure +/// scale. The default values for the exposure-related attributes combine to +/// give a scale of 1.0. /// /// \sa \ref UsdGeom_LinAlgBasics /// @@ -376,7 +412,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. /// /// | || /// | -- | -- | @@ -473,7 +509,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. /// /// | || /// | -- | -- | @@ -495,7 +531,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. @@ -516,6 +552,108 @@ 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. + /// Note that shutter:open and shutter:close model essentially the + /// same property of a physical camera, but are for specifying the + /// size of the motion blur streak which is for practical purposes + /// useful to keep separate. + /// + /// | || + /// | -- | -- | + /// | 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: + // --------------------------------------------------------------------- // + // EXPOSUREFSTOP + // --------------------------------------------------------------------- // + /// f-stop of the aperture when calculating exposure. Smaller numbers + /// create a brighter image, larger numbers darker. + /// Note that the `fStop` attribute also models the diameter of the camera + /// aperture, but for specifying depth of field. For practical + /// purposes it is useful to keep the exposure and the depth of field + /// controls separate. + /// + /// + /// | || + /// | -- | -- | + /// | Declaration | `float exposure:fStop = 1` | + /// | C++ Type | float | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float | + USDGEOM_API + UsdAttribute GetExposureFStopAttr() const; + + /// See GetExposureFStopAttr(), 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 CreateExposureFStopAttr(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 @@ -556,6 +694,19 @@ class UsdGeomCamera : public UsdGeomXformable /// USDGEOM_API void SetFromCamera(const GfCamera &camera, const UsdTimeCode &time); + + /// Computes 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 ComputeLinearExposureScale(UsdTimeCode time=UsdTimeCode::Default()) const; }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/usd/usdGeom/generatedSchema.usda b/pxr/usd/usdGeom/generatedSchema.usda index c891690c7a..e988a553cf 100644 --- a/pxr/usd/usdGeom/generatedSchema.usda +++ b/pxr/usd/usdGeom/generatedSchema.usda @@ -4198,6 +4198,42 @@ class Camera "Camera" ( However, it follows that if even one property is authored in the correct scene units, then they all must be. + Camera Exposure Model + + UsdGeomCamera models exposure by a camera in terms of exposure time, ISO, + f-stop, and exposure compensation, mirroring the controls on a real camera. + These parameters are provided by \\ref UsdGeomCamera::GetExposureTimeAttr(), + \\ref UsdGeomCamera::GetExposureIsoAttr(), + \\ref UsdGeomCamera::GetExposureFStopAttr(), + and \\ref UsdGeomCamera::GetExposureAttr(), respectively. + \\ref UsdGeomCamera::GetExposureResponsivityAttr() provides an additional + scaling factor to model the overall responsivity of the system, + including response of the sensor and loss by the lens. + + The calculated scaling factor can be obtained from + \\ref UsdGeomCamera::ComputeLinearExposureScale(). It is computed as: + \\code + linearExposureScale = exposureResponsivity * + (exposureTime * (exposureIso/100) * pow(2, exposure)) + / (exposureFStop * exposureFStop) + \\endcode + + This scaling factor is combined from two parts: The first, known as the + __imaging ratio__ (in _steradian-second_), converts from incident luminance + at the front of the lens system, in _nit_ (_cd/m^2_), to photometric + exposure at the sensor in _lux-second_. The second, `exposureResponsivity` + (in _inverse lux-second_), converts from photometric exposure at the sensor, + in _lux-second_, to a unitless output signal. + + For a thorough treatment of this topic, see + https://github.com/wetadigital/physlight/blob/main/docs/physLight-v1.3-1bdb6ec3-20230805.pdf, + Section 2.2. Note that we are essentially implementing Equation 2.7, but are + choosing C such that it exactly cancels with the factor of pi in the + numerator, replacing it with a responsivity factor that defaults to 1. + + Renderers should simply multiply the brightness of the image by the exposure + scale. The default values for the exposure-related attributes combine to + give a scale of 1.0. \\sa \\ref UsdGeom_LinAlgBasics """ @@ -4214,11 +4250,37 @@ 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:fStop = 1 ( + doc = """f-stop of the aperture when calculating exposure. Smaller numbers + create a brighter image, larger numbers darker. + Note that the `fStop` attribute also models the diameter of the camera + aperture, but for specifying depth of field. For practical + purposes it is useful to keep the exposure and the depth of field + controls separate. + """ + ) + 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. + Note that shutter:open and shutter:close model essentially the + same property of a physical camera, but are for specifying the + size of the motion blur streak which is for practical purposes + useful to keep separate.""" + ) float focalLength = 50 ( doc = """Perspective focal length in tenths of a scene unit; see .""" @@ -4228,7 +4290,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 @@ -4277,7 +4339,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 diff --git a/pxr/usd/usdGeom/schema.usda b/pxr/usd/usdGeom/schema.usda index ed5dd80b1f..35405e4ebc 100644 --- a/pxr/usd/usdGeom/schema.usda +++ b/pxr/usd/usdGeom/schema.usda @@ -2297,6 +2297,42 @@ class Camera "Camera" ( However, it follows that if even one property is authored in the correct scene units, then they all must be. + \\section UsdGeom_CameraExposure Camera Exposure Model + + UsdGeomCamera models exposure by a camera in terms of exposure time, ISO, + f-stop, and exposure compensation, mirroring the controls on a real camera. + These parameters are provided by \\ref UsdGeomCamera::GetExposureTimeAttr(), + \\ref UsdGeomCamera::GetExposureIsoAttr(), + \\ref UsdGeomCamera::GetExposureFStopAttr(), + and \\ref UsdGeomCamera::GetExposureAttr(), respectively. + \\ref UsdGeomCamera::GetExposureResponsivityAttr() provides an additional + scaling factor to model the overall responsivity of the system, + including response of the sensor and loss by the lens. + + The calculated scaling factor can be obtained from + \\ref UsdGeomCamera::ComputeLinearExposureScale(). It is computed as: + \\code + linearExposureScale = exposureResponsivity * + (exposureTime * (exposureIso/100) * pow(2, exposure)) + / (exposureFStop * exposureFStop) + \\endcode + + This scaling factor is combined from two parts: The first, known as the + __imaging ratio__ (in _steradian-second_), converts from incident luminance + at the front of the lens system, in _nit_ (_cd/m^2_), to photometric + exposure at the sensor in _lux-second_. The second, `exposureResponsivity` + (in _inverse lux-second_), converts from photometric exposure at the sensor, + in _lux-second_, to a unitless output signal. + + For a thorough treatment of this topic, see + https://github.com/wetadigital/physlight/blob/main/docs/physLight-v1.3-1bdb6ec3-20230805.pdf, + Section 2.2. Note that we are essentially implementing Equation 2.7, but are + choosing C such that it exactly cancels with the factor of pi in the + numerator, replacing it with a responsivity factor that defaults to 1. + + Renderers should simply multiply the brightness of the image by the exposure + scale. The default values for the exposure-related attributes combine to + give a scale of 1.0. \\sa \\ref UsdGeom_LinAlgBasics """ @@ -2337,7 +2373,7 @@ class Camera "Camera" ( # depth of field float fStop = 0.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 focusDistance = 0.0 ( doc = """Distance from the camera to the focus plane in scene units; see \\ref UsdGeom_CameraUnits .""") @@ -2358,16 +2394,47 @@ 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.""" ) # exposure adjustment float exposure = 0.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.""" ) + + # exposure controls + float exposure:iso = 100.0 ( + doc = """The speed rating of the sensor or film when calculating exposure. + Higher numbers give a brighter image, lower numbers darker.""" + ) + + float exposure:time = 1.0 ( + doc = """Time in seconds that the sensor is exposed to light when calculating exposure. + Longer exposure times create a brighter image, shorter times darker. + Note that shutter:open and shutter:close model essentially the + same property of a physical camera, but are for specifying the + size of the motion blur streak which is for practical purposes + useful to keep separate.""" + ) + + float exposure:fStop = 1.0 ( + doc = """f-stop of the aperture when calculating exposure. Smaller numbers + create a brighter image, larger numbers darker. + Note that the `fStop` attribute also models the diameter of the camera + aperture, but for specifying depth of field. For practical + purposes it is useful to keep the exposure and the depth of field + controls separate. + """ + ) + + float exposure:responsivity = 1.0 ( + 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.""" + ) } class "GeomModelAPI" diff --git a/pxr/usd/usdGeom/testenv/testUsdGeomCamera.py b/pxr/usd/usdGeom/testenv/testUsdGeomCamera.py index dcebde5f47..f5bedcdde9 100644 --- a/pxr/usd/usdGeom/testenv/testUsdGeomCamera.py +++ b/pxr/usd/usdGeom/testenv/testUsdGeomCamera.py @@ -138,6 +138,31 @@ def test_SetFromCameraWithComposition(self): self.assertEqual(usdCamera.GetHorizontalApertureAttr().Get(1.0), 500.0) self.assertEqual(usdCamera.ComputeLocalToWorldTransform(1.0), newXform) + def test_ComputeLinearExposureScale(self): + stage = Usd.Stage.Open("layers_a_b.usda") + layerA = Sdf.Layer.FindOrOpen("a.usda") + layerB = Sdf.Layer.FindOrOpen("b.usda") + stage.SetEditTarget(layerB) + + usdCamera = UsdGeom.Camera.Define(stage, '/camera') + + self.assertAlmostEqual(usdCamera.GetExposureAttr().Get(1.0), 1.0, places=3) + self.assertAlmostEqual(usdCamera.GetExposureTimeAttr().Get(1.0), 0.01, places=3) + self.assertAlmostEqual(usdCamera.GetExposureFStopAttr().Get(1.0), 4.0, places=3) + self.assertAlmostEqual(usdCamera.GetExposureIsoAttr().Get(1.0), 400.0, places=3) + self.assertAlmostEqual(usdCamera.GetExposureResponsivityAttr().Get(1.0), 3.0) + + self.assertAlmostEqual(usdCamera.ComputeLinearExposureScale(), 0.015, places=3) + + usdCamera.GetExposureAttr().Set(0.0) + usdCamera.GetExposureTimeAttr().Set(1.0) + usdCamera.GetExposureFStopAttr().Set(1.0) + usdCamera.GetExposureIsoAttr().Set(100.0) + usdCamera.GetExposureResponsivityAttr().Set(1.0) + + self.assertAlmostEqual(usdCamera.ComputeLinearExposureScale(), 1.0, places=3) + + if __name__ == '__main__': unittest.main() diff --git a/pxr/usd/usdGeom/testenv/testUsdGeomCamera/b.usda b/pxr/usd/usdGeom/testenv/testUsdGeomCamera/b.usda index 500c4dc949..faeb9380af 100644 --- a/pxr/usd/usdGeom/testenv/testUsdGeomCamera/b.usda +++ b/pxr/usd/usdGeom/testenv/testUsdGeomCamera/b.usda @@ -6,4 +6,10 @@ def Camera "camera" { float horizontalAperture = 1.0 + + float exposure = 1.0 + float exposure:time = 0.01 + float exposure:fStop = 4.0 + float exposure:iso = 400 + float exposure:responsivity = 3 } diff --git a/pxr/usd/usdGeom/tokens.cpp b/pxr/usd/usdGeom/tokens.cpp index eecb458377..519099c33d 100644 --- a/pxr/usd/usdGeom/tokens.cpp +++ b/pxr/usd/usdGeom/tokens.cpp @@ -46,6 +46,10 @@ UsdGeomTokensType::UsdGeomTokensType() : elementSize("elementSize", TfToken::Immortal), elementType("elementType", TfToken::Immortal), exposure("exposure", TfToken::Immortal), + exposureFStop("exposure:fStop", TfToken::Immortal), + exposureIso("exposure:iso", TfToken::Immortal), + exposureResponsivity("exposure:responsivity", TfToken::Immortal), + exposureTime("exposure:time", TfToken::Immortal), extent("extent", TfToken::Immortal), extentsHint("extentsHint", TfToken::Immortal), face("face", TfToken::Immortal), @@ -249,6 +253,10 @@ UsdGeomTokensType::UsdGeomTokensType() : elementSize, elementType, exposure, + exposureFStop, + exposureIso, + exposureResponsivity, + exposureTime, extent, extentsHint, face, diff --git a/pxr/usd/usdGeom/tokens.h b/pxr/usd/usdGeom/tokens.h index 3a745e5857..b3da4efddf 100644 --- a/pxr/usd/usdGeom/tokens.h +++ b/pxr/usd/usdGeom/tokens.h @@ -193,6 +193,22 @@ struct UsdGeomTokensType { /// /// UsdGeomCamera const TfToken exposure; + /// \brief "exposure:fStop" + /// + /// UsdGeomCamera + const TfToken exposureFStop; + /// \brief "exposure:iso" + /// + /// UsdGeomCamera + const TfToken exposureIso; + /// \brief "exposure:responsivity" + /// + /// UsdGeomCamera + const TfToken exposureResponsivity; + /// \brief "exposure:time" + /// + /// UsdGeomCamera + const TfToken exposureTime; /// \brief "extent" /// /// UsdGeomBoundable, UsdGeomCube, UsdGeomSphere, UsdGeomCylinder, UsdGeomCapsule, UsdGeomCone, UsdGeomCylinder_1, UsdGeomCapsule_1, UsdGeomPlane diff --git a/pxr/usd/usdGeom/wrapCamera.cpp b/pxr/usd/usdGeom/wrapCamera.cpp index 907839770d..4cc0a02035 100644 --- a/pxr/usd/usdGeom/wrapCamera.cpp +++ b/pxr/usd/usdGeom/wrapCamera.cpp @@ -129,6 +129,34 @@ _CreateExposureAttr(UsdGeomCamera &self, return self.CreateExposureAttr( UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); } + +static UsdAttribute +_CreateExposureIsoAttr(UsdGeomCamera &self, + object defaultVal, bool writeSparsely) { + return self.CreateExposureIsoAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} + +static UsdAttribute +_CreateExposureTimeAttr(UsdGeomCamera &self, + object defaultVal, bool writeSparsely) { + return self.CreateExposureTimeAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} + +static UsdAttribute +_CreateExposureFStopAttr(UsdGeomCamera &self, + object defaultVal, bool writeSparsely) { + return self.CreateExposureFStopAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} + +static UsdAttribute +_CreateExposureResponsivityAttr(UsdGeomCamera &self, + object defaultVal, bool writeSparsely) { + return self.CreateExposureResponsivityAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} static std::string _Repr(const UsdGeomCamera &self) @@ -269,6 +297,34 @@ void wrapUsdGeomCamera() &_CreateExposureAttr, (arg("defaultValue")=object(), arg("writeSparsely")=false)) + + .def("GetExposureIsoAttr", + &This::GetExposureIsoAttr) + .def("CreateExposureIsoAttr", + &_CreateExposureIsoAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetExposureTimeAttr", + &This::GetExposureTimeAttr) + .def("CreateExposureTimeAttr", + &_CreateExposureTimeAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetExposureFStopAttr", + &This::GetExposureFStopAttr) + .def("CreateExposureFStopAttr", + &_CreateExposureFStopAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetExposureResponsivityAttr", + &This::GetExposureResponsivityAttr) + .def("CreateExposureResponsivityAttr", + &_CreateExposureResponsivityAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) .def("__repr__", ::_Repr) ; @@ -304,6 +360,9 @@ WRAP_CUSTOM { .def("SetFromCamera", &UsdGeomCamera::SetFromCamera, (arg("camera"), arg("time") = UsdTimeCode::Default())) + .def("ComputeLinearExposureScale", + &UsdGeomCamera::ComputeLinearExposureScale, + (arg("time") = UsdTimeCode::Default())) ; } diff --git a/pxr/usd/usdGeom/wrapTokens.cpp b/pxr/usd/usdGeom/wrapTokens.cpp index 2c407ef25e..2fa733bedc 100644 --- a/pxr/usd/usdGeom/wrapTokens.cpp +++ b/pxr/usd/usdGeom/wrapTokens.cpp @@ -54,6 +54,10 @@ void wrapUsdGeomTokens() _ADD_TOKEN(cls, elementSize); _ADD_TOKEN(cls, elementType); _ADD_TOKEN(cls, exposure); + _ADD_TOKEN(cls, exposureFStop); + _ADD_TOKEN(cls, exposureIso); + _ADD_TOKEN(cls, exposureResponsivity); + _ADD_TOKEN(cls, exposureTime); _ADD_TOKEN(cls, extent); _ADD_TOKEN(cls, extentsHint); _ADD_TOKEN(cls, face); diff --git a/pxr/usdImaging/usdImaging/cameraAdapter.cpp b/pxr/usdImaging/usdImaging/cameraAdapter.cpp index 10f96e0026..77435fbae6 100644 --- a/pxr/usdImaging/usdImaging/cameraAdapter.cpp +++ b/pxr/usdImaging/usdImaging/cameraAdapter.cpp @@ -242,9 +242,30 @@ UsdImagingCameraAdapter::Get(UsdPrim const& prim, cam.GetShutterCloseAttr().Get(&vShutterClose, time); // conversion n/a return vShutterClose; } else if (key == HdCameraTokens->exposure) { - VtValue v; - cam.GetExposureAttr().Get(&v, time); // conversion n/a - return v; + // The raw exponential compensation attribute. + // See "linearExposureScale" below for the computed linear multiplier. + VtValue vExposureExponent; + cam.GetExposureAttr().Get(&vExposureExponent, time); // conversion n/a + return vExposureExponent; + } else if (key == HdCameraTokens->exposureTime) { + VtValue vExposureTime; + cam.GetExposureTimeAttr().Get(&vExposureTime, time); // conversion n/a + return vExposureTime; + } else if (key == HdCameraTokens->exposureIso) { + VtValue vExposureIso; + cam.GetExposureIsoAttr().Get(&vExposureIso, time); // conversion n/a + return vExposureIso; + } else if (key == HdCameraTokens->exposureFStop) { + VtValue vExposureFStop; + cam.GetExposureFStopAttr().Get(&vExposureFStop, time); // conversion n/a + return vExposureFStop; + } else if (key == HdCameraTokens->exposureResponsivity) { + VtValue vExposureResponsivity; + cam.GetExposureResponsivityAttr().Get(&vExposureResponsivity, time); // conversion n/a + return vExposureResponsivity; + } else if (key == HdCameraTokens->linearExposureScale) { + // The computed linear exposure multiplier. + return VtValue(cam.ComputeLinearExposureScale(time)); } VtValue v; @@ -276,7 +297,11 @@ UsdImagingCameraAdapter::ProcessPropertyChange(UsdPrim const& prim, propertyName == UsdGeomTokens->focusDistance || propertyName == UsdGeomTokens->shutterOpen || propertyName == UsdGeomTokens->shutterClose || - propertyName == UsdGeomTokens->exposure) + propertyName == UsdGeomTokens->exposure || + propertyName == UsdGeomTokens->exposureTime || + propertyName == UsdGeomTokens->exposureIso || + propertyName == UsdGeomTokens->exposureFStop || + propertyName == UsdGeomTokens->exposureResponsivity) return HdCamera::DirtyParams; diff --git a/pxr/usdImaging/usdImaging/dataSourceCamera.cpp b/pxr/usdImaging/usdImaging/dataSourceCamera.cpp index 0f96d88448..771a3f6a3a 100644 --- a/pxr/usdImaging/usdImaging/dataSourceCamera.cpp +++ b/pxr/usdImaging/usdImaging/dataSourceCamera.cpp @@ -109,6 +109,78 @@ class _Vec4fArrayToVec4dArrayDataSource typename HdTypedSampledDataSource>::Handle _dataSource; }; +class _CameraLinearExposureScaleDataSource + : public HdTypedSampledDataSource +{ +public: + HD_DECLARE_DATASOURCE(_CameraLinearExposureScaleDataSource); + + _CameraLinearExposureScaleDataSource( + const SdfPath &sceneIndexPath, + UsdGeomCamera usdCamera, + const UsdImagingDataSourceStageGlobals &stageGlobals) + : _sceneIndexPath(sceneIndexPath) + , _usdCamera(usdCamera) + , _stageGlobals(stageGlobals) + { + static const HdDataSourceLocator linearExposureScaleLocator = + HdCameraSchema::GetLinearExposureScaleLocator(); + + static const std::vector inputNames = { + UsdGeomTokens->exposure, + UsdGeomTokens->exposureTime, + UsdGeomTokens->exposureIso, + UsdGeomTokens->exposureFStop, + UsdGeomTokens->exposureResponsivity + }; + + _inputs.resize(inputNames.size()); + UsdPrim prim = _usdCamera.GetPrim(); + for (const TfToken& inputName : inputNames) { + _inputs.push_back(UsdImagingDataSourceAttributeNew( + prim.GetAttribute(inputName), + _stageGlobals, + _sceneIndexPath, + linearExposureScaleLocator)); + } + } + + VtValue GetValue(Time shutterOffset) override + { + return VtValue(GetTypedValue(shutterOffset)); + } + + float GetTypedValue(Time shutterOffset) override + { + UsdTimeCode time = _stageGlobals.GetTime(); + if (time.IsNumeric()) { + time = UsdTimeCode(time.GetValue() + shutterOffset); + } + return _usdCamera.ComputeLinearExposureScale(time); + } + + bool GetContributingSampleTimesForInterval( + Time startTime, + Time endTime, + std::vector