Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d79a536
Set up surprise checking for new camera input option
emily-howell Jul 16, 2025
e9ed8e0
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Jul 16, 2025
8ddb69f
Adding a test for the ascent camera format
emily-howell Jul 16, 2025
c6cda28
Fetting test passing and adding some rough tests for the visit case a…
emily-howell Jul 16, 2025
8dc4da2
Successfully got something that looks the same in ascent for both cam…
emily-howell Jul 17, 2025
17a6124
Checkpoint with functional positioning and zoom. However, clipping is…
emily-howell Jul 31, 2025
05d5c30
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Jul 31, 2025
dcd5e76
Cleaning up the tests so that they pass. Still have clipping plane issue
emily-howell Aug 1, 2025
00272a3
Adding 2d as valid path for ascent camera definition
emily-howell Aug 1, 2025
3c47319
Adding some infos for the users to help with confusion?
emily-howell Aug 7, 2025
d631424
Cleaning up the tests a smidge
emily-howell Aug 7, 2025
e80b65b
switching all visit parameter variable names to snake case
emily-howell Aug 12, 2025
9c8fe60
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Aug 12, 2025
6caff07
Adding documentation about rendering camera parameters
emily-howell Aug 13, 2025
ec94407
Making the unsupported visit camera parameters clearer
emily-howell Aug 13, 2025
82e0149
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Aug 13, 2025
077d4c9
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Aug 19, 2025
3a9ae24
Trying clearning up the tests to see if that helps?
emily-howell Aug 19, 2025
1dc5d7b
Seeing if modifying the rendering helps?
emily-howell Aug 19, 2025
91afd7c
Using a better pi
emily-howell Aug 19, 2025
e93c4f1
Putting my tests back
emily-howell Aug 19, 2025
dd893c4
Updating clipping planes in tests
emily-howell Aug 21, 2025
4483305
Merge branch 'develop' of github.com:Alpine-DAV/ascent into task/7_15…
emily-howell Oct 21, 2025
87b12bd
Addressing MR feedback :) (thank you Justin)
emily-howell Oct 28, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s
- [email protected]
- [email protected]

### Added
- Added ability to define cameras for rendering using visit camera view parameters

## [0.9.5] - Released 2025-09-10
### Preferred dependency versions for [email protected]
Expand Down
62 changes: 62 additions & 0 deletions src/docs/sphinx/Actions/Scenes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,68 @@ Now we add a second render to the same example using every available parameter:
near_plane: 0.1
far_plane: 100.1
Rendering Camera Configuration
---------------------------------
Ascent supports rendering in both 2D and 3D. For 3D rendering, Ascent supports two primary methods for defining the camera:
the Ascent native (VTKm style) camera, which is camera-centric, and the VisIt style camera, which is view-centric.
Both formats provide control over how scenes are rendered, but they differ in terminology, orientation, and internal computation of the view matrix.

2D Camera
^^^^^^^^^
2D rendering can be accomplished by defining the 2D view bounds of the rendered scene.

- ``2d`` or ``windowCoords``: Enables 2D rendering mode. Expects a 4-element array defining the 2D view bounds [x0 (left), x1 (right), y0 (bottom), y1 (top)].

Ascent Native (VTKm Style) Camera
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The native Ascent camera follows the VTKm camera model which focuses on defining the camera's physical parameters and orientation in 3D space.
This camera-centric approach specifies where the camera is located, what it is looking at, and how it is oriented.
The following parameters are supported:

- ``look_at`` : A 3-element array [x, y, z] indicating the point the camera is directed toward.
- ``position`` : A 3-element array [x, y, z] indicating the camera's position in space.
- ``up`` : A 3-element vector that defines the up direction of the camera.
- ``fov`` : Field of view in degrees for perspective projection.
- ``xpan`` : Pan offset in the horizontal direction.
- ``ypan`` : Pan offset in the vertical direction.
- ``zoom`` : Uniform zoom factor applied to the view.
- ``near_plane`` : Distance from the camera to the near clipping plane.
- ``far_plane`` : Distance from the camera to the far clipping plane.
- ``azimuth`` : Rotates the camera around the up axis.
- ``elevation`` : Rotates the camera around the right axis.

