[hdPrman] Use shutter curve on the camera when available.
authorrajabala <rajabala@users.noreply.github.com>
Sat, 3 Feb 2024 03:54:43 +0000 (19:54 -0800)
committerpixar-oss <pixar-oss@users.noreply.github.com>
Sat, 3 Feb 2024 04:09:39 +0000 (20:09 -0800)
- Update HdPrmanCamera to query and cache shutter curve attributes.
- Rework HdPrman_CameraContext to use the camera's shutter curve when available. It no longer needs to cache any of this state nor expose API to set it.
- Add unit test for various shutter interval and curve scenarios. See movingSphere.usda for notes on having motion blur show up correctly when using usdview.
- Update existing motion blur tests to use the fallback shutter curve for batch rendering so the baselines can remain unchanged.

Note that usdImaging wasn't updated to accomplish this. The reason this works is because the 1.0 and 2.0 getters (UsdImagingDelegate::GetCameraParamValue and UsdImagingDataSourceCameraPrim) fallback to querying the attribute on the USD prim. The shutter curve attributes are auto-applied by the UsdRi PxrCameraAPI schema on any UsdGeomCamera prim and thus always available when using hdPrman with USD.

It would however be useful to add an UsdImagingAPISchemaAdapter for PxrCameraAPI to allow its attributes to be inspectable in the Hydra Scene Browser.

(Internal change: 2313615)

third_party/renderman-25/plugin/hdPrman/camera.cpp
third_party/renderman-25/plugin/hdPrman/camera.h
third_party/renderman-25/plugin/hdPrman/cameraContext.cpp
third_party/renderman-25/plugin/hdPrman/cameraContext.h
third_party/renderman-25/plugin/hdPrman/renderParam.cpp
third_party/renderman-25/plugin/hdPrman/renderParam.h
third_party/renderman-25/plugin/hdPrman/renderPass.cpp
third_party/renderman-25/plugin/hdPrman/renderSettings.cpp

index 5c4aaa3984080d9168f87f70f454e533bb0d3df9..4846fe94dd46206e2463a923b495f5e1f4a2855d 100644 (file)
@@ -40,6 +40,44 @@ TF_DEFINE_PRIVATE_TOKENS(
 );
 #endif
 
+TF_DEFINE_PRIVATE_TOKENS(
+    _tokens,
+    ((shutterOpenTime,  "ri:shutterOpenTime"))
+    ((shutterCloseTime, "ri:shutterCloseTime"))
+    ((shutterOpening,   "ri:shutterOpening"))
+);
+
+namespace {
+
+const HdPrmanCamera::ShutterCurve&
+_GetFallbackShutterCurve(
+    bool interactive)
+{
+    if (interactive) {
+        // Open instantaneously, remain fully open for the duration of the
+        // shutter interval (set via the param RixStr.k_Ri_Shutter) and close
+        // instantaneously.
+        static const HdPrmanCamera::ShutterCurve interactiveFallback = {
+            0.0,
+            1.0,
+            { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }};
+
+        return interactiveFallback;
+    }
+
+    // Open instantaneously and start closing immediately, rapidly at first
+    // decelerating until the end of the interval.
+    static const HdPrmanCamera::ShutterCurve batchFallback = {
+        0.0,
+        0.0,
+        { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.3f, 0.0f }};
+    
+    return batchFallback;
+}
+
+} // anon
+
+
 HdPrmanCamera::HdPrmanCamera(SdfPath const& id)
   : HdCamera(id)
 #if HD_API_VERSION < 52
@@ -50,6 +88,7 @@ HdPrmanCamera::HdPrmanCamera(SdfPath const& id)
   , _lensDistortionAsym(0.0f)
   , _lensDistortionScale(1.0f)
 #endif
+    , _shutterCurve(_GetFallbackShutterCurve(/*isInteractive = */true))
 {
 }
 
