Iray SDK API nvidia_logo_transpbg.gif Up
Example for Fibers
[Previous] [Next] [Up]

This example imports a partial scene containing definitions for the camera, a light, and some geometry (a ground plane and a yellow cube). It then creates a fibers object using the API that is shaded with a multicolor hair material.

New Topics

  • Creation of fibers

Detailed Description

Creation of fibers


To create a fibers object you need to add each fiber one after another, specifying for each one how many control points that fiber will contain and then adding the control points to it. In create_fibers_ball() we create a fibers object that is shaped as a ball in which all its fibers start from a single point and go outwards. In this example, the type of curves used for the fibers is B-spline but you can also choose Catmull-Rom splines or linear curves. Here we use the same number of control points for all the fibers but this is not mandatory; you can choose to have a varying number of control points for each fiber.

Notice also that we are adding a so-called phantom (or ghost) point at the beginning of each fiber, in order for the B-spline curves to actually start at the center of the sphere. The radii are set per-control point. In this example the positions and radii of the control points are set all at once for each fiber (except for the phantom point, whose position and radius is set for each fiber as the first point). Control points can also be set incrementally for each fiber or all at once for the whole fibers object.

Example Source

Source Code Location: examples/example_fibers.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_fibers.cpp
//
// Creates and manipulates fiber objects.
//
// The example expects the following command line arguments:
//
// example_fibers <mdl_path>
//
// mdl_path path to the MDL modules, e.g., iray-<version>/mdl
//
// The rendered image is written to a file named "example_fibers.png".
#include <mi/neuraylib.h>
// Include code shared by all examples.
#include "example_shared.h"
// Include an implementation of IRender_target.
#include "example_render_target_simple.h"
#include <iostream>
#include <map>
#include <vector>
// Linear congruential generator for pseudo-random numbers, see
// https://en.wikipedia.org/wiki/Linear_congruential_generator
unsigned int lcg_a = 134775815;
unsigned int lcg_c = 123456;
unsigned int lcg_m = 1 << 31;
unsigned int lcg_prev = 33478921;
// Return a random number in the range [ 0 ... lcg_m )
unsigned int get_random_uint()
{
mi::Uint64 val = (lcg_a * lcg_prev + lcg_c) % lcg_m;
lcg_prev = static_cast<unsigned int>(val);
return lcg_prev;
}
// Return a random number in the range [min..max]
float get_random_float(const float& min, const float& max)
{
return ((float(get_random_uint()) * (max - min)) / float(lcg_m)) + min;
}
// Create a fibers ball around a unit sphere.
mi::neuraylib::IFibers* create_fibers_ball( mi::neuraylib::ITransaction* transaction)
{
// Some constants to define the fibers ball
const mi::Float32_3 sphere_center(0.f, 0.f, 0.f);
const mi::Float32 sphere_radius = 0.2f;
const mi::Float32 min_length = 0.8f;
const mi::Float32 max_length = 1.0f;
const mi::Float32 base_radius = 0.01f;
const mi::Float32 tip_radius = 0.002f;
const mi::Float32 randomness = 0.2f;
const unsigned int num_fibers = 1000;
const unsigned int num_vertices_per_fiber = 9; // must be at least 4
mi::neuraylib::IFibers *fibers = transaction->create<mi::neuraylib::IFibers>("Fibers");
// the fibers will have an implicit U mapping from 0.0 to 1.0 along them from base to tip
std::vector<mi::Float32_4> control_points;
control_points.reserve(num_vertices_per_fiber);
for (unsigned int n=0; n<num_fibers; ++n) {
// draw a random position on a sphere of radius 'sphere_radius' and center 'sphere_center'
// generating random direction vectors
const float rx = get_random_float(-1.0f, 1.0f);
const float ry = get_random_float(-1.0f, 1.0f);
const float rz = get_random_float(-1.0f, 1.0f);
mi::Float32_3 dir(rx, ry, rz);
dir.normalize();
// first vertex of the fiber
const mi::Float32_3 first_pos = sphere_center + sphere_radius * dir;
// compute tangent space around the direction
mi::Float32_3 tu = (dir.y * dir.y > dir.x * dir.x) ? mi::Float32_3(0.0f, dir.z, -dir.y) : mi::Float32_3(-dir.z, 0.0f, dir.x);
mi::Float32_3 tv = cross(tu, dir);
tv.normalize();
tu = cross(tv, dir);
tu.normalize();
// compute a random (approximate) length of the fiber, between 'min_length' and 'max_length'
const mi::Float32 fiber_length = get_random_float(min_length, max_length);
// (approximate) length of a segment of the fiber
const mi::Float32 segment_step = fiber_length / float(num_vertices_per_fiber - 1);
// step for the radius
const mi::Float32 radius_step = (tip_radius - base_radius) /
float(num_vertices_per_fiber - 1);
control_points.clear();
// first compute all the normal B-spline control points along with their radii
// and save them in 'control_points' and 'radii'
for (unsigned int k = 0; k < num_vertices_per_fiber; ++k) {
mi::Float32_3 v = first_pos + float(k) * segment_step * dir;
if (k > 0) {
// all vertices get randomly moved in the tangent space of the direction
// except the first one, which is the base vertex of the fiber
const float du = get_random_float(-randomness*0.5f, randomness*0.5f);
const float dv = get_random_float(-randomness*0.5f, randomness*0.5f);
v += (du * tu + dv * tv);
}
const mi::Float32 radius = base_radius + float(k) * radius_step;
control_points.push_back(mi::Float32_4(v.x, v.y, v.z, radius));
}
// compute an extra point to be put at the very beginning of the B-spline,
// this is a ghost point (or phantom point) that has the effect of making
// the curve effectively start at 'control_points[0]'
mi::Float32_4 ghost_point = (2.0 * control_points[0]) - control_points[1];
mi::Float32 ghost_radius = control_points[0].w;
// add a fiber that has the ghost point at the beginning and all the computed control points
const mi::neuraylib::Fiber_handle_struct fh = fibers->add_fiber(num_vertices_per_fiber + 1);
fibers->set_control_point(fh, 0, mi::Float32_3(ghost_point.x, ghost_point.y, ghost_point.z));
fibers->set_radius(fh, 0, ghost_radius);
// add control points/radii
fibers->set_fiber_data(fh, 1, control_points.data(), control_points.size());
}
return fibers;
}
// Add a fibers object that has the 'unicorn_hair' material attached.
void setup_scene( mi::neuraylib::ITransaction* transaction, const char* rootgroup)
{
// Create the fibers object
mi::base::Handle<mi::neuraylib::IFibers> fibers_object(create_fibers_ball( transaction));
transaction->store( fibers_object.get(), "fibers_obj");
// Create the instance for the fibers object
transaction->create<mi::neuraylib::IInstance>( "Instance"));
instance->attach( "fibers_obj");
// Set the transformation matrix, the visible attribute, and the material
mi::Float64_4_4 matrix( 1.0 );
matrix.translate( 0.0, -0.4, 0.0);
instance->set_matrix( matrix );
instance->create_attribute<mi::IBoolean>( "visible", "Boolean"));
visible->set_value( true);
mi::base::Handle<mi::IRef> material( instance->create_attribute<mi::IRef>( "material", "Ref"));
material->set_reference( "unicorn_hair");
transaction->store( instance.get(), "instance_fibers");
// Attach the instance to the root group
transaction->edit<mi::neuraylib::IGroup>( rootgroup));
group->attach( "instance_fibers");
}
void configuration( mi::neuraylib::INeuray* neuray, const char* mdl_path)
{
// Configure the neuray library. Here we set the search path for .mdl files.
check_success( rc->add_mdl_path( mdl_path) == 0);
check_success( rc->add_mdl_path( ".") == 0);
// Load the OpenImageIO, Iray Photoreal, and .mi importer plugins.
check_success( pc->load_plugin_library( "nv_openimageio" MI_BASE_DLL_FILE_EXT) == 0);
check_success( pc->load_plugin_library( "libiray" MI_BASE_DLL_FILE_EXT) == 0);
check_success( pc->load_plugin_library( "mi_importer" MI_BASE_DLL_FILE_EXT) == 0);
}
void rendering( mi::neuraylib::INeuray* neuray)
{
// Get the database, the global scope of the database, and create a transaction in the global
// scope for importing the scene file and storing the scene.
check_success( database.is_valid_interface());
database->get_global_scope());
scope->create_transaction());
check_success( transaction.is_valid_interface());
// Import the scene file
check_success( import_api.is_valid_interface());
import_api->import_elements( transaction.get(), "file:main.mi"));
check_success( import_result->get_error_number() == 0);
// Add two triangle meshes to the scene
setup_scene( transaction.get(), import_result->get_rootgroup());
// Create the scene object
transaction->create<mi::neuraylib::IScene>( "Scene"));
scene->set_rootgroup( import_result->get_rootgroup());
scene->set_options( import_result->get_options());
scene->set_camera_instance( import_result->get_camera_inst());
transaction->store( scene.get(), "the_scene");
// Create the render context using the Iray Photoreal render mode
scene = transaction->edit<mi::neuraylib::IScene>( "the_scene");
scene->create_render_context( transaction.get(), "iray"));
check_success( render_context.is_valid_interface());
mi::base::Handle<mi::IString> scheduler_mode( transaction->create<mi::IString>());
scheduler_mode->set_c_str( "batch");
render_context->set_option( "scheduler_mode", scheduler_mode.get());
scene = 0;
// Create the render target and render the scene
new Render_target( image_api.get(), "Color", 512, 384));
check_success( render_context->render( transaction.get(), render_target.get(), 0) >= 0);
// Write the image to disk
check_success( export_api.is_valid_interface());
mi::base::Handle<mi::neuraylib::ICanvas> canvas( render_target->get_canvas( 0));
export_api->export_canvas( "file:example_fibers.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_fibers <mdl_path>" << std::endl;
keep_console_open();
return EXIT_FAILURE;
}
const char* mdl_path = argv[1];
// Access the neuray library
mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
check_success( neuray.is_valid_interface());
// Configure the neuray library
configuration( neuray.get(), mdl_path);
// Start the neuray library
mi::Sint32 result = neuray->start();
check_start_success( result);
// Do the actual rendering
rendering( neuray.get());
// Shut down the neuray library
check_success( neuray->shutdown() == 0);
neuray = 0;
// Unload the neuray library
check_success( unload());
keep_console_open();
return EXIT_SUCCESS;
}
This interface represents bool.
Definition: inumber.h:122
A reference is an object that acts as a pointer to other database elements.
Definition: iref.h:25
A simple string class.
Definition: istring.h:22
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
NxM-dimensional matrix class template of fixed dimensions.
Definition: matrix.h:367
Fixed-size math vector class template with generic operations.
Definition: vector.h:286
This interface is used to interact with the distributed database.
Definition: idatabase.h:293
This interface is used to export files.
Definition: iexport_api.h:38
Interface representing a collection of fibers.
Definition: ifibers.h:80
virtual Fiber_handle_struct add_fiber(Size vertices)=0
Adds a fiber with the given number of vertices.
virtual Sint32 set_type(Fiber_type fiber_type)=0
Sets the fiber type.
virtual Sint32 set_radius(Fiber_handle_struct s, Float32 radius)=0
Sets the radius of all vertices of a fiber.
virtual Sint32 set_fiber_data(Fiber_handle_struct s, Size index, const Float32_4_struct *data, Size n)=0
Sets an array of control points and radii per fiber.
virtual Sint32 set_control_point(Fiber_handle_struct s, Size index, Float32_3_struct p)=0
Sets a control point.
A group is a container for other scene elements.
Definition: igroup.h:39
This interface provides various utilities related to canvases and buffers.
Definition: iimage_api.h:49
This interface is used to import files.
Definition: iimport_api.h:100
An instance is a scene element that adds a transformation and attributes to another scene element.
Definition: iinstance.h:117
This is an object representing the Iray library.
Definition: ineuray.h:44
virtual Sint32 shutdown(bool blocking=true)=0
Shuts down the library.
virtual base::IInterface * get_api_component(const base::Uuid &uuid) const =0
Returns an API component from the Iray SDK API.
virtual Sint32 start(bool blocking=true)=0
Starts the operation of the Iray library.
This interface is used to load plugins and to query information about loaded plugins.
Definition: iplugin_configuration.h:24
This interface is used to query and change the rendering configuration.
Definition: irendering_configuration.h:109
The scene is the top-level element describing a subset of DB elements to be rendered.
Definition: iscene.h:44
A transaction provides a consistent view on the database.
Definition: itransaction.h:81
virtual base::IInterface * create(const char *type_name, Uint32 argc=0, const base::IInterface *argv[]=0)=0
Creates an object of the type type_name.
virtual base::IInterface * edit(const char *name)=0
Retrieves an element from the database and returns it ready for editing.
virtual Sint32 commit()=0
Commits the transaction.
virtual Sint32 store(base::IInterface *db_element, const char *name, Uint8 privacy=LOCAL_SCOPE)=0
Stores the element db_element in the database under the name name and with the privacy level privacy.
#define MI_BASE_DLL_FILE_EXT
The operating system specific default filename extension for shared libraries (DLLs)
Definition: config.h:340
unsigned long long Uint64
64-bit unsigned integer.
Definition: types.h:62
float Float32
32-bit float.
Definition: types.h:51
signed int Sint32
32-bit signed integer.
Definition: types.h:46
T cross(const Vector_struct<T, 2> &lhs, const Vector_struct<T, 2> &rhs)
Returns the two-times-two determinant result for the two vectors lhs and rhs.
Definition: vector.h:1705
bool normalize()
Normalizes this vector to unit length.
Definition: vector.h:646
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
@ FIBER_TYPE_BSPLINE
Uses cubic uniform B-Splines.
Definition: ifibers.h:27
Iray SDK API.
Handle class for type-safety.
Definition: identifier.h:56
[Previous] [Next] [Up]