VisIt Style Camera
^^^^^^^^^^^^^^^^^^
Alternatively, the camera can be defined using the VisIt camera parameters which follows a view centric approach.
Instead of positioning the camera explicitly, it defines the view using vectors like ``view_normal`` and ``view_up``, which describe the direction and orientation of the camera relative to a focal point.
The following parameters are supported:

- ``view_normal`` : A vector [x, y, z] indicating the direction to the camera from the ``focus`` point.
- ``focus`` : A 3D point [x, y, z] indicating the point of focus in the scene.
- ``view_up`` : A vector indicating which direction is up in the rendered view.
- ``view_angle`` : Field of view half-angle in degrees. This is equivalent to 2x the ``fov`` value of the Ascent Camera
- ``parallel_scale`` : Half of the image height in world space.
- ``near_plane`` : Distance from the ``focus`` point along the ``view_normal`` to the near clipping plane.
- ``far_plane`` : Distance from the ``focus`` point along the ``view_normal`` to the far clipping plane.
- ``image_pan`` : A 2-element array [x, y] specifying image-space panning.
- ``image_zoom`` : Zoom factor for the image.


Unsupported VisIt Camera Parameters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In addition to the above supported VisIt camera parameters, there are a number of VisIt camera parameters that are not completely translatable to the VTKm style camera and are therefore currently ignored.

.. Note::
These parameters are safely ignored if provided. They will not influence the rendered image but also will not produce errors.

- ``perspective`` : Boolean flag (true/false) indicating whether to use perspective (true) or parallel (false) projection. In Ascent, only perspective projection is currently used so this flag is ignored.
- ``eye_angle`` : Used in stereo rendering to control the eye separation angle. Ascent does not currently support stereo rendering, so this has no effect.
- ``center_of_rotation_set`` : Boolean flag indicating whether ``center_of_rotation`` has been explicitly set. Not used in Ascent.
- ``center_of_rotation`` : A 3D point used as the pivot for interactive rotation in VisIt. Ascent does not support interactive camera manipulation, so this is ignored.
- ``axis_3d_scale_flag`` : Boolean flag that enables non-uniform axis scaling (e.g., X:Y:Z aspect ratios). Not supported in Ascent.
- ``axis_3d_scale`` : A 3D vector specifying per-axis scaling for non-uniform visualizations. No effect in Ascent.
- ``shear`` : A 3-element array used to apply a shear transformation to the view. Not currently implemented.
- ``window_valid`` : Internal VisIt flag to indicate whether the current window setup is valid. Irrelevant in Ascent and ignored.

Copy link
Member

Choose a reason for hiding this comment

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

Docs look great!

Additional Render Options
-------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,33 @@ parse_camera(const conduit::Node camera_node, vtkm::rendering::Camera &camera)
// Get the optional camera parameters
//

// check for 2d mode first
if(camera_node.has_child("2d"))
// -------------------- //
// 2D camera parameters //
// -------------------- //
if(camera_node.has_child("2d") || camera_node.has_child("windowCoords"))
{
// camera:
// 2d: [l,r,b,t]
camera.SetModeTo2D();
conduit::Node n;
camera_node["2d"].to_float64_array(n);
const float64 *view_vals = n.as_float64_ptr();
float64_accessor view_vals;
if(camera_node.has_child("2d"))
{
view_vals = camera_node["2d"].value();
}
else
{
view_vals = camera_node["windowCoords"].value();
}

camera.SetViewRange2D(view_vals[0],
view_vals[1],
view_vals[2],
view_vals[3]);
}

// ------------------------ //
// Ascent camera parameters //
// ------------------------ //
if(camera_node.has_child("look_at"))
{
conduit::Node n;
Expand Down Expand Up @@ -191,6 +202,113 @@ parse_camera(const conduit::Node camera_node, vtkm::rendering::Camera &camera)
vtkm::Float64 elevation = camera_node["elevation"].to_float64();
camera.Elevation(elevation);
}

// ----------------------- //
// Visit camera parameters //
// ----------------------- //
if(camera_node.has_child("focus"))
{
float64_accessor coords = camera_node["focus"].value();
vtkmVec3f look_at(coords[0], coords[1], coords[2]);
camera.SetLookAt(look_at);
}

