diff --git a/CHANGELOG.md b/CHANGELOG.md index 89e5e4f11..5e06fe983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,10 @@ Notable changes to Ascent are documented in this file. This changelog started on The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project aspires to adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## Unreleased ### Preferred dependency versions for ascent@develop - conduit@0.9.2 -- vtk-m@2.1.0 (requires [patch 1](https://github.com/Alpine-DAV/ascent/blob/0aef6cffd522be7419651e6adf586f9a553297d0/scripts/build_ascent/2024_05_03_vtkm-mr3215-ext-geom-fix.patch) +- vtk-m@2.1.0 (requires [patch 1](https://github.com/Alpine-DAV/ascent/blob/0aef6cffd522be7419651e6adf586f9a553297d0/scripts/build_ascent/2024_05_03_vtkm-mr3215-ext-geom-fix.patch) [patch 2](https://github.com/Alpine-DAV/ascent/blob/develop/scripts/build_ascent/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch) ) - raja@2024.02.1 - umpire@2024.02.1 @@ -31,11 +31,12 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s - Added `fields` option to the project 2d to support scalar rendering of specific fields. - Added `dataset_bounds` option to the project 2d, which can be used instead of a full 3D camera specification - Added support for triggers to execute actions from multiple files via an `actions_files` option that takes a list of actions files. -- Added an `external_surfaces` transform filter, that can be used to reduce memory requirements in pipelines where you plan to only process the external faces of a data set. +- Added an `external_surfaces` transform filter, that can be used to reduce memory requirements in pipelines where you plan to only process the external faces of a data set. - Added a `declare_fields` action, that allows users to explicitly list the fields to return for field filtering. This option avoids complex field parsing logic. +- Added a 2d camera mode (`camera/2d: [left, right, bottom, top]`) to scene render cameras and the `project_2d` (scalar rendering) filter cameras. ### Changed -- Changed the replay utility's binary names such that `replay_ser` is now `ascent_replay` and `raplay_mpi` is now `ascent_replay_mpi`. This will help prevent potential name collisions with other tools that also have replay utilities. +- Changed the replay utility's binary names such that `replay_ser` is now `ascent_replay` and `raplay_mpi` is now `ascent_replay_mpi`. This will help prevent potential name collisions with other tools that also have replay utilities. ### Fixed - Resolved a few cases where MPI_COMM_WORLD was used instead instead of the selected MPI communicator. @@ -75,7 +76,7 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s ### Changed - Changed the Data Binning filter to accept a `reduction_field` parameter (instead of `var`), and similarly the axis parameters to take `field` (instead of `var`). The `var` style parameters are still accepted, but deprecated and will be removed in a future release. - Changed the Streamline and WarpXStreamline filters to apply the VTK-m Tube filter to their outputs, allowing for the results to be rendered. -- Updated CMake Python build infrastructure to use +- Updated CMake Python build infrastructure to use ### Fixed - Various small bug fixes @@ -128,12 +129,12 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s - Added extract `flatten` from Conduit Blueprint - Added Log base 10 filter. Filter type is `log10` - Added Log base 2 filter. Filter type is `log2` -- Added Feature Map in the docs. Detailing Devil Ray and VTKh features +- Added Feature Map in the docs. Detailing Devil Ray and VTKh features - Added `scripts/build_ascent/build_ascent.sh` a script that demonstrates how to manually build Ascent and its main dependencies - Added ability to override dimensions for the rendered bounding box around a dataset - Added CMake option `ENABLE_HIDDEN_VISIBILITY` (default=ON), which controls if hidden visibility is used for private symbols - Added documentation for how to use ROCm's rocprof profiler for GPUs with Ascent -- Added support for Caliper performance annotations +- Added support for Caliper performance annotations - Added automatic slice filter that evaluates a number of slices and outputs the one with the highest entropy ### Changed @@ -157,15 +158,15 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s - Added OCCA Derived Field Generation support - Added more math expressions - Added a time expression -- Added Cinema rendering support for Devil Ray -- Added `streamline` and `particle_advection` transforms +- Added Cinema rendering support for Devil Ray +- Added `streamline` and `particle_advection` transforms - Added history gradient expressions - Added the ability save named sessions - Added new options to specify Cinema rendering parameters - Added the ability save subsets of expression results to session files - Added the ability to add comments to PNG files that Ascent creates - Added timings out control option to Ascent (and Flow) -- Added support to render Polygonal nd Polyhedral Meshes +- Added support to render Polygonal nd Polyhedral Meshes - Added option to turn of world annotations - Added FIDES Support diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp index fe9bc7797..f6104abdb 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp @@ -87,14 +87,33 @@ parse_image_dims(const conduit::Node &node, int &width, int &height) } + //----------------------------------------------------------------------------- void parse_camera(const conduit::Node camera_node, vtkm::rendering::Camera &camera) { typedef vtkm::Vec<vtkm::Float32,3> vtkmVec3f; + // // Get the optional camera parameters // + + // check for 2d mode first + if(camera_node.has_child("2d")) + { + // 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(); + + camera.SetViewRange2D(view_vals[0], + view_vals[1], + view_vals[2], + view_vals[3]); + } + if(camera_node.has_child("look_at")) { conduit::Node n; @@ -248,8 +267,8 @@ parse_color_table(const conduit::Node &color_table_node) } else if (control_points_node.dtype().is_object()) { - if (control_points_node.has_child("r") && - control_points_node.has_child("g") && + if (control_points_node.has_child("r") && + control_points_node.has_child("g") && control_points_node.has_child("b")) { clear = true; diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_rendering_filters.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_rendering_filters.cpp index 8fbc6d5fc..8fe459da0 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_rendering_filters.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_rendering_filters.cpp @@ -147,6 +147,7 @@ check_renders_surprises(const conduit::Node &renders_node) const int num_renders = renders_node.number_of_children(); // render paths std::vector<std::string> r_valid_paths; + r_valid_paths.push_back("camera/2d"); r_valid_paths.push_back("image_name"); r_valid_paths.push_back("image_prefix"); r_valid_paths.push_back("image_width"); @@ -214,7 +215,7 @@ check_renders_surprises(const conduit::Node &renders_node) const conduit::Node &position = phi_theta_positions.child(i); std::stringstream ss; ss << "[" << i << "]"; - if (position.name() != ss.str()) + if (position.name() != ss.str()) { surprises += "Surprise parameter '"; surprises += position.name(); @@ -522,8 +523,8 @@ vtkh::Render parse_render(const conduit::Node &render_node, conduit::Node n; render_node["color_bar_position"].to_float32_array(n); const float32 *cb_pos = n.as_float32_ptr(); - vtkm::Bounds pos(vtkm::Range(cb_pos[0+4*i],cb_pos[1+4*i]), - vtkm::Range(cb_pos[2+4*i],cb_pos[3+4*i]), + vtkm::Bounds pos(vtkm::Range(cb_pos[0+4*i],cb_pos[1+4*i]), + vtkm::Range(cb_pos[2+4*i],cb_pos[3+4*i]), vtkm::Range(0.0,0.0)); cb_position.push_back(pos); } @@ -911,7 +912,7 @@ class CinemaManager void create_cinema_angles() { - for(int p = 0; p < m_phi_values.size(); ++p) + for(int p = 0; p < m_phi_values.size(); ++p) { for(int t = 0; t < m_theta_values.size(); ++t) { @@ -1267,13 +1268,13 @@ DefaultRender::execute() { float64_accessor d_bounds = render_node["dataset_bounds"].value(); int num_bounds = d_bounds.number_of_elements(); - + if(num_bounds != 6) { std::string render_name = renders_node.child_names()[i]; std::string fpath = filter_to_path(this->name()); ASCENT_ERROR("Render ("<<fpath<<"/"<<render_name<<")"<< - " only provided " << num_bounds << + " only provided " << num_bounds << " dataset_bounds when 6 are required:" << " [xMin,xMax,yMin,yMax,zMin,zMax]"); } @@ -1292,12 +1293,12 @@ DefaultRender::execute() } if(is_auto_camera) - { + { DataObject *source = graph().workspace().registry().fetch<DataObject>("source_object"); - + std::shared_ptr<VTKHCollection> collection = source->as_vtkh_collection(); - + if(!render_node.has_path("auto_camera/field")) ASCENT_ERROR("Auto Camera must specify a 'field'"); if(!render_node.has_path("auto_camera/metric")) @@ -1308,41 +1309,41 @@ DefaultRender::execute() std::string field_name = render_node["auto_camera/field"].as_string(); std::string metric = render_node["auto_camera/metric"].as_string(); int samples = render_node["auto_camera/samples"].as_int32(); - + if(!collection->has_field(field_name)) { ASCENT_ERROR("Unknown field '"<<field_name<<"' in Auto Camera"); } - + std::string topo_name = collection->field_topology(field_name); vtkh::DataSet &dataset = collection->dataset_by_topology(topo_name); - + vtkh::AutoCamera auto_cam; - + int height = 1024; int width = 1024; if(render_node.has_path("auto_camera/bins")) { int bins = render_node["auto_camera/bins"].as_int32(); - auto_cam.SetNumBins(bins); + auto_cam.SetNumBins(bins); } if(render_node.has_path("auto_camera/height")) { height = render_node["auto_camera/height"].as_int32(); - auto_cam.SetHeight(height); + auto_cam.SetHeight(height); } if(render_node.has_path("auto_camera/width")) { width = render_node["auto_camera/width"].as_int32(); - auto_cam.SetWidth(width); + auto_cam.SetWidth(width); } - + auto_cam.SetInput(&dataset); auto_cam.SetField(field_name); auto_cam.SetMetric(metric); auto_cam.SetNumSamples(samples); auto_cam.Update(); - + vtkm::rendering::Camera *camera = new vtkm::rendering::Camera; *camera = auto_cam.GetCamera(); vtkh::Render render = vtkh::MakeRender(width, @@ -1388,12 +1389,12 @@ DefaultRender::execute() scene_bounds = original_bounds; } } - + vtkh::Render render = vtkh::MakeRender(1024, 1024, scene_bounds, image_name); - + Node meta = Metadata::n_metadata; if(meta.has_path("comments")) { @@ -1444,7 +1445,7 @@ VTKHBounds::execute() { ASCENT_ERROR("VTKHBounds input must be a data object"); } - + DataObject *data_object = input<DataObject>(0); // data could be the result of a failed pipeline @@ -1453,7 +1454,7 @@ VTKHBounds::execute() std::shared_ptr<VTKHCollection> collection = data_object->as_vtkh_collection(); bounds->Include(collection->global_bounds()); } - + set_output<vtkm::Bounds>(bounds); } @@ -1801,7 +1802,7 @@ CreatePlot::execute() } - + if(type == "mesh") { @@ -1900,25 +1901,33 @@ ExecScene::declare_interface(conduit::Node &i) } //----------------------------------------------------------------------------- -void generate_camera_meshes(conduit::Node &image_data){ +void generate_camera_meshes(conduit::Node &image_data) +{ conduit::Node &camera = image_data["camera"]; + + if(camera.has_child("2d")) + { + // skip cam mesh for 2d cam mode + return; + } + conduit::Node &cam_frust = camera["camera_frustum_mesh"]; // std::string image_name = image_data["image_name"].as_string(); - + // Scene Bounds Mesh float64_accessor scene_bounds = image_data["scene_bounds"].value(); - double x_scene_bounds[] = {scene_bounds[0], scene_bounds[0], scene_bounds[0], scene_bounds[0], + double x_scene_bounds[] = {scene_bounds[0], scene_bounds[0], scene_bounds[0], scene_bounds[0], scene_bounds[3], scene_bounds[3], scene_bounds[3], scene_bounds[3]}; - double y_scene_bounds[] = {scene_bounds[1], scene_bounds[1], scene_bounds[4], scene_bounds[4], + double y_scene_bounds[] = {scene_bounds[1], scene_bounds[1], scene_bounds[4], scene_bounds[4], scene_bounds[1], scene_bounds[1], scene_bounds[4], scene_bounds[4]}; - double z_scene_bounds[] = {scene_bounds[2], scene_bounds[5], scene_bounds[5], scene_bounds[2], + double z_scene_bounds[] = {scene_bounds[2], scene_bounds[5], scene_bounds[5], scene_bounds[2], scene_bounds[2], scene_bounds[5], scene_bounds[5], scene_bounds[2]}; cam_frust["coordsets/scene_bounds_coords/type"] = "explicit"; cam_frust["coordsets/scene_bounds_coords/values/x"].set(x_scene_bounds, 8); cam_frust["coordsets/scene_bounds_coords/values/y"].set(y_scene_bounds, 8); cam_frust["coordsets/scene_bounds_coords/values/z"].set(z_scene_bounds, 8); - + cam_frust["topologies/scene_bounds_topo/type"] = "unstructured"; cam_frust["topologies/scene_bounds_topo/coordset"] = "scene_bounds_coords"; cam_frust["topologies/scene_bounds_topo/elements/shape"] = "line"; @@ -1937,14 +1946,14 @@ void generate_camera_meshes(conduit::Node &image_data){ // Initializing and normalizing up vector float64_accessor up = camera["up"].value(); vtkm::Vec<vtkm::Float64,3> vtkm_up(up[0], up[1], up[2]); - + vtkm::Vec<vtkm::Float64,3> forward(0,0,-1); double angle_between = vtkm::ACos(vtkm::Dot(forward, vtkm_look)) / vtkm::Pi() * 180; // If the look vector has been rotated by a certain angle, adjust the camera up vector to match if (vtkm::Abs(angle_between) >= 0.001) { vtkm::Vec<vtkm::Float64,3> axisOfRotation = vtkm::Cross(vtkm_look, forward); - vtkm_up = + vtkm_up = vtkm::Transform3DVector(vtkm::Transform3DRotate(-angle_between, axisOfRotation), vtkm_up); } vtkm::Normalize(vtkm_up); @@ -1965,24 +1974,24 @@ void generate_camera_meshes(conduit::Node &image_data){ // Near frustum double frust_near_height = near_dist * vtkm::Tan(fov * 0.5 * vtkm::Pi() / 180.0) / zoom; double frust_near_width = frust_near_height; - vtkm::Vec<vtkm::Float64,3> near_frust_ll = look_near_pt + (-1 * vtkm_up * frust_near_height) + vtkm::Vec<vtkm::Float64,3> near_frust_ll = look_near_pt + (-1 * vtkm_up * frust_near_height) + (vtkm_side * frust_near_width * image_aspect ); - vtkm::Vec<vtkm::Float64,3> near_frust_lr = look_near_pt + (-1 * vtkm_up * frust_near_height) + vtkm::Vec<vtkm::Float64,3> near_frust_lr = look_near_pt + (-1 * vtkm_up * frust_near_height) + (-1 * vtkm_side * frust_near_width * image_aspect); - vtkm::Vec<vtkm::Float64,3> near_frust_ur = look_near_pt + (vtkm_up * frust_near_height) + vtkm::Vec<vtkm::Float64,3> near_frust_ur = look_near_pt + (vtkm_up * frust_near_height) + (-1 * vtkm_side * frust_near_width * image_aspect); - vtkm::Vec<vtkm::Float64,3> near_frust_ul = look_near_pt + (vtkm_up * frust_near_height) + vtkm::Vec<vtkm::Float64,3> near_frust_ul = look_near_pt + (vtkm_up * frust_near_height) + (vtkm_side * frust_near_width * image_aspect); // Far frustum double frust_far_height = far_dist * vtkm::Tan(fov * 0.5 * vtkm::Pi() / 180.0) / zoom; double frust_far_width = frust_far_height; - vtkm::Vec<vtkm::Float64,3> far_frust_ll = look_far_pt + (-1 * vtkm_up * frust_far_height) + vtkm::Vec<vtkm::Float64,3> far_frust_ll = look_far_pt + (-1 * vtkm_up * frust_far_height) + (vtkm_side * frust_far_width * image_aspect); - vtkm::Vec<vtkm::Float64,3> far_frust_lr = look_far_pt + (-1 * vtkm_up * frust_far_height) + vtkm::Vec<vtkm::Float64,3> far_frust_lr = look_far_pt + (-1 * vtkm_up * frust_far_height) + (-1 * vtkm_side * frust_far_width * image_aspect); - vtkm::Vec<vtkm::Float64,3> far_frust_ur = look_far_pt + (vtkm_up * frust_far_height) + vtkm::Vec<vtkm::Float64,3> far_frust_ur = look_far_pt + (vtkm_up * frust_far_height) + (-1 * vtkm_side * frust_far_width * image_aspect); - vtkm::Vec<vtkm::Float64,3> far_frust_ul = look_far_pt + (vtkm_up * frust_far_height) + vtkm::Vec<vtkm::Float64,3> far_frust_ul = look_far_pt + (vtkm_up * frust_far_height) + (vtkm_side * frust_far_width * image_aspect); // Assembling frustum mesh @@ -1996,7 +2005,7 @@ void generate_camera_meshes(conduit::Node &image_data){ double z_val_frust[] = {near_frust_ll[2],near_frust_lr[2],near_frust_ur[2],near_frust_ul[2], far_frust_ll[2], far_frust_lr[2], far_frust_ur[2], far_frust_ul[2], look_near_pt[2], look_far_pt[2], up_vector_pt[2]}; - + cam_frust["coordsets/camera_frustum_coords/type"] = "explicit"; cam_frust["coordsets/camera_frustum_coords/values/x"].set(x_val_frust, 11); cam_frust["coordsets/camera_frustum_coords/values/y"].set(y_val_frust, 11); @@ -2057,13 +2066,30 @@ ExecScene::execute() image_data["image_width"] = renders->at(i).GetWidth(); image_data["image_height"] = renders->at(i).GetHeight(); - image_data["camera/position"].set(&renders->at(i).GetCamera().GetPosition()[0],3); - image_data["camera/look_at"].set(&renders->at(i).GetCamera().GetLookAt()[0],3); - image_data["camera/up"].set(&renders->at(i).GetCamera().GetViewUp()[0],3); - image_data["camera/zoom"] = renders->at(i).GetCamera().GetZoom(); - image_data["camera/fov"] = renders->at(i).GetCamera().GetFieldOfView(); - image_data["camera/near_plane"] = renders->at(i).GetCamera().GetClippingRange().Min; - image_data["camera/far_plane"] = renders->at(i).GetCamera().GetClippingRange().Max; + // check for 2d vs 3d camera + if(renders->at(i).GetCamera().GetMode() == vtkm::rendering::Camera::Mode::TwoD) + { + vtkm::Bounds bounds = renders->at(i).GetCamera().GetViewRange2D(); + double view_2d[4] = {bounds.X.Min, + bounds.Y.Min, + bounds.X.Max, + bounds.Y.Max}; + + image_data["camera/2d"].set(view_2d,4); + } + else + { + image_data["camera/position"].set(&renders->at(i).GetCamera().GetPosition()[0],3); + image_data["camera/look_at"].set(&renders->at(i).GetCamera().GetLookAt()[0],3); + image_data["camera/up"].set(&renders->at(i).GetCamera().GetViewUp()[0],3); + image_data["camera/zoom"] = renders->at(i).GetCamera().GetZoom(); + image_data["camera/fov"] = renders->at(i).GetCamera().GetFieldOfView(); + image_data["camera/near_plane"] = renders->at(i).GetCamera().GetClippingRange().Min; + image_data["camera/far_plane"] = renders->at(i).GetCamera().GetClippingRange().Max; + } + auto pan_vals = renders->at(i).GetCamera().GetPan(); + image_data["camera/xpan"] = pan_vals[0]; + image_data["camera/ypan"] = pan_vals[1]; vtkm::Bounds bounds= renders->at(i).GetSceneBounds(); double coord_bounds [6] = {bounds.X.Min, bounds.Y.Min, @@ -2071,7 +2097,7 @@ ExecScene::execute() bounds.X.Max, bounds.Y.Max, bounds.Z.Max}; - + image_data["scene_bounds"].set(coord_bounds, 6); generate_camera_meshes(image_data); diff --git a/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_1_100.png b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_1_100.png new file mode 100644 index 000000000..1f47cc254 Binary files /dev/null and b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_1_100.png differ diff --git a/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_2_100.png b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_2_100.png new file mode 100644 index 000000000..e830a7113 Binary files /dev/null and b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_2_100.png differ diff --git a/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_3_100.png b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_3_100.png new file mode 100644 index 000000000..203c86337 Binary files /dev/null and b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_3_100.png differ diff --git a/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_4_100.png b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_4_100.png new file mode 100644 index 000000000..aa96f1f80 Binary files /dev/null and b/src/tests/_baseline_images/tout_render_2d_uniform_2d_cam_view_4_100.png differ diff --git a/src/tests/ascent/t_ascent_render_2d.cpp b/src/tests/ascent/t_ascent_render_2d.cpp index ee3d19e10..e5de102b4 100644 --- a/src/tests/ascent/t_ascent_render_2d.cpp +++ b/src/tests/ascent/t_ascent_render_2d.cpp @@ -406,6 +406,91 @@ TEST(ascent_render_2d, test_render_2d_uniform_render_serial_backend) EXPECT_TRUE(check_test_image(output_file)); } +//----------------------------------------------------------------------------- +TEST(ascent_render_2d, test_render_2d_cam) +{ + + // the vtkm runtime is currently our only rendering runtime + Node n; + ascent::about(n); + // only run this test if ascent was built with vtkm support + if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled") + { + ASCENT_INFO("Ascent vtkm support disabled, skipping test"); + return; + } + + ASCENT_INFO("Testing 2D Ascent Runtime 2d camera controls"); + + // + // Create an example mesh. + // + Node data, verify_info; + conduit::blueprint::mesh::examples::braid("uniform", + EXAMPLE_MESH_SIDE_DIM, + EXAMPLE_MESH_SIDE_DIM, + 0, + data); + + EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info)); + + string output_path = prepare_output_dir(); + string output_file_base = conduit::utils::join_file_path(output_path, "tout_render_2d_uniform_2d_cam"); + string output_file_v1 = output_file_base + "_view_1_"; + string output_file_v2 = output_file_base + "_view_2_"; + string output_file_v3 = output_file_base + "_view_3_"; + string output_file_v4 = output_file_base + "_view_4_"; + string output_info = output_file_base + "_info"; + // remove old images before rendering + remove_test_image(output_file_v1); + remove_test_image(output_file_v2); + remove_test_image(output_file_v3); + remove_test_image(output_file_v4); + + // + // Create the actions. + // + Node actions; + conduit::Node &add_scenes = actions.append(); + add_scenes["action"] = "add_scenes"; + conduit::Node &scenes = add_scenes["scenes"]; + scenes["scene1/plots/plt1/type"] = "pseudocolor"; + scenes["scene1/plots/plt1/field"] = "braid"; + + scenes["scene1/renders/r1/image_prefix"] = output_file_v1; + 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/r3/image_prefix"] = output_file_v3; + scenes["scene1/renders/r3/camera/2d"] = {-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}; + scenes["scene1/renders/r4/image_width"] = 512; + scenes["scene1/renders/r4/image_height"] = 1024; + + + conduit::Node info; + + Ascent ascent; + ascent.open(); + ascent.publish(data); + ascent.execute(actions); + ascent.info(info); + ascent.close(); + + std::cout << info.to_yaml() << std::endl; + + // check output + EXPECT_TRUE(check_test_image(output_file_v1)); + EXPECT_TRUE(check_test_image(output_file_v2)); + EXPECT_TRUE(check_test_image(output_file_v3)); + EXPECT_TRUE(check_test_image(output_file_v4)); +} + + //----------------------------------------------------------------------------- TEST(ascent_render_2d, test_render_2d_bentgrid_example) { diff --git a/src/tests/ascent/t_ascent_scalar_renderer.cpp b/src/tests/ascent/t_ascent_scalar_renderer.cpp index 257dce26f..57ce66f4d 100644 --- a/src/tests/ascent/t_ascent_scalar_renderer.cpp +++ b/src/tests/ascent/t_ascent_scalar_renderer.cpp @@ -226,7 +226,7 @@ TEST(ascent_scalar_rendering, test_scalar_rendering_data_bounds_specified) conduit::relay::io::blueprint::save_mesh(data,conduit::utils::join_file_path(output_path, "tout_scalar_rendering_bounds_specified_input"),"hdf5"); - + // // Create the actions. // @@ -275,6 +275,77 @@ TEST(ascent_scalar_rendering, test_scalar_rendering_data_bounds_specified) ASCENT_ACTIONS_DUMP(actions,output_file,msg); } +//----------------------------------------------------------------------------- +TEST(ascent_scalar_rendering, test_scalar_rendering_2d_camera) +{ + // the vtkm runtime is currently our only rendering runtime + Node n; + ascent::about(n); + // only run this test if ascent was built with vtkm support + if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled") + { + ASCENT_INFO("Ascent support disabled, skipping test"); + return; + } + + + // + // Create an example mesh. + // + Node data, verify_info; + conduit::blueprint::mesh::examples::braid("quads", + EXAMPLE_MESH_SIDE_DIM, + EXAMPLE_MESH_SIDE_DIM, + 0, + data); + + EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info)); + + ASCENT_INFO("Testing Scalar Rendering with a 2d camera"); + + + string output_path = prepare_output_dir(); + string output_file = conduit::utils::join_file_path(output_path,"tout_scalar_rendering_2d_camera"); + + conduit::relay::io::blueprint::save_mesh(data,conduit::utils::join_file_path(output_path, + "tout_scalar_rendering_2d_camera_input"),"hdf5"); + + // + // Create the actions. + // + + conduit::Node actions; + // add the pipeline + conduit::Node &add_pipelines= actions.append(); + add_pipelines["action"] = "add_pipelines"; + conduit::Node &pipelines = add_pipelines["pipelines"]; + pipelines["pl1/f1/type"] = "project_2d"; + conduit::Node ¶ms = pipelines["pl1/f1/params"]; + params["image_width"] = 512; + params["image_height"] = 512; + params["camera/2d"] = { -7.0, 3.0, 0.0,4.0 }; + + // add the extracts + conduit::Node &add_extracts = actions.append(); + add_extracts["action"] = "add_extracts"; + conduit::Node &extracts=add_extracts["extracts"];; + extracts["e1/type"] = "relay"; + extracts["e1/pipeline"] = "pl1"; + extracts["e1/params/path"] = output_file; + extracts["e1/params/protocol"] = "blueprint/mesh/hdf5"; + + + Ascent ascent; + ascent.open(); + ascent.publish(data); + ascent.execute(actions); + ascent.close(); + + // check that we created an image + std::string msg = "An example of scalar rendering with 2d camera mode"; + ASCENT_ACTIONS_DUMP(actions,output_file,msg); +} + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) {