From 211d1154e62058f3823ab2a68d3573277198fcd2 Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:43:17 -0700 Subject: [PATCH] IECoreScene Camera : Add depthOfField accessors Adding these allow us to address a longstanding todo in Gaffer that will simplify handling of applying depth of field from the globals to a camera. --- Changes | 5 +++++ include/IECoreScene/Camera.h | 7 +++++++ src/IECoreScene/Camera.cpp | 1 + src/IECoreScene/bindings/CameraBinding.cpp | 5 +++++ test/IECoreScene/Camera.py | 6 ++++++ 5 files changed, 24 insertions(+) diff --git a/Changes b/Changes index 84ae7fbb92..969cd9353f 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,11 @@ 10.x.x.x (relative to 10.5.x.x) ======== +Improvements +------------ + +- IECoreScene::Camera : Added "depthOfField" parameter accessors. + Fixes ----- diff --git a/include/IECoreScene/Camera.h b/include/IECoreScene/Camera.h index d9d2b88efe..36ae78dc22 100644 --- a/include/IECoreScene/Camera.h +++ b/include/IECoreScene/Camera.h @@ -210,6 +210,13 @@ class IECORESCENE_API Camera : public PreWorldRenderable void setShutter( const Imath::V2f &shutter ); void removeShutter(); + /// Override whether the camera should render with depth of field blur. The amount of blur + /// can be controlled from the fStop parameter. + bool hasDepthOfField() const; + bool getDepthOfField() const; + void setDepthOfField( const bool &depthOfField ); + void removeDepthOfField(); + /// Given window with an arbitrary aspect, compute a box that fits it with a particular fit mode, /// to achieve a desired target aspect ratio. static Imath::Box2f fitWindow( const Imath::Box2f &window, Camera::FilmFit fitMode, float targetAspect ); diff --git a/src/IECoreScene/Camera.cpp b/src/IECoreScene/Camera.cpp index 727a8ae689..a866d2e2ef 100644 --- a/src/IECoreScene/Camera.cpp +++ b/src/IECoreScene/Camera.cpp @@ -263,6 +263,7 @@ DECLARE_ACCESSORS_FOR_OPTIONAL( OverscanTop, "overscanTop", FloatData, 0.0f ); DECLARE_ACCESSORS_FOR_OPTIONAL( OverscanBottom, "overscanBottom", FloatData, 0.0f ); DECLARE_ACCESSORS_FOR_OPTIONAL( CropWindow, "cropWindow", Box2fData, Box2f() ); DECLARE_ACCESSORS_FOR_OPTIONAL( Shutter, "shutter", V2fData, V2f( -0.5f, 0.5f ) ); +DECLARE_ACCESSORS_FOR_OPTIONAL( DepthOfField, "depthOfField", BoolData, false ); namespace { diff --git a/src/IECoreScene/bindings/CameraBinding.cpp b/src/IECoreScene/bindings/CameraBinding.cpp index 15fb51739d..c884cddc45 100644 --- a/src/IECoreScene/bindings/CameraBinding.cpp +++ b/src/IECoreScene/bindings/CameraBinding.cpp @@ -150,6 +150,11 @@ void bindCamera() .def( "getShutter", &Camera::getShutter ) .def( "removeShutter", &Camera::removeShutter ) + .def( "hasDepthOfField", &Camera::hasDepthOfField ) + .def( "setDepthOfField", &Camera::setDepthOfField ) + .def( "getDepthOfField", &Camera::getDepthOfField ) + .def( "removeDepthOfField", &Camera::removeDepthOfField ) + .def( "fitWindow", &Camera::fitWindow ).staticmethod( "fitWindow" ) .def( "frustum", &Camera::frustum ) .def( "frustum", &Camera::frustum ) diff --git a/test/IECoreScene/Camera.py b/test/IECoreScene/Camera.py index e40a8891be..7d2265631a 100644 --- a/test/IECoreScene/Camera.py +++ b/test/IECoreScene/Camera.py @@ -163,6 +163,7 @@ def testRenderOverrides( self ): self.assertEqual( c.hasOverscanBottom(), False ) self.assertEqual( c.hasCropWindow(), False ) self.assertEqual( c.hasShutter(), False ) + self.assertEqual( c.hasDepthOfField(), False ) c.setFilmFit( IECoreScene.Camera.FilmFit.Vertical ) c.setResolution( imath.V2i( 1280, 720 ) ) @@ -175,6 +176,7 @@ def testRenderOverrides( self ): c.setOverscanBottom( 0.4 ) c.setCropWindow( imath.Box2f( imath.V2f( 0.1, 0.2 ), imath.V2f( 0.8, 0.9 ) ) ) c.setShutter( imath.V2f( -0.7, 0.3 ) ) + c.setDepthOfField( True ) self.assertEqual( c.hasFilmFit(), True ) self.assertEqual( c.hasResolution(), True ) @@ -187,6 +189,7 @@ def testRenderOverrides( self ): self.assertEqual( c.hasOverscanBottom(), True ) self.assertEqual( c.hasCropWindow(), True ) self.assertEqual( c.hasShutter(), True ) + self.assertEqual( c.hasDepthOfField(), True ) self.assertEqual( c.getFilmFit(), IECoreScene.Camera.FilmFit.Vertical ) self.assertEqual( c.getResolution(), imath.V2i( 1280, 720 ) ) @@ -199,6 +202,7 @@ def testRenderOverrides( self ): self.assertAlmostEqual( c.getOverscanBottom(), 0.4 ) self.assertBox2fEqual( c.getCropWindow(), 0.1, 0.2, 0.8, 0.9 ) self.assertAlmostEqual( c.getShutter(), imath.V2f( -0.7, 0.3 ) ) + self.assertEqual( c.getDepthOfField(), True ) c.removeFilmFit() c.removeResolution() @@ -211,6 +215,7 @@ def testRenderOverrides( self ): c.removeOverscanBottom() c.removeCropWindow() c.removeShutter() + c.removeDepthOfField() self.assertEqual( c.hasFilmFit(), False ) self.assertEqual( c.hasResolution(), False ) @@ -223,6 +228,7 @@ def testRenderOverrides( self ): self.assertEqual( c.hasOverscanBottom(), False ) self.assertEqual( c.hasCropWindow(), False ) self.assertEqual( c.hasShutter(), False ) + self.assertEqual( c.hasDepthOfField(), False ) def testHash( self ) : c = IECoreScene.Camera()