@@ -113,6 +152,27 @@ HdPrmanCamera::Sync(HdSceneDelegate *sceneDelegate,
                 .GetWithDefault<float>(1.0f);
 #endif
 
+        const VtValue vShutterOpenTime =
+            sceneDelegate->GetCameraParamValue(id, _tokens->shutterOpenTime);
+        const VtValue vShutterCloseTime =
+            sceneDelegate->GetCameraParamValue(id, _tokens->shutterCloseTime);
+        const VtValue vShutterOpening =
+            sceneDelegate->GetCameraParamValue(id, _tokens->shutterOpening);
+        
+        if (vShutterOpenTime.IsHolding<float>() &&
+            vShutterCloseTime.IsHolding<float>() &&
+            vShutterOpening.IsHolding<VtArray<float>>()) {
+
+            _shutterCurve = {
+                vShutterOpenTime.UncheckedGet<float>(),
+                vShutterCloseTime.UncheckedGet<float>(),
+                vShutterOpening.UncheckedGet<VtArray<float>>()
+            };
+
+        } else {
+            _shutterCurve = _GetFallbackShutterCurve(param->IsInteractive());
+        }
+        
         if (id == param->GetCameraContext().GetCameraPath()) {
             // Motion blur in Riley only works correctly if the
             // shutter interval is set before any rprims are synced
index 3523578772841e6b934e66df722654210f9cedd7..3375b03fd48240a9223a4b285e4ad153430d8d13 100644 (file)
@@ -30,6 +30,8 @@
 #include "pxr/imaging/hd/camera.h"
 #include "pxr/imaging/hd/timeSampleArray.h"
 
+#include "pxr/base/vt/array.h"
+
 PXR_NAMESPACE_OPEN_SCOPE
 
 class HdSceneDelegate;
@@ -45,6 +47,16 @@ class HdSceneDelegate;
 class HdPrmanCamera final : public HdCamera
 {
 public:
+    /// See GetShutterCurve() below for a description of what these
+    /// values represent.
+    ///
+    struct ShutterCurve
+    {
+        float shutterOpenTime;
+        float shutterCloseTime;
+        VtArray<float> shutterOpening;
+    };
+
     HDPRMAN_API
     HdPrmanCamera(SdfPath const& id);
 
@@ -90,6 +102,43 @@ public:
     }
 #endif
 
+    /// Get the shutter curve of the camera. This curve determines the
+    /// transparency of the shutter as a function of (normalized)
+    /// time.
+    ///
+    /// Note that the times returned here are relative to the shutter
+    /// interval.
+    ///
+    /// Some more explanation:
+    ///
+    /// The values given here are passed to the Riley camera as options
+    /// RixStr.k_shutterOpenTime, k_shutterCloseTime and k_shutteropening.
+    ///
+    /// (where as the shutter interval is set through the global Riley options
+    /// using Ri:Shutter).
+    ///
+    /// RenderMan computes the shutter curve using constant pieces and
+    /// cubic Bezier interpolation between the following points
+    /// 
+    /// (0, 0), (t1, y1), (t2,y2), (t3, 1), (t4, 1), (t5, y5), (t6, y6), (1, 0)
+    ///
+    /// which are encoded as:
+    ///    t3 is the shutterOpenTime
+    ///    t4 is the shutterCloseTime
+    ///    [t1, y1, t2, y2, t5, y5, t6, y6] is the shutteropening array.
+    ///
+    /// \note The shutter:open and shutter:close attributes of UsdGeomCamera
+    ///       represent the (frame-relative) time the shutter *begins to open*
+    ///       and is *fully closed* respectively.
+    ///
+    ///       The Riley shutterOpenTime and shutterCloseTime represent the
+    ///       (riley shutter-interval relative)  time the shutter is *fully
+    ///       open* and *begins to close* respectively.
+    ///
+    const ShutterCurve& GetShutterCurve() const {
+        return _shutterCurve;
+    }
+
 private:
     HdTimeSampleArray<GfMatrix4d, HDPRMAN_MAX_TIME_SAMPLES> _sampleXforms;
 
@@ -101,6 +150,18 @@ private:
     GfVec2f _lensDistortionAsym;
     float _lensDistortionScale;
 #endif
+
+    /// RenderMan computes the shutter curve using constant pieces and
+    /// cubic Bezier interpolation between the following points
+    /// 
+    /// (0, 0), (t1, y1), (t2,y2), (t3, 1), (t4, 1), (t5, y5), (t6, y6), (1, 0)
+    ///
+    /// which are encoded as:
+    ///    t3 is the shutterOpenTime
+    ///    t4 is the shutterCloseTime
+    ///    [t1, y1, t2, y2, t5, y5, t6, y6] is shutteropeningPoints array.
+    ///
+    ShutterCurve _shutterCurve;
 };
 
 
index 2a2d1d0f991de17fb6369c648bac58a26067fe70..8a39cd00711b237eb96d943f837612ccd55fc69a 100644 (file)
@@ -42,13 +42,6 @@ static const RtUString s_projectionNodeName("cam_projection");
 HdPrman_CameraContext::HdPrman_CameraContext()
   : _policy(CameraUtilFit)
   , _disableDepthOfField(false)
-  , _shutterOpenTime(0.0f)
-  , _shutterCloseTime(1.0f)
-  , _shutteropeningPoints{ // matches RenderMan default
-            0.0f, 0.0f, // points before open time
-            0.0f, 0.0f, 
-            1.0f, 0.0f, // points after close time
-            1.0f, 0.0f}
   , _invalid(false)
 {
 }
@@ -91,52 +84,6 @@ HdPrman_CameraContext::SetWindowPolicy(
     }
 }
 