if(camera_node.has_child("view_normal") &&
camera_node.has_child("focus") &&
camera_node.has_child("view_angle") &&
camera_node.has_child("parallel_scale"))
{
// Compute camera distance using perspective projection formula
conduit::float64 view_angle = camera_node["view_angle"].to_float64() * (vtkm::Pi() / 360.0);
conduit::float64 parallel_scale = camera_node["parallel_scale"].to_float64();
conduit::float64 distance = (parallel_scale) / std::tan(view_angle);

// Normalize viewNormal vector
float64_accessor view = camera_node["view_normal"].value();
conduit::float64 norm = std::sqrt(view[0]*view[0] + view[1]*view[1] + view[2]*view[2]);
conduit::float64 view_norm[3] = { view[0]/norm, view[1]/norm, view[2]/norm };

float64_accessor focus = camera_node["focus"].value();
conduit::float64 pos[3];
for(int i = 0; i < 3; ++i)
{
pos[i] = focus[i] + view_norm[i] * distance;
}

vtkmVec3f position(pos[0], pos[1], pos[2]);
camera.SetPosition(position);

// Clipping planes require positional information to be computed
if(camera_node.has_child("near_plane"))
{
vtkm::Range clipping_range = camera.GetClippingRange();
clipping_range.Min =std::max(CONDUIT_EPSILON, distance + camera_node["near_plane"].to_float64());
camera.SetClippingRange(clipping_range);
}

if(camera_node.has_child("far_plane"))
{
vtkm::Range clipping_range = camera.GetClippingRange();
clipping_range.Max = distance + camera_node["far_plane"].to_float64();
camera.SetClippingRange(clipping_range);
}
}

if(camera_node.has_child("view_angle"))
{
camera.SetFieldOfView(camera_node["view_angle"].to_float64() * 2);
}

if(camera_node.has_child("view_up"))
{
float64_accessor coords = camera_node["view_up"].value();
vtkmVec3f up(coords[0], coords[1], coords[2]);
vtkm::Normalize(up);
camera.SetViewUp(up);
}

if(camera_node.has_child("image_pan"))
{
float64_accessor pan_xy = camera_node["image_pan"].value();
camera.Pan(pan_xy[0], pan_xy[1]);
}

if(camera_node.has_child("image_zoom"))
{
camera.Zoom(zoom_to_vtkm_zoom(camera_node["image_zoom"].to_float64()));
}

if(camera_node.has_child("perspective"))
{
ASCENT_INFO("Visit camera parameter \"perspective\" is recognized but currently has no effect");
}

if(camera_node.has_child("eye_angle"))
{
ASCENT_INFO("Visit camera parameter \"eye_angle\" is recognized but currently has no effect");
}

if(camera_node.has_child("center_of_rotation_set") ||
camera_node.has_child("center_of_rotation"))
{
ASCENT_INFO("Visit camera parameter \"center_of_rotation\" and \"center_of_rotation_set\" are recognized but currently have no effect");
}

if(camera_node.has_child("axis_3d_scale_flag") ||
camera_node.has_child("axis_3d_scale"))
{
ASCENT_INFO("Visit camera parameter \"axis_3d_scale\" and \"axis_3d_scale_flag\" are recognized but currently have no effect");
}

if(camera_node.has_child("shear"))
{
ASCENT_INFO("Visit camera parameter \"shear\" is recognized but currently has no effect");
}

if(camera_node.has_child("window_valid"))
{
ASCENT_INFO("Visit camera parameter \"window_valid\" is recognized but currently has no effect");
}
}

