NVIDIA Index example code nvidia_logo_transpbg.gif Up
normal_recalculation.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 *****************************************************************************/
6
7#include <mi/dice.h>
8
9// Include code shared by all examples.
10#include "utility/example_shared.h"
11#include "utility/index_resource.h"
12
13#include <nv/index/icamera.h>
14#include <nv/index/iconfig_settings.h>
15#include <nv/index/idata_distribution.h>
16#include <nv/index/iindex.h>
17#include <nv/index/ilight.h>
18#include <nv/index/imaterial.h>
19#include <nv/index/iregular_heightfield_patch.h>
20#include <nv/index/iscene.h>
21#include <nv/index/isession.h>
22
23#include <nv/index/app/index_connect.h>
24#include <nv/index/app/string_dict.h>
25
26#include "utility/app_rendering_context.h"
27#include "utility/canvas_utility.h"
28
29#include <iostream>
30#include <sstream>
31
32//----------------------------------------------------------------------
34 public nv::index::app::Index_connect
35{
36public:
38 :
39 Index_connect(),
40 m_heightfield_tag(mi::neuraylib::NULL_TAG),
41 m_frame_idx(0)
42 {
43 // INFO_LOG << "DEBUG: Normal_recalculation() ctor";
44 }
45
47 {
48 // Note: Index_connect::~Index_connect() will be called after here.
49 // INFO_LOG << "DEBUG: ~Normal_recalculation() dtor";
50 }
51
52 // launch application
53 mi::Sint32 launch();
54
55protected:
56 virtual bool evaluate_options(nv::index::app::String_dict& sdict) CPP11_OVERRIDE;
57 // override
59 mi::neuraylib::INetwork_configuration* network_configuration,
60 nv::index::app::String_dict& options) CPP11_OVERRIDE
61 {
62 check_success(network_configuration != 0);
63
64 check_success(options.is_defined("unittest"));
65 const bool is_unittest = nv::index::app::get_bool(options.get("unittest"));
66 if (is_unittest)
67 {
68 info_cout("NETWORK: disabled networking mode.", options);
69 network_configuration->set_mode(mi::neuraylib::INetwork_configuration::MODE_OFF);
70 return true;
71 }
72
73 return initialize_networking_as_default_udp(network_configuration, options);
74 }
75
76private:
77 // Render one frame
78 // \return true when test success.
79 bool render_frame(const std::string& output_fname,
80 const std::string& verify_fname);
81 // Get next frame index. This index will be incremented when
82 // render_frame() called.
83 //
84 // \return current frame index
85 mi::Sint32 get_next_frame_idx() const
86 {
87 return m_frame_idx;
88 }
89 // Compute heightfield
90 //
91 // Note: Only the arguments is_normal_recalc and
92 // is_set_constant_normal are considered for normal
93 // computation. The value sdict.get("use_normal_recalculation") is
94 // disregarded.
95 //
96 // \param[in] is_normal_recalc recalculate normal on when true
97 // \param[in] is_set_constant_normal set constant normal when true (if is_normal_recalc false).
98 // \param[in] compute_id user defined compute call id
99 void compute_heightfield(
100 bool is_normal_recalc,
101 bool is_set_constant_normal,
102 mi::Sint32 compute_id);
103 // Create the scene.
104 void create_scene();
105 // Camera setup to see all the scene.
106 // \param[in] cam the camera
107 void setup_camera(nv::index::IPerspective_camera* cam) const;
108
109
110 // This session tag
111 mi::neuraylib::Tag m_session_tag;
112 // NVIDIA IndeX cluster configuration
113 mi::base::Handle<nv::index::ICluster_configuration> m_cluster_configuration;
114 // Application layer image file canvas (a render target)
115 mi::base::Handle<nv::index::app::canvas_infrastructure::IIndex_image_file_canvas> m_image_file_canvas;
116 // Create_icons options
117 std::string m_outfbase;
118 bool m_is_unittest;
119 std::string m_verify_image_path_base;
120 mi::math::Vector<mi::Uint32, 2> m_heightfield_size;
121 std::string m_heightfield_infile;
122 mi::math::Vector<mi::Float32, 2> m_heightfield_range;
123 mi::math::Vector<mi::Sint32, 2> m_use_normal_recalc;
124 mi::math::Vector<mi::Sint32, 2> m_set_normal_const;
125 mi::neuraylib::Tag m_heightfield_tag;
126 mi::Sint32 m_frame_idx;
127 mi::math::Bbox<mi::Float32, 3> m_roi;
128};
129
130//----------------------------------------------------------------------
132{
133 m_cluster_configuration = get_index_interface()->get_api_component<nv::index::ICluster_configuration>();
134 check_success(m_cluster_configuration.is_valid_interface());
135
136 // create image canvas in application_layer
137 m_image_file_canvas = create_image_file_canvas(get_application_layer_interface());
138 check_success(m_image_file_canvas.is_valid_interface());
139
140 // Verifying that local host has joined
141 // This may fail when there is a license problem.
142 check_success(is_local_host_joined(m_cluster_configuration.get()));
143
144 mi::Sint32 exit_code = 0;
145 create_scene();
146
147 // render one frame
148 {
149 const mi::Sint32 fidx = get_next_frame_idx();
150 const std::string outfbase = get_output_file_name(m_outfbase, fidx);
151 const std::string refimg_fname = get_output_file_name(m_verify_image_path_base, fidx);
152 check_success(render_frame(outfbase, refimg_fname));
153 }
154
155 INFO_LOG << "use_normal_recalc: " << m_use_normal_recalc
156 << ", set_normal_const: " << m_set_normal_const;
157
158 mi::Sint32 compute_id = 0; // tell the compute task which compute this is.
159 {
160 const bool is_normal_recalc = (m_use_normal_recalc.x == 1) ? true : false;
161 const bool is_set_constant_normal = (m_set_normal_const.x == 1) ? true : false;
162 compute_heightfield(is_normal_recalc, is_set_constant_normal, compute_id);
163
164 const mi::Sint32 fidx = get_next_frame_idx();
165 const std::string outfbase = get_output_file_name(m_outfbase, fidx);
166 const std::string refimg_fname = get_output_file_name(m_verify_image_path_base, fidx);
167 check_success(render_frame(outfbase, refimg_fname));
168 }
169
170 // edit (restore) height values of the heightfield and render one frame
171 ++compute_id;
172 {
173 const bool is_normal_recalc = (m_use_normal_recalc.y == 1) ? true : false;
174 const bool is_set_constant_normal = (m_set_normal_const.y == 1) ? true : false;
175 compute_heightfield(is_normal_recalc, is_set_constant_normal, compute_id);
176
177 const mi::Sint32 fidx = get_next_frame_idx();
178 const std::string outfbase = get_output_file_name(m_outfbase, fidx);
179 const std::string refimg_fname = get_output_file_name(m_verify_image_path_base, fidx);
180 check_success(render_frame(outfbase, refimg_fname));
181 }
182
183 return exit_code;
184}
185
186//----------------------------------------------------------------------
187bool Normal_recalculation::evaluate_options(nv::index::app::String_dict& sdict)
188{
189 const std::string com_name = sdict.get("command:", "<unknown_command>");
190 m_is_unittest = nv::index::app::get_bool(sdict.get("unittest", "false"));
191
192 if (m_is_unittest)
193 {
194 if (nv::index::app::get_bool(sdict.get("is_call_from_test", "false")))
195 {
196 sdict.insert("is_dump_comparison_image_when_failed", "0");
197 }
198 sdict.insert("dice::verbose", "2");
199 sdict.insert("outfbase", "");
200 }
201
202 // Set own options
203 m_outfbase = sdict.get("outfbase", "");
204 m_verify_image_path_base = sdict.get("verify_image_path_base", "");
205 m_heightfield_size = nv::index::app::get_vector_from_string<mi::Uint32,2> (sdict.get("heightfield_size"));
206 m_heightfield_infile = sdict.get("heightfield_infile");
207 m_heightfield_range = nv::index::app::get_vector_from_string<mi::Float32,2>(sdict.get("heightfield_range"));
208 m_use_normal_recalc = nv::index::app::get_vector_from_string<mi::Sint32,2> (sdict.get("use_normal_recalc"));
209 m_set_normal_const = nv::index::app::get_vector_from_string<mi::Sint32,2> (sdict.get("set_normal_const"));
210 m_roi = nv::index::app::get_bbox_from_string<mi::Float32,3>(sdict.get("roi"));
211
212
213 // Check necessary arguments for this example
214 if (m_heightfield_infile.empty())
215 {
216 ERROR_LOG << "No -heightfield_infile option specified. Need -heightfield_file.";
217 return false;
218 }
219 if (m_heightfield_size == mi::math::Vector<mi::Uint32, 2>(0, 0))
220 {
221 ERROR_LOG << "Invalid heightfield_size (0, 0). Need -heightfield_size.";
222 return false;
223 }
224 if (m_heightfield_range == mi::math::Vector<mi::Float32,2>(0.0f, 0.0f))
225 {
226 ERROR_LOG << "Invalid heightfield_range (0, 0). Need -heightfield_range.";
227 return false;
228 }
229
230 info_cout(std::string("running ") + com_name, sdict);
231 info_cout("outfbase = [" + m_outfbase +
232 "], verify_image_fname = [" + m_verify_image_path_base +
233 "], dice::verbose = " + sdict.get("dice::verbose"), sdict);
234
235 // print help and exit if -h
236 if (sdict.is_defined("h"))
237 {
238 std::cout
239 << "info: Usage: " << com_name << " [option]\n"
240 << "Option: [-h]\n"
241 << " print out this message\n"
242 << " [-dice::verbose severity_level]\n"
243 << " verbose severity level (3 is info).\n"
244 << " (default: " << sdict.get("dice::verbose") << ")\n"
245
246 << " [-heightfield_size 'int int']\n"
247 << " Heightfield size heightfield.\n"
248 << " (default: [" << m_heightfield_size << "])\n"
249
250 << " [-heightfield_infile FILENAME]\n"
251 << " Heightfield input file path name.\n"
252 << " (default: [" << m_heightfield_infile << "])\n"
253
254 << " [-heightfield_range 'float float']\n"
255 << " Heightfield height range.\n"
256 << " (default: [" << m_heightfield_range << "])\n"
257
258 << " [-use_normal_recalc 'INT INT']\n"
259 << " Use normal recalculation of the height field when true.\n"
260 << " The first INT is for the first edit, the second INT is for the second edit.\n"
261 << " Use INT here since no BOOL vector. False when INT is 0, true when INT is 1.\n"
262 << " (default: [" << sdict.get("use_normal_recalc") << "])\n"
263
264 << " [-set_normal_const 'INT INT']\n"
265 << " Set normal a constant vector of the height field when true.\n"
266 << " The first INT is for the first edit, the second INT is for the second edit.\n"
267 << " This option is only effective when corresponding use_normal_recalc option is false.\n"
268 << " Use INT here since no BOOL vector. False when INT is 0, true when INT is 1.\n"
269 << " (default: [" << sdict.get("set_normal_const") << "])\n"
270
271 << " [-outfbase FILENAME]\n"
272 << " output ppm file base name. When empty, no output.\n"
273 << " A frame number and extension (.ppm) will be added.\n"
274 << " (default: [" << m_outfbase << "])\n"
275
276 << " [-verify_image_path_base FILEBASE]\n"
277 << " when FILEBAS exists, verify the rendering image with adding frame number.\n"
278 << " (default: [" << m_verify_image_path_base << "])\n"
279
280 << "\n"
281 << "Test and debug option\n"
282 << "\n"
283
284 << " [-unittest bool]\n"
285 << " when true, unit test mode.\n"
286 << " (default: [" << m_is_unittest << "])\n"
287
288 << std::endl;
289 exit(1);
290 }
291
292 return true;
293}
294
295//======================================================================
296// Heightfield fill task example (height value negation operation)
297//
299 public mi::base::Interface_implement<nv::index::IRegular_heightfield_compute_task>
300{
301public:
302 // Constructor
303 //
304 // You can use an arbitrary compute_id to specify the compute
305 // task for test purpose. This is caller defined any value.
306 //
307 // \param[in] is_normal_recalc normal recalculation when true
308 // \param[in] is_set_constant_normal set constant normal (0,1,0) to every normal value
309 // when is_normal_recalc is false.
310 // \param[in] compute_id compute id (for test)
311 Example_height_fill_task(bool is_normal_recalc,
312 bool is_set_constant_normal,
313 mi::Sint32 compute_id)
314 :
315 m_is_normal_recalc(is_normal_recalc),
316 m_is_set_constant_normal(is_set_constant_normal),
317 m_compute_id(compute_id)
318 {
319 // empty
320 }
321
322 // implement IRegular_heightfield_compute_task
323
325 mi::math::Bbox_struct<mi::Sint32, 2>& roi) const
326 {
327 // empty. This example applies whole region of interest.
328 }
329
330 // Compute height value with automatically recalculate the
331 // normal value by the IndeX library.
332 virtual bool compute(
333 const mi::math::Bbox_struct<mi::Sint32, 2>& ij_patch_bbox,
334 mi::Float32* elevation_values,
335 mi::neuraylib::IDice_transaction* dice_transaction) const
336 {
337 INFO_LOG << "Example_height_fill_task: called with automatic normal calculation. compute_id: "
338 << m_compute_id;
339
340 mi::math::Bbox<mi::Sint64, 2> ij_patch_bbox_s64;
341 ij_patch_bbox_s64.min.x = static_cast< mi::Sint64 >(ij_patch_bbox.min.x);
342 ij_patch_bbox_s64.min.y = static_cast< mi::Sint64 >(ij_patch_bbox.min.y);
343 ij_patch_bbox_s64.max.x = static_cast< mi::Sint64 >(ij_patch_bbox.max.x);
344 ij_patch_bbox_s64.max.y = static_cast< mi::Sint64 >(ij_patch_bbox.max.y);
345
346 this->compute_elevation_value(ij_patch_bbox_s64, elevation_values);
347 if (m_is_set_constant_normal)
348 {
349 WARN_LOG << "Turn off the is_set_constant_normal since is_normal_recalc is on.";
350 }
351
352 return true;
353 }
354
355 // Compute height value, but intentionally made the normal value
356 // unchanged.
357 //
358 // If m_is_set_constant_normal is true, set the (0,1,0) normal
359 // everywhere for test.
360 virtual bool compute(
361 const mi::math::Bbox_struct<mi::Sint32, 2>& ij_patch_bbox,
362 mi::Float32* elevation_values,
363 mi::math::Vector_struct<mi::Float32, 3>* normal_values,
364 mi::neuraylib::IDice_transaction* dice_transaction) const
365 {
366 std::string normal_set_type = "";
367 if (m_is_set_constant_normal)
368 {
369 normal_set_type = "set constant";
370 }
371 else
372 {
373 normal_set_type = "empty";
374 }
375 INFO_LOG << "Example_height_fill_task: called with (" << normal_set_type
376 << ") user defined normal calculation. compute_id: " << m_compute_id;
377
378 mi::math::Bbox<mi::Sint64, 2> ij_patch_bbox_s64;
379 ij_patch_bbox_s64.min.x = static_cast< mi::Sint64 >(ij_patch_bbox.min.x);
380 ij_patch_bbox_s64.min.y = static_cast< mi::Sint64 >(ij_patch_bbox.min.y);
381 ij_patch_bbox_s64.max.x = static_cast< mi::Sint64 >(ij_patch_bbox.max.x);
382 ij_patch_bbox_s64.max.y = static_cast< mi::Sint64 >(ij_patch_bbox.max.y);
383
384 this->compute_elevation_value(ij_patch_bbox_s64, elevation_values);
385 if (m_is_set_constant_normal)
386 {
387 this->compute_normal_value(ij_patch_bbox_s64, normal_values);
388 }
389
390 return true;
391 }
392
394 {
395 if (m_is_normal_recalc)
396 {
397 return false;
398 }
399 return true;
400 }
401
402private:
403 // Compute elevation value
404 //
405 // \param[in] ij_patch_bbox_s64 local patch bounding box
406 // \param[out] elevation_values (out) generated elevation value array
407 void compute_elevation_value(
408 const mi::math::Bbox<mi::Sint64, 2>& ij_patch_bbox_s64,
409 mi::Float32 * elevation_values) const
410 {
411 INFO_LOG << "Compute_elevation_value (negation): ij patch bbox:" << ij_patch_bbox_s64;
412
413 // Size of the heightfield patch in memory
414 mi::math::Vector<mi::Sint64, 2> patch_raw_dim = ij_patch_bbox_s64.max - ij_patch_bbox_s64.min;
415 inline_template_argument_ignore_fn(patch_raw_dim);
416 assert((patch_raw_dim[0] > 0) && (patch_raw_dim[1] > 0));
417
418 mi::math::Vector<mi::Sint64, 2> ij = ij_patch_bbox_s64.min;
419 for(ij[0] = ij_patch_bbox_s64.min[0]; ij[0] < ij_patch_bbox_s64.max[0]; ++ij[0])
420 {
421 for(ij[1] = ij_patch_bbox_s64.min[1]; ij[1] < ij_patch_bbox_s64.max[1]; ++ij[1])
422 {
423 mi::Sint64 const ij_idx = get_heightfield_index(ij, ij_patch_bbox_s64);
424 assert(ij_idx >= 0);
425 assert(ij_idx < patch_raw_dim[0] * patch_raw_dim[1]);
426
427 if (!nv::index::IRegular_heightfield_patch::is_hole(elevation_values[ij_idx]))
428 {
429 elevation_values[ij_idx] = -1.0f * elevation_values[ij_idx];
430 }
431 }
432 }
433 }
434
435 // Compute normal value ... set constant normal
436 //
437 // \param[in] ij_patch_bbox_s64 local patch bounding box
438 // \param[out] normal_data (out) generated normal value array
439 void compute_normal_value(const mi::math::Bbox<mi::Sint64, 2>& ij_patch_bbox_s64,
440 mi::math::Vector_struct<mi::Float32, 3>* normal_values) const
441 {
442 const mi::math::Vector<mi::Sint64, 2> patch_raw_dim =
443 ij_patch_bbox_s64.max - ij_patch_bbox_s64.min;
444 assert((patch_raw_dim[0] > 0) && (patch_raw_dim[1] > 0));
445 mi::Sint64 const patch_raw_size = patch_raw_dim[0] * patch_raw_dim[1];
446
447 const mi::math::Vector<mi::Float32, 3> normal_vec(0.0f, -1.0f, 0.0f);
448 INFO_LOG << "Example_height_fill_task: set all normal to " << normal_vec;
449 for(mi::Sint64 i = 0; i < patch_raw_size; i++)
450 {
451 normal_values[i] = normal_vec;
452 }
453 }
454
455private:
456 // recompute normal or not
457 bool m_is_normal_recalc;
458 // set constant normal (0,1,0) for test.
459 bool m_is_set_constant_normal;
460 // compute id for test
461 mi::Sint32 m_compute_id;
462};
463
464//======================================================================
465// Height field operation example.
467 public nv::index::Distributed_data_job<0xc1a29939,0x5853,0x4406,0x91,0x95,0xa6,0x9f,0xb3,0x28,0x6f,0xfb>
468{
469public:
470 // Constructor
471 //
472 // \param[in] heightfield_tag Tag of the heightfield scene element
473 // \param[in] is_normal_recalc switch for automatic normal recalculation or not
474 // \param[in] is_set_constant_normal set constant normal (0,1,0) to every normal value
475 // when is_normal_recalc is false.
476 // \param[in] compute_id compute id for test (user defined value)
478 const mi::neuraylib::Tag& heightfield_tag,
479 bool is_normal_recalc,
480 bool is_set_constant_normal,
481 mi::Sint32 compute_id)
482 : m_heightfield_tag(heightfield_tag),
483 m_is_normal_recalc(is_normal_recalc),
484 m_is_set_constant_normal(is_set_constant_normal),
485 m_compute_id(compute_id) {}
486
487 // Default constructor
489 : m_heightfield_tag(mi::neuraylib::NULL_TAG),
490 m_is_normal_recalc(true),
491 m_is_set_constant_normal(false),
492 m_compute_id(0) { }
493
494 virtual nv::index::IDistributed_data_locality_query_mode* get_scheduling_mode() const
495 {
496 return new nv::index::Regular_heightfield_locality_query_mode(m_heightfield_tag, mi::math::Bbox<mi::Uint32, 2>(), true);
497 }
498
499 virtual void execute_subset(
500 mi::neuraylib::IDice_transaction* dice_transaction,
501 const nv::index::IData_distribution* data_distribution,
502 nv::index::IData_subset_compute_task_processing* data_subset_processing,
503 mi::Size data_subset_index, // not to confuse with subset data ID
504 mi::Size data_subset_count)
505 {
506 Example_height_fill_task heightfield_operation_task(m_is_normal_recalc, m_is_set_constant_normal, m_compute_id);
507 data_subset_processing->execute_compute_task(&heightfield_operation_task, dice_transaction); // THIS SHALL TRIGGER A INFO LOG THAT WARNS: USE OF USING DEPRECATED HEIGHTFIELD
508
509 mi::base::Handle<nv::index::IRegular_heightfield_data_edit> compute_processing(
510 data_subset_processing->get_interface<nv::index::IRegular_heightfield_data_edit>());
511 if (compute_processing.is_valid_interface())
512 {
513 compute_processing->edit(&heightfield_operation_task, dice_transaction);
514 }
515 }
516
518 mi::neuraylib::ISerializer* serializer,
519 mi::neuraylib::IDice_transaction* dice_transaction,
520 const nv::index::IData_distribution* data_distribution,
521 nv::index::IData_subset_compute_task_processing* data_subset_processing,
522 mi::Size data_subset_index,
523 mi::Size data_subset_count)
524 {
525 Example_height_fill_task heightfield_operation_task(m_is_normal_recalc, m_is_set_constant_normal, m_compute_id);
526 data_subset_processing->execute_compute_task(&heightfield_operation_task, dice_transaction); // THIS SHALL TRIGGER A INFO LOG THAT WARNS: USE OF USING DEPRECATED HEIGHTFIELD
527
528 mi::base::Handle<nv::index::IRegular_heightfield_data_edit> compute_processing(
529 data_subset_processing->get_interface<nv::index::IRegular_heightfield_data_edit>());
530 if (compute_processing.is_valid_interface())
531 {
532 compute_processing->edit(&heightfield_operation_task, dice_transaction);
533 }
534 }
535
537 mi::neuraylib::IDeserializer* deserializer,
538 mi::neuraylib::IDice_transaction* dice_transaction,
539 const nv::index::IData_distribution* data_distribution,
540 mi::Size data_subset_index,
541 mi::Size data_subset_count) {}
542
543 virtual void serialize(mi::neuraylib::ISerializer *serializer) const
544 {
545 serializer->write(&m_heightfield_tag.id, 1);
546 serializer->write(&m_is_normal_recalc, 1);
547 serializer->write(&m_is_set_constant_normal, 1);
548 serializer->write(&m_compute_id, 1);
549 }
550
551 virtual void deserialize(mi::neuraylib::IDeserializer* deserializer)
552 {
553 deserializer->read(&m_heightfield_tag.id, 1);
554 deserializer->read(&m_is_normal_recalc, 1);
555 deserializer->read(&m_is_set_constant_normal, 1);
556 deserializer->read(&m_compute_id, 1);
557 }
558
559private:
560 mi::neuraylib::Tag m_heightfield_tag;
561 bool m_is_normal_recalc;
562 bool m_is_set_constant_normal;
563 mi::Sint32 m_compute_id;
564};
565
566//----------------------------------------------------------------------
567//======================================================================
568//----------------------------------------------------------------------
569void Normal_recalculation::create_scene()
570{
571 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
572 check_success(dice_transaction.is_valid_interface());
573 {
574 m_session_tag = m_index_session->create_session(dice_transaction.get());
575 check_success(m_session_tag.is_valid());
576 mi::base::Handle<const nv::index::ISession> session(
577 dice_transaction->access<nv::index::ISession>(m_session_tag));
578 check_success(session.is_valid_interface());
579
580 // Access (edit mode) the scene instance from the database.
581 mi::base::Handle<nv::index::IScene> scene_edit(
582 dice_transaction->edit<nv::index::IScene>(session->get_scene()));
583 check_success(scene_edit.is_valid_interface());
584
585 nv::index::app::String_dict heightfield_opt;
586 heightfield_opt.insert("args::type", "heightfield");
587 heightfield_opt.insert("args::importer", "nv::index::plugin::legacy_importer.Raw_heightfield_data_importer");
588 heightfield_opt.insert("args::input_file", m_heightfield_infile);
589 heightfield_opt.insert("args::size", nv::index::app::to_string(m_heightfield_size));
590 heightfield_opt.insert("args::range", "0.1 1000");
591 heightfield_opt.insert("args::cache", "false");
592 heightfield_opt.insert("args::serial_access", "false");
593 heightfield_opt.insert("args::stats", "false");
594
595 nv::index::IDistributed_data_import_callback* importer_callback =
596 get_importer_from_application_layer(
597 get_application_layer_interface(),
598 "nv::index::plugin::legacy_importer.Raw_heightfield_data_importer",
599 heightfield_opt);
600
601 const mi::Float32 rotate_k = 0.0f;
602 const mi::math::Vector<mi::Float32, 3> translate(0.0f, 0.0f, 0.0f);
603 const mi::math::Vector<mi::Float32, 3> scale( 1.0f, 1.0f, 1.0f);
604
605 // Create a heightfield scene element via the raw heightfield importer
606 mi::base::Handle<nv::index::IRegular_heightfield> heightfield(
607 scene_edit->create_regular_heightfield(
608 scale, rotate_k, translate,
609 m_heightfield_size,
610 m_heightfield_range,
611 importer_callback,
612 dice_transaction.get()));
613 check_success(heightfield.is_valid_interface());
614
615 // ... and store the heightfield scene element in the distributed database
616 check_success(!m_heightfield_tag.is_valid()); // must not yet created before this initialization.
617 m_heightfield_tag =
618 dice_transaction->store_for_reference_counting(heightfield.get());
619 check_success(m_heightfield_tag.is_valid()); // Now this should exist.
620
621 // Create static group node for heightfield data
622 mi::base::Handle<nv::index::IStatic_scene_group> static_group_node(
623 scene_edit->create_scene_group<nv::index::IStatic_scene_group>());
624 check_success(static_group_node.is_valid_interface());
625
626 // Added a light and a material to the static group node
627 {
628 // Add a light
629 mi::base::Handle<nv::index::IDirectional_headlight> headlight(
630 scene_edit->create_attribute<nv::index::IDirectional_headlight>());
631 check_success(headlight.is_valid_interface());
632 const mi::math::Color_struct color_intensity = { 1.0f, 1.0f, 1.0f, 1.0f, };
633 headlight->set_intensity(color_intensity);
634 headlight->set_direction(mi::math::Vector<mi::Float32, 3>(1.0f, -1.0f, -1.0f));
635 const mi::neuraylib::Tag headlight_tag = dice_transaction->store_for_reference_counting(headlight.get());
636 check_success(headlight_tag.is_valid());
637 static_group_node->append(headlight_tag, dice_transaction.get());
638
639 // Material for the heightfield
640 mi::base::Handle<nv::index::IPhong_gl> phong_1(scene_edit->create_attribute<nv::index::IPhong_gl>());
641 check_success(phong_1.is_valid_interface());
642
643 // Define a more interesting greenish material
644 phong_1->set_ambient(mi::math::Color(0.0f, 0.3f, 0.0f, 0.3f));
645 phong_1->set_diffuse(mi::math::Color(0.0f, 0.8f, 0.2f, 0.3f));
646 phong_1->set_specular(mi::math::Color(0.6f));
647 phong_1->set_shininess(100.0f);
648
649 const mi::neuraylib::Tag phong_1_tag
650 = dice_transaction->store_for_reference_counting(phong_1.get());
651 check_success(phong_1_tag.is_valid());
652 static_group_node->append(phong_1_tag, dice_transaction.get());
653 }
654
655 // Append the heightfield to the scene group
656 static_group_node->append(m_heightfield_tag, dice_transaction.get());
657 mi::neuraylib::Tag static_group_node_tag =
658 dice_transaction->store_for_reference_counting(static_group_node.get());
659 check_success(static_group_node_tag.is_valid());
660
661 // Append the static scene group to the scene.
662 scene_edit->append(static_group_node_tag, dice_transaction.get());
663
664 std::stringstream sstr;
665 sstr << "Created a heightfield: size = "
666 << m_heightfield_size << ", tag = " << m_heightfield_tag.id;
667 INFO_LOG << sstr.str();
668
669 // Define a region of interest
670 scene_edit->set_clipped_bounding_box(m_roi);
671
672 // Optionally adjust the scene's coordinate system
673 mi::math::Matrix<mi::Float32, 4, 4> transform_mat(
674 1.0f, 0.0f, 0.0f, 0.0f,
675 0.0f, 1.0f, 0.0f, 0.0f,
676 0.0f, 0.0f, -1.0f, 0.0f, // adjust for coordinate system
677 0.0f, 0.0f, 0.0f, 1.0f
678 );
679
680 scene_edit->set_transform_matrix(transform_mat);
681
682 // Create a camera and set it to the scene.
683 mi::base::Handle< nv::index::IPerspective_camera > cam(
684 scene_edit->create_camera<nv::index::IPerspective_camera>());
685 check_success(cam.is_valid_interface());
686 setup_camera(cam.get());
687
688 const mi::neuraylib::Tag camera_tag = dice_transaction->store(cam.get());
689 check_success(camera_tag.is_valid());
690
691 scene_edit->set_camera(camera_tag);
692
693 const mi::math::Vector<mi::Uint32, 2> buffer_resolution(512, 512);
694 m_image_file_canvas->set_resolution(buffer_resolution);
695 }
696 dice_transaction->commit();
697}
698
699//----------------------------------------------------------------------
700void Normal_recalculation::setup_camera(
701 nv::index::IPerspective_camera* cam) const
702{
703 check_success(cam != 0);
704
705 // Set the camera parameters to see the whole scene
706 mi::math::Vector<mi::Float32, 3> from(2959.61f, 1993.47f, -1653.08f);
707 mi::math::Vector<mi::Float32, 3> dir (-0.5891f, -0.3783f, 0.7141f);
708 mi::math::Vector<mi::Float32, 3> up (-0.6795f, -0.2464f, -0.6911f);
709 dir.normalize();
710
711 cam->set(from, dir, up);
712 cam->set_aperture(0.033f);
713 cam->set_aspect(1.0f);
714 cam->set_focal(0.03f);
715 cam->set_clip_min(2.0f);
716 cam->set_clip_max(10000.0f);
717}
718
719//----------------------------------------------------------------------
720bool Normal_recalculation::render_frame(const std::string& output_fname,
721 const std::string& verify_fname)
722{
723 bool success = true;
724
725 // Rendering to a file by means of the file canvas
726 m_image_file_canvas->set_rgba_file_name(output_fname.c_str()); // No output if empty string
727
728 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
729 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
730 check_success(dice_transaction.is_valid_interface());
731 {
732 m_index_session->update(m_session_tag, dice_transaction.get());
733 mi::base::Handle<nv::index::IFrame_results> frame_results(
734 m_index_rendering->render(
735 m_session_tag,
736 m_image_file_canvas.get(),
737 dice_transaction.get()));
738 check_success(frame_results.is_valid_interface());
739 }
740 dice_transaction->commit();
741
742 if (!output_fname.empty())
743 {
744 INFO_LOG << "save the rendered image to: " << output_fname;
745 }
746
747 // verify the generated frame
748 if (!verify_fname.empty())
749 {
750 if (!(verify_canvas_result(get_application_layer_interface(),
751 m_image_file_canvas.get(), verify_fname, get_options())))
752 {
753 success = false;
754 }
755 }
756
757 // increment the frame index.
758 ++m_frame_idx;
759
760 return success;
761}
762
763//----------------------------------------------------------------------
764void Normal_recalculation::compute_heightfield(
765 bool is_normal_recalc,
766 bool is_set_constant_normal,
767 mi::Sint32 compute_id)
768{
769 check_success(m_session_tag.is_valid());
770 check_success(m_heightfield_tag.is_valid());
771
772 // DiCE database access
773 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(create_transaction());
774 check_success(dice_transaction.is_valid_interface());
775 {
776 // Choose a distributed computing algorithm for heightfield creation
777 mi::base::Handle<nv::index::IDistributed_data_job> distributed_compute_algorithm;
778 // Edit the heightfield
779 {
780 INFO_LOG << "Normal recalculation: " << (is_normal_recalc ? "on" : "off");
781 if (!is_normal_recalc)
782 {
783 INFO_LOG << "Set constant normal: " << (is_set_constant_normal ? "on" : "off");
784 }
785
786 mi::base::Handle< nv::index::IDistributed_data_job > eh_op(
787 new Example_heightfield_operation(m_heightfield_tag,
788 is_normal_recalc,
789 is_set_constant_normal,
790 compute_id));
791 distributed_compute_algorithm.swap(eh_op);
792 }
793 mi::base::Handle<const nv::index::ISession> session(dice_transaction->access<const nv::index::ISession>(m_session_tag));
794 check_success(session.is_valid_interface());
795
796 const mi::neuraylib::Tag dist_layout_tag = session->get_distribution_layout();
797 mi::base::Handle<const nv::index::IData_distribution> distribution_layout(dice_transaction->access<nv::index::IData_distribution>(dist_layout_tag));
798
799 distribution_layout->create_scheduler()->execute(distributed_compute_algorithm.get(), dice_transaction.get());
800
801 INFO_LOG << "Done heightfield computation.";
802
803 }
804 dice_transaction->commit();
805}
806
807//----------------------------------------------------------------------
808// The API example illustrates the use of the normal recalculation of
809// normal of a hightfield.
810int main(int argc, const char* argv[])
811{
812 nv::index::app::String_dict sdict;
813 // DiCE options
814 sdict.insert("dice::verbose", "3");
815 sdict.insert("dice::network::mode", "OFF");
816 sdict.insert("dice::network::multicast_address", "224.1.3.2");
817
818 // Test specific options
819 sdict.insert("heightfield_name", "heightfield_1");
820 sdict.insert("heightfield_infile", "");
821 sdict.insert("heightfield_size", "0 0");
822 sdict.insert("heightfield_range", "0 0");
823 sdict.insert("roi", "0 0 -1024 2040 2040 1024");
824 sdict.insert("use_normal_recalc", "0 1");
825 sdict.insert("set_normal_const", "1 0");
826 sdict.insert("outfbase", "frame_normal_recalculation"); // output file base name
827
828 // Unit test specific options
829 sdict.insert("unittest", "0"); // unit test mode
830 sdict.insert("verify_image_path_base", ""); // reference image file base name
831 sdict.insert("is_dump_comparison_image_when_failed", "1"); // default: dump images when failed.
832 sdict.insert("is_call_from_test", "0"); // default: not call from make check.
833
834 // IndeX settings
835 sdict.insert("index::config::set_monitor_performance_values", "true");
836 sdict.insert("index::service", "rendering_and_compositing");
837 sdict.insert("index::cuda_debug_checks", "false");
838
839 // Application_layer settings
840 sdict.insert("index::app::components::application_layer::component_name_list",
841 "canvas_infrastructure image io");
842 // plugin: legacy_importer
843 sdict.insert("index::app::plugins::legacy_importer::enabled", "true");
844
845 // Initialize application
846 Normal_recalculation normal_recalculation;
847 normal_recalculation.initialize(argc, argv, sdict);
848 check_success(normal_recalculation.is_initialized());
849
850 // launch the application. creating the scene and rendering.
851 const mi::Sint32 exit_code = normal_recalculation.launch();
852 INFO_LOG << "Shutting down ...";
853
854 return exit_code;
855}
Example_height_fill_task(bool is_normal_recalc, bool is_set_constant_normal, mi::Sint32 compute_id)
virtual void get_region_of_interest_for_compute(mi::math::Bbox_struct< mi::Sint32, 2 > &roi) const
virtual bool compute(const mi::math::Bbox_struct< mi::Sint32, 2 > &ij_patch_bbox, mi::Float32 *elevation_values, mi::neuraylib::IDice_transaction *dice_transaction) const
virtual bool user_defined_normal_computation() const
virtual bool compute(const mi::math::Bbox_struct< mi::Sint32, 2 > &ij_patch_bbox, mi::Float32 *elevation_values, mi::math::Vector_struct< mi::Float32, 3 > *normal_values, mi::neuraylib::IDice_transaction *dice_transaction) const
virtual nv::index::IDistributed_data_locality_query_mode * get_scheduling_mode() const
virtual void serialize(mi::neuraylib::ISerializer *serializer) const
virtual void execute_subset_remote(mi::neuraylib::ISerializer *serializer, mi::neuraylib::IDice_transaction *dice_transaction, const nv::index::IData_distribution *data_distribution, nv::index::IData_subset_compute_task_processing *data_subset_processing, mi::Size data_subset_index, mi::Size data_subset_count)
virtual void deserialize(mi::neuraylib::IDeserializer *deserializer)
virtual void execute_subset(mi::neuraylib::IDice_transaction *dice_transaction, const nv::index::IData_distribution *data_distribution, nv::index::IData_subset_compute_task_processing *data_subset_processing, mi::Size data_subset_index, mi::Size data_subset_count)
Example_heightfield_operation(const mi::neuraylib::Tag &heightfield_tag, bool is_normal_recalc, bool is_set_constant_normal, mi::Sint32 compute_id)
virtual void receive_subset_result(mi::neuraylib::IDeserializer *deserializer, mi::neuraylib::IDice_transaction *dice_transaction, const nv::index::IData_distribution *data_distribution, mi::Size data_subset_index, mi::Size data_subset_count)
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)