-void
-HdPrman_CameraContext::SetShutterCurve(const float shutterOpenTime,
-                                       const float shutterCloseTime,
-                                       const float shutteropeningPoints[8])
-{
-    if (_shutterOpenTime != shutterOpenTime) {
-        _shutterOpenTime = shutterOpenTime;
-        _invalid = true;
-    }
-    if (_shutterCloseTime != shutterCloseTime) {
-        _shutterCloseTime = shutterCloseTime;
-        _invalid = true;
-    }
-    size_t i = 0;
-    for (; i < TfArraySize(_shutteropeningPoints); i++) {
-        if (_shutteropeningPoints[i] != shutteropeningPoints[i]) {
-            _invalid = true;
-            break;
-        }
-    }
-    for (; i < TfArraySize(_shutteropeningPoints); i++) {
-        _shutteropeningPoints[i] = shutteropeningPoints[i];
-    }
-}
-
-void
-HdPrman_CameraContext::SetFallbackShutterCurve(bool isInteractive)
-{
-    if (isInteractive) {
-        // Open instantaneously, remain fully open for the duration of the
-        // shutter interval (set via the param RixStr.k_Ri_Shutter) and close
-        // instantaneously.
-        static const float pts[8] = {
-            0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f
-        };
-        SetShutterCurve(0.0f, 1.0f, pts);
-    } else {
-        // Open instantaneously and start closing immediately, rapidly at first
-        // decelerating until the end of the interval.
-        static const float pts[8] = {
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.3f, 0.0f
-        };
-        SetShutterCurve(0.0f, 0.0f, pts);
-    }
-}
-
 void
 HdPrman_CameraContext::SetDisableDepthOfField(bool disableDepthOfField)
 {
@@ -438,30 +385,19 @@ HdPrman_CameraContext::_ComputeCameraParams(
         result.SetFloat(RixStr.k_farClip, clippingRange.GetMax());
     }
 
-    result.SetFloat(RixStr.k_shutterOpenTime, _shutterOpenTime);
-    result.SetFloat(RixStr.k_shutterCloseTime, _shutterCloseTime);
+    const HdPrmanCamera * const hdPrmanCamera =
+        dynamic_cast<const HdPrmanCamera * const>(camera);
+    const HdPrmanCamera::ShutterCurve &shutterCurve
+        = hdPrmanCamera->GetShutterCurve();
+        
+    result.SetFloat(RixStr.k_shutterOpenTime, shutterCurve.shutterOpenTime);
+    result.SetFloat(RixStr.k_shutterCloseTime, shutterCurve.shutterCloseTime);
     result.SetFloatArray(
         RixStr.k_shutteropening,
-        _shutteropeningPoints, TfArraySize(_shutteropeningPoints));
-
-    // XXX : Ideally we would want to set the proper shutter open and close,
-    // however we can not fully change the shutter without restarting
-    // Riley.
-    
-    // double const *shutterOpen =
-    //     _GetDictItem<double>(_params, HdCameraTokens->shutterOpen);
-    // if (shutterOpen) {
-    //     camParams->SetFloat(RixStr.k_shutterOpenTime, *shutterOpen);
-    // }
-    
-    // double const *shutterClose =
-    //     _GetDictItem<double>(_params, HdCameraTokens->shutterClose);
-    // if (shutterClose) {
-    //     camParams->SetFloat(RixStr.k_shutterCloseTime, *shutterClose);
-    // }
+        shutterCurve.shutterOpening.data(),
+        shutterCurve.shutterOpening.size());
 
     const GfVec4f s = _ToVec4f(screenWindow);
-    
     result.SetFloatArray(RixStr.k_Ri_ScreenWindow, s.data(), 4);
 
     return result;
index 2c01324d390b25d6afb02da0db82a9e391832e3d..0170a7203f132047bb16895f9541e9267a26cec6 100644 (file)
@@ -112,40 +112,6 @@ public:
     /// Get resolution for offline rendering.
     GfVec2i GetResolutionFromDisplayWindow() const;
 