bool is_valid_name(const std::string &name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,6 @@ check_renders_surprises(const conduit::Node &renders_node)
r_valid_paths.push_back("image_width");
r_valid_paths.push_back("image_height");
r_valid_paths.push_back("scene_bounds");
r_valid_paths.push_back("camera/look_at");
r_valid_paths.push_back("camera/position");
r_valid_paths.push_back("camera/up");
r_valid_paths.push_back("camera/fov");
r_valid_paths.push_back("camera/xpan");
r_valid_paths.push_back("camera/ypan");
r_valid_paths.push_back("camera/zoom");
r_valid_paths.push_back("camera/near_plane");
r_valid_paths.push_back("camera/far_plane");
r_valid_paths.push_back("camera/azimuth");
r_valid_paths.push_back("camera/elevation");
r_valid_paths.push_back("type");
r_valid_paths.push_back("phi");
r_valid_paths.push_back("phi_range");
Expand Down Expand Up @@ -200,6 +189,45 @@ check_renders_surprises(const conduit::Node &renders_node)

std::vector<std::string> r_ignore_paths;
r_ignore_paths.push_back("phi_theta_positions");
r_ignore_paths.push_back("camera");

// Valid Ascent input camera format
std::vector<std::string> c_ascent_valid_paths;
c_ascent_valid_paths.push_back("2d");
c_ascent_valid_paths.push_back("look_at");
c_ascent_valid_paths.push_back("position");
c_ascent_valid_paths.push_back("up");
c_ascent_valid_paths.push_back("fov");
c_ascent_valid_paths.push_back("xpan");
c_ascent_valid_paths.push_back("ypan");
c_ascent_valid_paths.push_back("zoom");
c_ascent_valid_paths.push_back("near_plane");
c_ascent_valid_paths.push_back("far_plane");
c_ascent_valid_paths.push_back("azimuth");
c_ascent_valid_paths.push_back("elevation");

// Valid Visit input camera format
std::vector<std::string> c_visit_valid_paths;
c_visit_valid_paths.push_back("windowCoords");
c_visit_valid_paths.push_back("view_normal");
c_visit_valid_paths.push_back("focus");
c_visit_valid_paths.push_back("view_up");
c_visit_valid_paths.push_back("view_angle");
c_visit_valid_paths.push_back("parallel_scale");
c_visit_valid_paths.push_back("near_plane");
c_visit_valid_paths.push_back("far_plane");
c_visit_valid_paths.push_back("image_pan");
c_visit_valid_paths.push_back("image_zoom");
c_visit_valid_paths.push_back("perspective");
c_visit_valid_paths.push_back("eye_angle");
c_visit_valid_paths.push_back("center_of_rotation_set");
c_visit_valid_paths.push_back("center_of_rotation");
c_visit_valid_paths.push_back("axis_3d_scale_flag");
c_visit_valid_paths.push_back("axis_3d_scale");
c_visit_valid_paths.push_back("shear");
c_visit_valid_paths.push_back("window_valid");

std::vector<std::string> c_ignore_paths;

for(int i = 0; i < num_renders; ++i)
{
Expand All @@ -223,6 +251,22 @@ check_renders_surprises(const conduit::Node &renders_node)
}
}
}

if(render_node.has_path("camera"))
{
const conduit::Node &camera_node = render_node["camera"];
std::string c_ascent_surprises = surprise_check(c_ascent_valid_paths, c_ignore_paths, camera_node);
std::string c_visit_surprises = surprise_check(c_visit_valid_paths, c_ignore_paths, camera_node);

if(!c_ascent_surprises.empty() && !c_visit_surprises.empty())
{
surprises += "Cameras must follow either an ascent format or a visit format, not both.\n";
surprises += "\nAscent camera surpises:\n";
surprises += c_ascent_surprises;
surprises += "\nVisit camera surprises:\n";
surprises += c_visit_surprises;
}
}
}
return surprises;
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/tests/ascent/t_ascent_render_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@ TEST(ascent_render_2d, test_render_2d_cam)
scenes["scene1/renders/r1/camera/2d"] = {-10.0,10.0,-10.0,10.0};

scenes["scene1/renders/r2/image_prefix"] = output_file_v2;
scenes["scene1/renders/r2/camera/2d"] = {-20.0,20.0,-20.0,20.0};
scenes["scene1/renders/r2/camera/windowCoords"] = {-20.0,20.0,-20.0,20.0};

scenes["scene1/renders/r3/image_prefix"] = output_file_v3;
scenes["scene1/renders/r3/camera/2d"] = {-7.0,3.0,0.0,4.0};
scenes["scene1/renders/r3/camera/windowCoords"] = {-7.0,3.0,0.0,4.0};

scenes["scene1/renders/r4/image_prefix"] = output_file_v4;
scenes["scene1/renders/r4/camera/2d"] = {-10.0,0.0,-10.0,10.0};
Expand Down
Loading