From 5bcf7e04990419ac467c5bfc21361660306e5b8b Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Sun, 26 Jul 2026 17:37:44 -0500 Subject: [PATCH 1/2] =?UTF-8?q?pycvc=5Fgl:=20render=5Fpng=5Fcamera=20?= =?UTF-8?q?=E2=80=94=20offscreen=20render=20with=20an=20explicit=20camera?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit render_png() auto-frames the whole scene (ResetCamera), so it can't script a chase camera. Add render_png_camera(sg, path, w, h, eye, focal, up, view_angle, clip) — same offscreen path, but sets the camera explicitly — so callers can render a sequence of frames from a moving camera (e.g. capturing a learned-driving demo to video) without a live window. Auto-wrapped via the header %include; needs a pycvc_gl rebuild to surface in Python. NOTE: not build-tested in this checkout (no configured pycvc_gl build tree here); it is a direct mirror of render_png with SetPosition/SetFocalPoint/SetViewUp/ SetViewAngle/SetClippingRange in place of ResetCamera. CI builds the bindings. --- bindings/pycvc/pycvc_scene.cpp | 33 +++++++++++++++++++++++++++++++++ bindings/pycvc/pycvc_scene.h | 8 ++++++++ 2 files changed, 41 insertions(+) diff --git a/bindings/pycvc/pycvc_scene.cpp b/bindings/pycvc/pycvc_scene.cpp index 1769a568..56d69045 100644 --- a/bindings/pycvc/pycvc_scene.cpp +++ b/bindings/pycvc/pycvc_scene.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,38 @@ void render_png(SceneGraph &sg, const std::string &path, int width, int height) window->Finalize(); } +void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, + double eye_x, double eye_y, double eye_z, double focal_x, double focal_y, + double focal_z, double up_x, double up_y, double up_z, double view_angle, + double clip_near, double clip_far) { + // Like render_png, but sets an EXPLICIT camera (eye / focal / up + view angle + + // clip range) instead of ResetCamera() — so a caller can script a chase camera + // for frame-by-frame offscreen capture. Needs a GL context (offscreen is fine). + vtkNew renderer; + vtkNew window; + window->SetOffScreenRendering(1); + window->AddRenderer(renderer); + window->SetSize(width, height); + sg.setRenderer(renderer); + sg.processEvents(); + vtkCamera *cam = renderer->GetActiveCamera(); + cam->SetPosition(eye_x, eye_y, eye_z); + cam->SetFocalPoint(focal_x, focal_y, focal_z); + cam->SetViewUp(up_x, up_y, up_z); + cam->SetViewAngle(view_angle); + cam->SetClippingRange(clip_near, clip_far); + window->Render(); + vtkNew w2i; + w2i->SetInput(window); + w2i->Update(); + vtkNew writer; + writer->SetFileName(path.c_str()); + writer->SetInputConnection(w2i->GetOutputPort()); + writer->Write(); + sg.setRenderer(nullptr); + window->Finalize(); +} + void show(SceneGraph &sg, const std::string &title, int width, int height) { vtkNew renderer; vtkNew window; diff --git a/bindings/pycvc/pycvc_scene.h b/bindings/pycvc/pycvc_scene.h index 57ab4f96..89ec5d80 100644 --- a/bindings/pycvc/pycvc_scene.h +++ b/bindings/pycvc/pycvc_scene.h @@ -28,6 +28,14 @@ namespace pycvc { // events + frames the camera first. Needs a GL context (offscreen is fine). void render_png(SceneGraph &sg, const std::string &path, int width = 1024, int height = 768); +// Render one offscreen frame with an EXPLICIT camera (eye / focal-point / up + +// view angle + clip range) instead of auto-framing — for scripting a chase camera +// across a sequence of frames (e.g. capturing a drive to video). Offscreen is fine. +void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, + double eye_x, double eye_y, double eye_z, double focal_x, double focal_y, + double focal_z, double up_x, double up_y, double up_z, + double view_angle = 30.0, double clip_near = 1.0, double clip_far = 1e5); + // Open a blocking interactive window on `sg` (needs a display); returns when the // window closes. Don't call this in the embedded case — the host owns the loop. void show(SceneGraph &sg, const std::string &title = "pycvc_gl", int width = 1024, From c2053b606750c991bbde73b94f42a4b3afc449e8 Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Sun, 26 Jul 2026 18:02:54 -0500 Subject: [PATCH 2/2] pycvc_gl: clang-format render_png_camera signatures --- bindings/pycvc/pycvc_scene.cpp | 8 ++++---- bindings/pycvc/pycvc_scene.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bindings/pycvc/pycvc_scene.cpp b/bindings/pycvc/pycvc_scene.cpp index 56d69045..cc7aeb57 100644 --- a/bindings/pycvc/pycvc_scene.cpp +++ b/bindings/pycvc/pycvc_scene.cpp @@ -76,10 +76,10 @@ void render_png(SceneGraph &sg, const std::string &path, int width, int height) window->Finalize(); } -void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, - double eye_x, double eye_y, double eye_z, double focal_x, double focal_y, - double focal_z, double up_x, double up_y, double up_z, double view_angle, - double clip_near, double clip_far) { +void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, double eye_x, + double eye_y, double eye_z, double focal_x, double focal_y, double focal_z, + double up_x, double up_y, double up_z, double view_angle, double clip_near, + double clip_far) { // Like render_png, but sets an EXPLICIT camera (eye / focal / up + view angle + // clip range) instead of ResetCamera() — so a caller can script a chase camera // for frame-by-frame offscreen capture. Needs a GL context (offscreen is fine). diff --git a/bindings/pycvc/pycvc_scene.h b/bindings/pycvc/pycvc_scene.h index 89ec5d80..fdd1e885 100644 --- a/bindings/pycvc/pycvc_scene.h +++ b/bindings/pycvc/pycvc_scene.h @@ -31,10 +31,10 @@ void render_png(SceneGraph &sg, const std::string &path, int width = 1024, int h // Render one offscreen frame with an EXPLICIT camera (eye / focal-point / up + // view angle + clip range) instead of auto-framing — for scripting a chase camera // across a sequence of frames (e.g. capturing a drive to video). Offscreen is fine. -void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, - double eye_x, double eye_y, double eye_z, double focal_x, double focal_y, - double focal_z, double up_x, double up_y, double up_z, - double view_angle = 30.0, double clip_near = 1.0, double clip_far = 1e5); +void render_png_camera(SceneGraph &sg, const std::string &path, int width, int height, double eye_x, + double eye_y, double eye_z, double focal_x, double focal_y, double focal_z, + double up_x, double up_y, double up_z, double view_angle = 30.0, + double clip_near = 1.0, double clip_far = 1e5); // Open a blocking interactive window on `sg` (needs a display); returns when the // window closes. Don't call this in the embedded case — the host owns the loop.