-    /// Set the shutter curve, i.e., the curve that determines how
-    /// transparency of the shutter as a function of (normalized)
-    /// time.
-    ///
-    /// Note that the times given here are relative to the shutter
-    /// interval.
-    ///
-    /// Some more explanation:
-    ///
-    /// The values given here are passed to the Riley camera as options
-    /// RixStr.k_shutterOpenTime, k_shutterCloseTime and k_shutteropening.
-    ///
-    /// (where as the shutter interval is set through the global Riley options
-    /// using Ri:Shutter).
-    ///
-    /// RenderMan computes the shutter curve using constant pieces and
-    /// cubic Bezier interpolation between the following points
-    /// 
-    /// (0, 0), (t1, y1), (t2,y2), (t3, 1), (t4, 1), (t5, y5), (t6, y6), (1, 0)
-    ///
-    /// which are encoded as:
-    ///    t3 is the shutterOpenTime
-    ///    t4 is the shutterCloseTime
-    ///    [t1, y1, t2, y2, t5, y5, t6, y6] is shutteropeningPoints array.
-    ///
-    void SetShutterCurve(const float shutterOpenTime,
-                         const float shutterCloseTime,
-                         const float shutteropeningPoints[8]);
-
-    /// Use hardcoded fallback values for the shutter curve. Ideally, this
-    /// can be removed once we add UsdImaging/Hydra support for PxrCameraAPI.
-    ///
-    void SetFallbackShutterCurve(bool isInteractive);
-
     /// When depth of field is disabled the fstop is set to infinity.
     void SetDisableDepthOfField(bool disableDepthOfField);
 
@@ -190,10 +156,6 @@ private:
     CameraUtilFraming _framing;
     CameraUtilConformWindowPolicy _policy;
     bool _disableDepthOfField;
-
-    float _shutterOpenTime;
-    float _shutterCloseTime;
-    float _shutteropeningPoints[8];
     
     // Save ids of riley clip planes so that we can delete them before
     // re-creating them to update the clip planes.
index 8ad444cdf9c7f3ae1a644728485d0d1a6614db6f..6f834a58ea612223646027db97b720eb68971b95 100644 (file)
@@ -3407,4 +3407,10 @@ HdPrman_RenderParam::GetInstancer(const SdfPath& id)
     return nullptr;
 }
 
+bool
+HdPrman_RenderParam::IsInteractive() const
+{
+    return _renderDelegate->IsInteractive();
+}
+
 PXR_NAMESPACE_CLOSE_SCOPE
index 2f085c030968aab1931db3ae03ff546bbed5bcf4..6102e07b7cb90c300f1fcc09a97a10cd03618cc0 100644 (file)
@@ -362,6 +362,10 @@ public:
     // Set Riley scene options by composing opinion sources.
     void SetRileyOptions();
 
+    // Returns true if the render delegate in interactive mode (as opposed to
+    // batched/offline mode).
+    bool IsInteractive() const;
+
 private:
     void _CreateStatsSession();
     void _CreateRiley(const std::string &rileyVariant, 
index b3bb4cfe7b04c1e3b5d1208f179a1ed1414432f5..b360f40221713a6d66bc32cc25616ddbaa25e112 100644 (file)
@@ -444,8 +444,6 @@ HdPrman_RenderPass::_Execute(
     _UpdateCameraPath(renderPassState, &cameraContext);
     const bool dataWindowChanged = _UpdateCameraFramingAndWindowPolicy(
         renderPassState, &cameraContext);
-    // XXX This should come from the camera.
-    cameraContext.SetFallbackShutterCurve(isInteractive);
     const bool camChanged = cameraContext.IsInvalid();
     cameraContext.MarkValid();
     
@@ -593,7 +591,7 @@ HdPrman_RenderPass::_Execute(
         }
     }
 
-    if (renderDelegate->IsInteractive()) {
+    if (isInteractive) {
         // This path uses the render thread to start the render.
         _RestartRenderIfNecessary(renderDelegate);
     } else {
index 17dafa3d53df6eec5db1509d298b22d3ae01e813..67e326b13a341d69033b407b6879907a4cf1d048 100644 (file)
@@ -179,7 +179,6 @@ _UpdateRileyCamera(
     riley::Riley *riley,
     const HdRenderIndex *renderIndex,
     const SdfPath &cameraPathFromProduct,
-    bool interactive,
     HdPrman_CameraContext *cameraContext)
 {
     if (cameraContext->IsInvalid()) {
@@ -188,11 +187,6 @@ _UpdateRileyCamera(
             cameraContext->GetCameraId().AsUInt32(),
             cameraContext->GetCameraPath().GetText());
 
-        // XXX This should come from the camera Sprim instead and should be
-        //     folded into UpdateRileyCameraAndClipPlanes.
-        //
-        cameraContext->SetFallbackShutterCurve(interactive);
-
         cameraContext->UpdateRileyCameraAndClipPlanes(riley, renderIndex);
         cameraContext->MarkValid();
     }
@@ -376,7 +370,6 @@ HdPrman_RenderSettings::UpdateAndRender(
             param->AcquireRiley(),
             renderIndex,
             product.cameraPath,
-            interactive,
             &cameraContext);
         
         const GfVec2f shutter =