NVIDIA Index example code nvidia_logo_transpbg.gif Up
embedded_heightfield_geometry.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 *****************************************************************************/
6
7#include <nv/index/icamera.h>
8#include <nv/index/iconfig_settings.h>
9#include <nv/index/idata_sample.h>
10#include <nv/index/iindex.h>
11#include <nv/index/ilight.h>
12#include <nv/index/imaterial.h>
13#include <nv/index/iregular_heightfield.h>
14#include <nv/index/iheightfield_pick_result.h>
15#include <nv/index/iscene.h>
16#include <nv/index/isession.h>
17#include <nv/index/itexture_filter_mode.h>
18#include <nv/index/isparse_volume_rendering_properties.h>
19
20#include "utility/app_rendering_context.h"
21#include "utility/canvas_utility.h"
22#include "utility/example_shared.h"
23
24#include <nv/index/app/idata_analysis_and_processing.h>
25#include <nv/index/app/index_connect.h>
26#include <nv/index/app/string_dict.h>
27
28#include <iostream>
29#include <sstream>
30
31//----------------------------------------------------------------------
33 public nv::index::app::Index_connect
34{
35public:
37 :
38 Index_connect()
39 {
40 // INFO_LOG << "DEBUG: Embedded_heightfield_geometry() ctor";
41 }
42
44 {
45 // Note: Index_connect::~Index_connect() will be called after here.
46 // INFO_LOG << "DEBUG: ~Embedded_heightfield_geometry() dtor";
47 }
48
49 // launch application
50 mi::Sint32 launch();
51
52protected:
53 virtual bool evaluate_options(nv::index::app::String_dict& sdict) CPP11_OVERRIDE;
54 // override
56 mi::neuraylib::INetwork_configuration* network_configuration,
57 nv::index::app::String_dict& options) CPP11_OVERRIDE
58 {
59 check_success(network_configuration != 0);
60
61 check_success(options.is_defined("unittest"));
62 const bool is_unittest = nv::index::app::get_bool(options.get("unittest"));
63 if (is_unittest)
64 {
65 info_cout("NETWORK: disabled networking mode.", options);
66 network_configuration->set_mode(mi::neuraylib::INetwork_configuration::MODE_OFF);
67 return true;
68 }
69
70 return initialize_networking_as_default_udp(network_configuration, options);
71 }
72
73private:
74 void setup_camera(nv::index::IPerspective_camera* cam) const;
75 void pick_call(
76 const mi::math::Vector_struct<mi::Uint32, 2>& pick_location,
77 mi::neuraylib::IDice_transaction* dice_transaction) const;
78 void setup_scene(mi::neuraylib::IDice_transaction* dice_transaction);
79 // render a frame
80 // \param[in] output_fname output rendering image filename
81 // \return performance values
82 nv::index::IFrame_results* render_frame(const std::string& output_fname) const;
83
84 // This session tag
85 mi::neuraylib::Tag m_session_tag;
86 // NVIDIA IndeX cluster configuration
87 mi::base::Handle<nv::index::ICluster_configuration> m_cluster_configuration;
88 // Application layer image file canvas (a render target)
89 mi::base::Handle<nv::index::app::canvas_infrastructure::IIndex_image_file_canvas> m_image_file_canvas;
90 mi::base::Handle<nv::index::IIndex_scene_query> m_index_query;
91 // Create_icons options
92 std::string m_outfname;
93 bool m_is_unittest;
94 std::string m_verify_image_fname;
95 std::string m_heightfield;
96 std::string m_mask;
97 std::string m_geometry;
98 std::string m_voxel_format;
99 std::string m_render;
100 mi::Float32 m_size;
101 std::string m_texture;
102 bool m_use_texture;
103 bool m_zoom;
104 bool m_pick;
105 mi::Uint32 m_supersampling;
106};
107
108//----------------------------------------------------------------------
110{
111 mi::Sint32 exit_code = 0;
112 {
113 m_cluster_configuration = get_index_interface()->get_api_component<nv::index::ICluster_configuration>();
114 check_success(m_cluster_configuration.is_valid_interface());
115
116 // create image canvas in application_layer
117 m_image_file_canvas = create_image_file_canvas(get_application_layer_interface());
118 check_success(m_image_file_canvas.is_valid_interface());
119
120 m_index_query = get_index_interface()->get_api_component<nv::index::IIndex_scene_query>();
121 check_success(m_index_query.is_valid_interface());
122
123 // Verify that the local host has joined, this may fail when there is a license problem
124 check_success(is_local_host_joined(m_cluster_configuration.get()));
125
126 {
127 // Create our DiCE transaction
128 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
129 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
130 check_success(dice_transaction.is_valid_interface());
131 {
132 // Create an IndeX session
133 m_session_tag = m_index_session->create_session(dice_transaction.get());
134 check_success(m_session_tag.is_valid());
135
136 if(m_supersampling > 0)
137 {
138 mi::base::Handle<const nv::index::ISession> session(
139 dice_transaction->access<const nv::index::ISession>(m_session_tag));
140 check_success(session.is_valid_interface());
141
142 mi::base::Handle<nv::index::IConfig_settings> config_settings(
143 dice_transaction->edit<nv::index::IConfig_settings>(session->get_config()));
144 check_success(config_settings.is_valid_interface());
145
146 // Enable supersampling
147 config_settings->set_rendering_samples(m_supersampling);
148 }
149
150
151 // Create the scene
152 setup_scene(dice_transaction.get());
153 }
154 dice_transaction->commit();
155 }
156
157 // Render the scene
158 {
159 const mi::Sint32 frame_idx = 0;
160 const std::string fname = get_output_file_name(m_outfname, frame_idx);
161 m_image_file_canvas->set_rgba_file_name(fname.c_str());
162
163 mi::base::Handle<nv::index::IFrame_results> frame_results(render_frame(fname));
164 const mi::base::Handle<nv::index::IError_set> err_set(frame_results->get_error_set());
165 if (err_set->any_errors())
166 {
167 std::ostringstream os;
168
169 const mi::base::Handle<nv::index::IError_set> err_set(frame_results->get_error_set());
170 const mi::Uint32 nb_err = err_set->get_nb_errors();
171 for (mi::Uint32 e = 0; e < nb_err; ++e)
172 {
173 if (e != 0) os << '\n';
174 const mi::base::Handle<nv::index::IError> err(err_set->get_error(e));
175 os << err->get_error_string();
176 }
177
178 ERROR_LOG << "IIndex_rendering rendering call failed with the following error(s): " << '\n'
179 << os.str();
180 exit_code = 1;
181 }
182
183 // Verify the generated image
184 if (!verify_canvas_result(get_application_layer_interface(),
185 m_image_file_canvas.get(), m_verify_image_fname, get_options()))
186 {
187 exit_code = 1;
188 }
189 }
190
191 // Picking
192 {
193 // Create our DiCE transaction
194 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
195 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
196 check_success(dice_transaction.is_valid_interface());
197 {
198 if (m_pick)
199 {
200 pick_call(mi::math::Vector<mi::Uint32, 2>(386, 322), dice_transaction.get());
201 pick_call(mi::math::Vector<mi::Uint32, 2>(98, 318), dice_transaction.get());
202 pick_call(mi::math::Vector<mi::Uint32, 2>(422, 555), dice_transaction.get());
203 pick_call(mi::math::Vector<mi::Uint32, 2>(1024 - 962, 1024 - 453), dice_transaction.get());
204
205 // Picks a line in zoom mode
206 pick_call(mi::math::Vector<mi::Uint32, 2>(524, 496), dice_transaction.get());
207
208 // Pick a point in zoom mode
209 pick_call(mi::math::Vector<mi::Uint32, 2>(405, 578), dice_transaction.get());
210 }
211 }
212 // Finish the picking transaction
213 dice_transaction->commit();
214 }
215 }
216 return exit_code;
217}
218
219//----------------------------------------------------------------------
220bool Embedded_heightfield_geometry::evaluate_options(nv::index::app::String_dict& sdict)
221{
222 const std::string com_name = sdict.get("command:", "<unknown_command>");
223 m_is_unittest = nv::index::app::get_bool(sdict.get("unittest", "false"));
224
225 if (m_is_unittest)
226 {
227 if (nv::index::app::get_bool(sdict.get("is_call_from_test", "false")))
228 {
229 sdict.insert("is_dump_comparison_image_when_failed", "0");
230 }
231 sdict.insert("outfname", ""); // turn off file output in the unit test mode
232 sdict.insert("dice::verbose", "2");
233 }
234
235 m_outfname = sdict.get("outfname");
236 m_verify_image_fname = sdict.get("verify_image_fname");
237 m_heightfield = sdict.get("heightfield");
238 m_mask = sdict.get("mask");
239 m_geometry = sdict.get("geometry");
240 m_voxel_format = sdict.get("voxel_format");
241 m_render = sdict.get("render");
242 m_size = nv::index::app::get_float32(sdict.get("size"));
243 m_texture = sdict.get("texture");
244 m_use_texture = (m_texture != "none");
245 m_zoom = nv::index::app::get_bool(sdict.get("zoom", "false"));
246 m_pick = nv::index::app::get_bool(sdict.get("pick", "false"));
247 m_supersampling = nv::index::app::get_uint32(sdict.get("supersampling"));
248
249 info_cout("running " + com_name, sdict);
250 info_cout("outfname = [" + m_outfname +
251 "], verify_image_fname = [" + m_verify_image_fname +
252 "], dice::verbose = " + sdict.get("dice::verbose"), sdict);
253
254 // print help and exit if -h
255 if (sdict.is_defined("h"))
256 {
257 std::cout
258 << "info: Usage: " << com_name << " [option]\n"
259 << "Option: [-h]\n"
260 << " print out this message\n"
261 << " [-dice::verbose severity_level]\n"
262 << " verbose severity level (3 is info). (default: " + sdict.get("dice::verbose") << ")\n"
263
264 << " [-outfname string]\n"
265 << " output ppm file base name. When empty, no output.\n"
266 << " A frame number and extension (.ppm) will be added.\n"
267 << " (default: [" << m_outfname << "])\n"
268
269 << " [-verify_image_fname image_fname]\n"
270 << " when image_fname exist, verify the rendering image.\n"
271 << " (default: [" << m_verify_image_fname << "])\n"
272
273 << " [-unittest bool]\n"
274 << " when true, unit test mode.\n"
275 << " (default: [" << m_is_unittest << "])\n"
276
277 << " [-heightfield ppm_file]\n"
278 << " filename of a grayscale PPM image that represents the heightfield.\n"
279 << " (default: [" << m_heightfield << "])\n"
280
281 << " [-mask pgm_file]\n"
282 << " filename of a monochrome PGM image that will be used as a mask on the heightfield,\n"
283 << " creating hole and therefore isolated points and connecting lines.\n"
284 << " (default: [" << m_mask << "])\n"
285
286 << " [-geometry mode]\n"
287 << " NOTE: THIS MODE == volume IS DISABLED.\n"
288 << " color modes for embedded heightfield geometry.\n"
289 << " Available modes: none, fixed, material, volume, texture\n"
290 << " (default: [" << m_geometry << "])\n"
291
292 << " [-voxel_format format]\n"
293 << " voxel format for the volume geometry mode.\n"
294 << " Available formats: uint8, rgba8\n"
295 << " (default: [" << m_voxel_format << "])\n"
296
297 << " [-render mode]\n"
298 << " rendering modes for embedded heightfield geometry.\n"
299 << " Available modes: z-axis, screen, raster\n"
300 << " (default: [" << m_render << "])\n"
301
302 << " [-size float]\n"
303 << " geometry size for z-axis or screen, ignored for raster.\n"
304 << " (default: [" << m_size << "])\n"
305
306 << " [-texture mode]\n"
307 << " map a computed texture onto the heightfield.\n"
308 << " Available modes: none, mandelbrot\n"
309 << " (default: " << m_texture << ")\n"
310
311 << " [-zoom bool]\n"
312 << " zoom in to show details of the geometry.\n"
313 << " (default: [" << m_zoom << "])\n"
314
315 << " [-pick bool]\n"
316 << " apply picking operation at various screen positions.\n"
317 << " (default: [" << m_pick << "])\n"
318
319 << " [-supersampling int]\n"
320 << " apply supersampling using the given number of samples. If set to '0' supersampling is disabled.\n"
321 << " (default: [" << m_supersampling << "])\n"
322
323 << std::endl;
324
325 std::exit(1);
326 }
327 return true;
328}
329
330//----------------------------------------------------------------------
331void Embedded_heightfield_geometry::setup_camera(nv::index::IPerspective_camera* cam) const
332{
333 // Set the camera parameters to see the whole scene
334 mi::math::Vector<mi::Float32, 3> from;
335 mi::math::Vector<mi::Float32, 3> to;
336 mi::math::Vector<mi::Float32, 3> up(0.f, 0.f, 1.0);
337
338 if (m_zoom)
339 {
340 from = mi::math::Vector<mi::Float32, 3>(200.f, 60.f, 100.f);
341 to = mi::math::Vector<mi::Float32, 3>(170.f, 20.f, 70.f);
342 }
343 else
344 {
345 from = mi::math::Vector<mi::Float32, 3>(-0.f, -50.f, 200.f);
346 to = mi::math::Vector<mi::Float32, 3>(150.f, 150.f, 0.f);
347 }
348
349 mi::math::Vector<mi::Float32, 3> viewdir = to - from;
350 viewdir.normalize();
351
352 cam->set(from, viewdir, up);
353 cam->set_aperture(0.033f);
354 cam->set_aspect(1.0f);
355 cam->set_focal(0.03f);
356 cam->set_clip_min(2.0f);
357 cam->set_clip_max(1000.0f);
358}
359
360//----------------------------------------------------------------------
361void Embedded_heightfield_geometry::pick_call(
362 const mi::math::Vector_struct<mi::Uint32, 2>& pick_location,
363 mi::neuraylib::IDice_transaction* dice_transaction) const
364{
365 INFO_LOG << "Picking at screen position: " << pick_location;
366
367 // Run the picking operation
368 mi::base::Handle<nv::index::IScene_pick_results> scene_pick_results(
369 m_index_query->pick(pick_location, m_image_file_canvas.get(), m_session_tag, dice_transaction));
370
371 // Print the picking result
372 const mi::Uint32 nb_results = scene_pick_results->get_nb_results();
373 if (nb_results > 0)
374 {
375 INFO_LOG << "Number of pick results: " << nb_results;
376 for (mi::Uint32 i=0; i < nb_results; i++)
377 {
378 // Generic information
379 const mi::base::Handle<nv::index::IScene_pick_result> result(scene_pick_results->get_result(i));
380
381 std::stringstream log_out;
382 log_out << "Intersection no. " << i << "\n"
383 << "\t\t Element (tag) " << result->get_scene_element().id << "\n"
384 << "\t\t Sub index: " << result->get_scene_element_sub_index() << "\n"
385 << "\t\t Distance: " << result->get_distance() << "\n"
386 << "\t\t Position (local space): " << result->get_intersection() << "\n"
387 << "\t\t Color (evaluated): " << result->get_color() << "\n";
388
389 const mi::base::Handle<const nv::index::IData_sample> data_sample(result->get_data_sample());
390 if (data_sample)
391 {
392 const mi::base::Handle<const nv::index::IData_sample_uint8> ds_uint8(data_sample->get_interface<const nv::index::IData_sample_uint8>());
393 const mi::base::Handle<const nv::index::IData_sample_uint16> ds_uint16(data_sample->get_interface<const nv::index::IData_sample_uint16>());
394 const mi::base::Handle<const nv::index::IData_sample_float32> ds_float32(data_sample->get_interface<const nv::index::IData_sample_float32>());
395 const mi::base::Handle<const nv::index::IData_sample_rgba8> ds_rgba8(data_sample->get_interface<const nv::index::IData_sample_rgba8>());
396 if (ds_uint8) {
397 log_out << "\t Data sample: " << mi::Uint32(ds_uint8->get_sample_value()) << "\n";
398 }
399 else if (ds_uint16) {
400 log_out << "\t Data sample: " << ds_uint16->get_sample_value() << "\n";
401 }
402 else if (ds_float32) {
403 log_out << "\t Data sample: " << ds_float32->get_sample_value() << "\n";
404 }
405 else if (ds_rgba8) {
406 log_out << "\t Data sample: " << ds_rgba8->get_sample_value() << "\n";
407 }
408 }
409
410 INFO_LOG << log_out.str();
411
412 // Shape-specific information
413 if (result->get_intersection_info_class() == nv::index::IHeightfield_pick_result::IID())
414 {
415 mi::base::Handle<const nv::index::IHeightfield_pick_result> compute_pick_result(
416 result->get_interface<const nv::index::IHeightfield_pick_result>());
417 if (compute_pick_result && compute_pick_result->is_computing_enabled())
418 {
419 INFO_LOG << "Specific pick results for computed heightfield texture:";
420 INFO_LOG << "\t Computed color value: " << compute_pick_result->get_computed_color();
421 }
422 }
423 }
424 }
425 else
426 {
427 INFO_LOG << "No result at pick position: " << pick_location;
428 }
429}
430
431//----------------------------------------------------------------------
432void Embedded_heightfield_geometry::setup_scene(
433 mi::neuraylib::IDice_transaction* dice_transaction)
434{
435 // Access the session
436 mi::base::Handle<const nv::index::ISession> session(
437 dice_transaction->access<nv::index::ISession>(m_session_tag));
438 check_success(session.is_valid_interface());
439
440 // Edit the scene
441 mi::base::Handle<nv::index::IScene> scene_edit(
442 dice_transaction->edit<nv::index::IScene>(session->get_scene()));
443 check_success(scene_edit.is_valid_interface());
444
445 // Create static group node where all the scene elements will be attached
446 mi::base::Handle<nv::index::IStatic_scene_group> static_group_node(
447 scene_edit->create_scene_group<nv::index::IStatic_scene_group>());
448 check_success(static_group_node.is_valid_interface());
449
450 mi::neuraylib::Tag colormap_tag;
451 if (m_geometry == "volume")
452 {
453 // Create a color map using an external utility function.
454 const mi::Sint32 colormap_entry_id = 40; // same as demo application's colormap file 40
455 colormap_tag = create_colormap(colormap_entry_id, scene_edit.get(), dice_transaction);
456 check_success(colormap_tag.is_valid());
457 }
458
459 // Create the heightfield
460 mi::neuraylib::Tag heightfield_tag;
461 const mi::math::Vector<mi::Uint32, 2> heightfield_size(300, 300);
462 const mi::math::Vector<mi::Float32, 2> elevation_range(0.f, 300.f);
463 {
464 // Creating a ppm heightfield importer.
465 nv::index::app::String_dict heightfield_opt;
466 heightfield_opt.insert("args::type", "heightfield");
467 heightfield_opt.insert("args::importer", "nv::index::plugin::legacy_importer.PPM_heightfield_importer");
468 heightfield_opt.insert("args::input_file", m_heightfield);
469 {
470 std::stringstream sstr;
471 sstr << heightfield_size.x << " " << heightfield_size.y;
472 heightfield_opt.insert("args::size", sstr.str());
473 }
474 heightfield_opt.insert("args::importer_scale", "0.3");
475 heightfield_opt.insert("args::importer_offset", "0");
476 heightfield_opt.insert("args::importer_binary_mask", m_mask);
477 {
478 std::stringstream sstr;
479 sstr << elevation_range.x << " " << elevation_range.y;
480 heightfield_opt.insert("args::range", sstr.str());
481 }
482 nv::index::IDistributed_data_import_callback* importer_callback =
483 get_importer_from_application_layer(
484 get_application_layer_interface(),
485 "nv::index::plugin::legacy_importer.PPM_heightfield_importer",
486 heightfield_opt);
487
488 // Heightfield scene element
489 const mi::Float32 rotate_k = 0.f;
490 const mi::math::Vector<mi::Float32, 3> translate(0.f, 0.f, 1.f);
491 const mi::math::Vector<mi::Float32, 3> scale(1.f, 1.f, 1.f);
492 mi::base::Handle<nv::index::IRegular_heightfield> heightfield_scene_element(
493 scene_edit->create_regular_heightfield(
494 scale, rotate_k, translate,
495 heightfield_size,
496 elevation_range,
497 importer_callback,
498 dice_transaction));
499 check_success(heightfield_scene_element.is_valid_interface());
500
501 if (m_geometry == "volume")
502 {
503 // Enable volume mapping for the heightfield
504 heightfield_scene_element->set_colormap_mapping(true);
505 heightfield_scene_element->assign_colormap(colormap_tag);
506 }
507
508 heightfield_tag = dice_transaction->store_for_reference_counting(heightfield_scene_element.get());
509 check_success(heightfield_tag.is_valid());
510 }
511
512 // Add a light, a material, a rendering property, and a colormap
513 {
514 // Light
515 mi::base::Handle<nv::index::IDirectional_headlight> headlight(
516 scene_edit->create_attribute<nv::index::IDirectional_headlight>());
517 check_success(headlight.is_valid_interface());
518 const mi::math::Color color_intensity(1.f, 1.f, 1.f, 1.f);
519 headlight->set_intensity(color_intensity);
520 headlight->set_direction(mi::math::Vector<mi::Float32, 3>(1.f, -1.f, -1.f));
521 const mi::neuraylib::Tag headlight_tag = dice_transaction->store_for_reference_counting(headlight.get());
522 check_success(headlight_tag.is_valid());
523 static_group_node->append(headlight_tag, dice_transaction);
524
525 // Material for the heightfield
526 mi::base::Handle<nv::index::IPhong_gl> material(scene_edit->create_attribute<nv::index::IPhong_gl>());
527 check_success(material.is_valid_interface());
528
529 if (m_use_texture)
530 {
531 // Use just ambient white with texture
532 material->set_ambient(mi::math::Color(1.f));
533 material->set_diffuse(mi::math::Color(0.f));
534 material->set_specular(mi::math::Color(0.f));
535 }
536 else
537 {
538 // Define a more interesting greenish material
539 material->set_ambient(mi::math::Color(0.f, 0.1f, 0.0f));
540 material->set_diffuse(mi::math::Color(0.f, 0.8f, 0.2f));
541 material->set_specular(mi::math::Color(0.3f));
542 material->set_shininess(100.f);
543 }
544
545 const mi::neuraylib::Tag material_tag
546 = dice_transaction->store_for_reference_counting(material.get());
547 check_success(material_tag.is_valid());
548 static_group_node->append(material_tag, dice_transaction);
549
550 // Add a sparse_volume_render_properties to the scene.
551 mi::base::Handle<nv::index::ISparse_volume_rendering_properties> sparse_render_prop(
552 scene_edit->create_attribute<nv::index::ISparse_volume_rendering_properties>());
553 sparse_render_prop->set_filter_mode(nv::index::SPARSE_VOLUME_FILTER_NEAREST);
554 sparse_render_prop->set_sampling_distance( 1.0);
555 sparse_render_prop->set_reference_sampling_distance( 1.0);
556 sparse_render_prop->set_voxel_offsets( mi::math::Vector<mi::Float32, 3>(0.0f, 0.0f, 0.0f));
557 sparse_render_prop->set_preintegrated_volume_rendering(false);
558 sparse_render_prop->set_lod_rendering_enabled( false);
559 sparse_render_prop->set_lod_pixel_threshold( 2.0);
560 sparse_render_prop->set_debug_visualization_option( 0);
561 const mi::neuraylib::Tag sparse_render_prop_tag
562 = dice_transaction->store_for_reference_counting(sparse_render_prop.get());
563 check_success(sparse_render_prop_tag.is_valid());
564 static_group_node->append(sparse_render_prop_tag, dice_transaction);
565
566 // Add a colormap to the scene.
567 const mi::Sint32 colormap_entry_id = 1; // same as demo application's colormap file 1
568 const mi::neuraylib::Tag colormap_tag =
569 create_colormap(colormap_entry_id, scene_edit.get(), dice_transaction);
570 check_success(colormap_tag.is_valid());
571 static_group_node->append(colormap_tag, dice_transaction);
572 }
573
574 // Optionally map a computed texture onto the heightfield
575 if (m_use_texture)
576 {
577 // Mandelbrot texture
578 if (m_texture == "mandelbrot")
579 {
580 mi::base::Handle<nv::index::ITexture_filter_mode> tex_filter(
581 scene_edit->create_attribute<nv::index::ITexture_filter_mode_nearest_neighbor>());
582 check_success(tex_filter.is_valid_interface());
583 mi::neuraylib::Tag tex_filter_tag = dice_transaction->store_for_reference_counting(tex_filter.get());
584 check_success(tex_filter_tag.is_valid());
585 static_group_node->append(tex_filter_tag, dice_transaction);
586
587 // Access an application layer component that provides some sample techniques such as the mandelbrot for 2d surfaces:
588 mi::base::Handle<nv::index::app::data_analysis_and_processing::IData_analysis_and_processing> processing(
589 get_application_layer_interface()->get_api_component<nv::index::app::data_analysis_and_processing::IData_analysis_and_processing>());
590 // Create a mandelbrot technique and add it to the scene. For more details on how to implement the mandelbrot, please review the provided
591 // source that was shipped with the application layer component 'nv::index::app::data_analysis_and_processing::IData_analysis_and_processing'.
592 // Create the computed texture, with a size fitting the heightfield:
593 mi::base::Handle<nv::index::app::data_analysis_and_processing::ISample_tool_set> tool_set(processing->get_sample_tool_set());
594 mi::base::Handle<nv::index::IDistributed_compute_technique> mapping(
595 tool_set->create_mandelbrot_2d_technique(
596 mi::math::Vector<mi::Float32, 2>(heightfield_size), nv::index::IDistributed_compute_destination_buffer_2d_texture::FORMAT_RGBA_FLOAT32));
597
598 // Add the mapping to the scene before the heightfield
599 mi::neuraylib::Tag mapping_tag = dice_transaction->store_for_reference_counting(mapping.get());
600 check_success(mapping_tag.is_valid());
601 static_group_node->append(mapping_tag, dice_transaction);
602 }
603 else
604 {
605 ERROR_LOG << "Unknown texture mode '" << m_texture << "'";
606 check_success(false);
607 }
608 }
609
610 // Configure rendering of the embedded geometry
611 if (m_geometry == "fixed")
612 {
613 // Rendering mode
614 nv::index::IHeightfield_geometry_settings::Render_mode render_mode =
615 nv::index::IHeightfield_geometry_settings::RENDER_DEFAULT;
616 if (m_render == "z-axis")
617 {
618 render_mode = nv::index::IHeightfield_geometry_settings::RENDER_Z_AXIS_ALIGNED;
619 }
620 else if (m_render == "screen")
621 {
622 render_mode = nv::index::IHeightfield_geometry_settings::RENDER_SCREEN_ALIGNED;
623 }
624 else if (m_render == "raster")
625 {
626 render_mode = nv::index::IHeightfield_geometry_settings::RENDER_RASTERIZED;
627
628 // Use fixed geometry size in rasterized mode (only use for picking)
629 m_size = 2.0f;
630 }
631 else
632 {
633 ERROR_LOG << "Unknown render mode '" << m_render << "'";
634 check_success(false);
635 }
636
637 //
638 // Use separate settings for points and lines
639 //
640
641 // Settings for isolated points
642 mi::base::Handle<nv::index::IHeightfield_geometry_settings> point_settings(
643 scene_edit->create_attribute<nv::index::IHeightfield_geometry_settings>());
644 check_success(point_settings.is_valid_interface());
645 // Apply this attribute only to isolated points
646 point_settings->set_type_mask(nv::index::IHeightfield_geometry_settings::TYPE_ISOLATED_POINTS);
647 // Use a fixed color with no lighting
648 point_settings->set_color_mode(nv::index::IHeightfield_geometry_settings::MODE_FIXED);
649 // Blue points please
650 point_settings->set_color(mi::math::Color(0.f, 0.f, 1.f));
651 // Enable rendering of seed points
652 point_settings->set_visible(true);
653 // Set requested render mode
654 point_settings->set_render_mode(render_mode);
655 // Line width / point radius
656 point_settings->set_geometry_size(m_size);
657
658 const mi::neuraylib::Tag point_settings_tag
659 = dice_transaction->store_for_reference_counting(point_settings.get());
660 check_success(point_settings_tag.is_valid());
661 static_group_node->append(point_settings_tag, dice_transaction);
662
663 // Settings for seed lines
664 mi::base::Handle<nv::index::IHeightfield_geometry_settings> line_settings(
665 scene_edit->create_attribute<nv::index::IHeightfield_geometry_settings>());
666 check_success(line_settings.is_valid_interface());
667 // Apply this attribute only to connecting lines
668 line_settings->set_type_mask(nv::index::IHeightfield_geometry_settings::TYPE_CONNECTING_LINES);
669 // Use a fixed color with no lighting
670 line_settings->set_color_mode(nv::index::IHeightfield_geometry_settings::MODE_FIXED);
671 // Red lines please
672 line_settings->set_color(mi::math::Color(1.f, 0.f, 0.f));
673 // Enable rendering of seed lines
674 line_settings->set_visible(true);
675 // Set requested render mode
676 line_settings->set_render_mode(render_mode);
677 // Line width / point radius
678 line_settings->set_geometry_size(m_size);
679
680 const mi::neuraylib::Tag line_settings_tag
681 = dice_transaction->store_for_reference_counting(line_settings.get());
682 check_success(line_settings_tag.is_valid());
683 static_group_node->append(line_settings_tag, dice_transaction);
684 }
685 else if (m_geometry != "none")
686 {
687 //
688 // Use the same settings for points and lines
689 //
690 mi::base::Handle<nv::index::IHeightfield_geometry_settings> geometry_settings(
691 scene_edit->create_attribute<nv::index::IHeightfield_geometry_settings>());
692 check_success(geometry_settings.is_valid_interface());
693
694 // Apply this attribute to both isolated points and connecting lines
695 geometry_settings->set_type_mask(
696 nv::index::IHeightfield_geometry_settings::TYPE_ISOLATED_POINTS |
697 nv::index::IHeightfield_geometry_settings::TYPE_CONNECTING_LINES);
698
699 if (m_geometry == "material")
700 {
701 // Apply the heightfield material on the embedded geometry
702 geometry_settings->set_color_mode(nv::index::IHeightfield_geometry_settings::MODE_MATERIAL);
703 }
704 else if (m_geometry == "volume")
705 {
706 // Map the volume texture on the embedded geometry
707 geometry_settings->set_color_mode(nv::index::IHeightfield_geometry_settings::MODE_VOLUME_TEXTURE);
708 }
709 else if (m_geometry == "texture")
710 {
711 // Map the computed heightfield texture on the embedded geometry
712 geometry_settings->set_color_mode(nv::index::IHeightfield_geometry_settings::MODE_COMPUTED_TEXTURE);
713 }
714 else
715 {
716 ERROR_LOG << "Unknown geometry mode '" << m_geometry << "'";
717 check_success(false);
718 }
719
720 // Set color to white (the default), it will modulate the material or texture color
721 geometry_settings->set_color(mi::math::Color(1.f, 1.f, 1.f));
722 // Enable rendering (default)
723 geometry_settings->set_visible(true);
724
725 const mi::neuraylib::Tag geometry_settings_tag
726 = dice_transaction->store_for_reference_counting(geometry_settings.get());
727 check_success(geometry_settings_tag.is_valid());
728 static_group_node->append(geometry_settings_tag, dice_transaction);
729 }
730
731 // Create an artifical volume if requested
732 if (m_geometry == "volume")
733 {
734 // Set up parameter for the synthetic volume generation technique
735 const mi::math::Vector<mi::Uint32, 3> volume_size(
736 heightfield_size.x, heightfield_size.y, static_cast<mi::Uint32>(elevation_range.y));
737 const mi::math::Bbox<mi::Uint32, 3> bbox(
738 mi::math::Vector<mi::Uint32, 3>(0), volume_size);
739
740 // Creating a sparse volume synthetic volume generator.
741 nv::index::app::String_dict sparse_volume_opt;
742 sparse_volume_opt.insert("args::type", "sparse_volume");
743 sparse_volume_opt.insert("args::importer", "synthetic");
744 std::stringstream sstr;
745 sstr << "0 0 0 " << volume_size.x << " " << volume_size.y << " " << volume_size.z;
746 sparse_volume_opt.insert("args::bbox", sstr.str());
747 sparse_volume_opt.insert("args::voxel_format", "uint8");
748 sparse_volume_opt.insert("args::synthetic_type", "sphere_0");
749 nv::index::IDistributed_data_import_callback* importer_callback =
750 get_importer_from_application_layer(
751 get_application_layer_interface(),
752 "nv::index::plugin::base_importer.Sparse_volume_generator_synthetic",
753 sparse_volume_opt);
754 const mi::math::Bbox<mi::Float32, 3> ijk_bbox(0.0f, 0.0f, 0.0f,
755 static_cast<mi::Float32>(volume_size.x),
756 static_cast<mi::Float32>(volume_size.y),
757 static_cast<mi::Float32>(volume_size.z));
758 const mi::math::Matrix<mi::Float32, 4, 4> transform_mat(1.0f); // Identity matrix
759 mi::base::Handle<nv::index::ISparse_volume_scene_element> volume_scene_element(
760 scene_edit->create_sparse_volume(ijk_bbox, transform_mat, importer_callback, dice_transaction));
761 check_success(volume_scene_element.is_valid_interface());
762
763 // Do not render the volume directly, just map it onto the heightfield
764 volume_scene_element->set_enabled(false);
765
766 const mi::neuraylib::Tag volume_tag = dice_transaction->store_for_reference_counting(volume_scene_element.get());
767 check_success(volume_tag.is_valid());
768
769 static_group_node->append(volume_tag, dice_transaction);
770 }
771
772 // Append the heightfield to the scene group after all other scene elements
773 static_group_node->append(heightfield_tag, dice_transaction);
774 mi::neuraylib::Tag static_group_node_tag =
775 dice_transaction->store_for_reference_counting(static_group_node.get());
776 check_success(static_group_node_tag.is_valid());
777
778 // Append the static scene group to the scene
779 scene_edit->append(static_group_node_tag, dice_transaction);
780
781 // Create a camera and adjust its parameters
782 mi::base::Handle< nv::index::IPerspective_camera > cam(
783 scene_edit->create_camera<nv::index::IPerspective_camera>());
784 check_success(cam.is_valid_interface());
785 setup_camera(cam.get());
786
787 const mi::neuraylib::Tag camera_tag = dice_transaction->store(cam.get());
788 check_success(camera_tag.is_valid());
789
790 scene_edit->set_camera(camera_tag);
791
792 const mi::math::Vector<mi::Uint32, 2> buffer_resolution(1024, 1024);
793 m_image_file_canvas->set_resolution(buffer_resolution);
794
795 // Define the region of interest
796 const mi::math::Bbox<mi::Float32, 3> region_of_interest(
797 0.f, 0.f, 0.f,
798 static_cast<mi::Float32>(heightfield_size.x),
799 static_cast<mi::Float32>(heightfield_size.y),
800 static_cast<mi::Float32>(elevation_range.y));
801 scene_edit->set_clipped_bounding_box(region_of_interest);
802}
803
804//----------------------------------------------------------------------
805nv::index::IFrame_results* Embedded_heightfield_geometry::render_frame(const std::string& output_fname) const
806{
807 check_success(m_index_rendering.is_valid_interface());
808
809 // set output filename, empty string is valid
810 m_image_file_canvas->set_rgba_file_name(output_fname.c_str());
811
812 check_success(m_session_tag.is_valid());
813
814 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
815 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
816 check_success(dice_transaction.is_valid_interface());
817
818 m_index_session->update(m_session_tag, dice_transaction.get());
819
820 mi::base::Handle<nv::index::IFrame_results> frame_results(
821 m_index_rendering->render(
822 m_session_tag,
823 m_image_file_canvas.get(),
824 dice_transaction.get()));
825 check_success(frame_results.is_valid_interface());
826
827 dice_transaction->commit();
828
829 frame_results->retain();
830 return frame_results.get();
831}
832
833//----------------------------------------------------------------------
834int main(int argc, const char* argv[])
835{
836 nv::index::app::String_dict sdict;
837 sdict.insert("dice::verbose", "3"); // log level
838 sdict.insert("outfname", "frame_embedded_heightfield_geometry"); // output file base name
839 sdict.insert("verify_image_fname", ""); // for unit test
840 sdict.insert("unittest", "0"); // unit test mode
841
842 sdict.insert("heightfield", "../embedded_heightfield_geometry/spiral.ppm");
843 sdict.insert("mask", "../embedded_heightfield_geometry/spiral-mask.pgm");
844 sdict.insert("texture", "none");
845 sdict.insert("geometry", "fixed");
846 sdict.insert("voxel_format", "uint8");
847 sdict.insert("render", "z-axis");
848 sdict.insert("size", "0.5");
849 sdict.insert("zoom", "0");
850 sdict.insert("pick", "1");
851 sdict.insert("supersampling", "0");
852 sdict.insert("is_dump_comparison_image_when_failed", "1"); // default: dump images when failed.
853 sdict.insert("is_call_from_test", "0"); // default: not call from make check.
854
855 // Disabled until height_field can reference a sparse volume in the test code 2020-02-24
856 if (sdict.get("geometry") == "volume")
857 {
858 ERROR_LOG << "geometry == volume is currently not supported.";
859 return 1;
860 }
861
862 // Load IndeX library via Index_connect
863 sdict.insert("dice::network::mode", "OFF");
864
865 // index setting
866 sdict.insert("index::config::set_monitor_performance_values", "true");
867 sdict.insert("index::service", "rendering_and_compositing");
868 sdict.insert("index::cuda_debug_checks", "false");
869
870 // application_layer component loading
871 sdict.insert("index::app::components::application_layer::component_name_list",
872 "canvas_infrastructure image io data_analysis_and_processing");
873 sdict.insert("index::app::plugins::base_importer::enabled", "true");
874 sdict.insert("index::app::plugins::legacy_importer::enabled", "true");
875
876 // Initialize application
877 Embedded_heightfield_geometry embedded_heightfield_geometry;
878 embedded_heightfield_geometry.initialize(argc, argv, sdict);
879 check_success(embedded_heightfield_geometry.is_initialized());
880
881 // launch the application. creating the scene and rendering.
882 const mi::Sint32 exit_code = embedded_heightfield_geometry.launch();
883 INFO_LOG << "Shutting down ...";
884
885 return exit_code;
886}
virtual bool evaluate_options(nv::index::app::String_dict &sdict) CPP11_OVERRIDE
virtual bool initialize_networking(mi::neuraylib::INetwork_configuration *network_configuration, nv::index::app::String_dict &options) CPP11_OVERRIDE
int main(int argc, const char *argv[])
#define check_success(expr)