Iray SDK API nvidia_logo_transpbg.gif Up
Example for Freeform surfaces
[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 via the API two freeform surfaces and adds them to the scene.

New Topics

  • Creation of freeform surfaces

Detailed Description

Creation of freeform surfaces


The function create_sphere() creates a freeform surface that represents a sphere. Here we use a representation as Bezier surface of degree 2 in both directions. The sphere is centered at the origin and has radius 1.0.

Two freeform objects are added to the scene: a red sphere, and a blue partial ellipsoid. Note that the freeform surface of the blue ellipsoid actually represents a sphere, the ellipsoidal shape is created via its transformation matrix. The parameter range in U-direction has been restricted to [0.0, 0.5] to cut away the part of the ellipsoid that lies below the ground plane.

Example Source

Source Code Location: examples/example_freeform_surface.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_freeform_surface.cpp
//
// Creates a three instances of a freeform surface with different approximation levels.
//
// The example expects the following command line arguments:
//
// example_freeform_surface <mdl_path>
//
// mdl_path path to the MDL modules, e.g., iray-<version>/mdl
//
// The rendered image is written to a file named "example_freeform_surface.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>
// Create a sphere as a freeform surface.
{
const mi::Size n_points_u = 9;
const mi::Size n_points_v = 5;
// The control points
mi::Float32_3 control_points[n_points_u * n_points_v] = {
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 0.0f, 0.0f, -1.0f),
mi::Float32_3( 1.0f, 0.0f, -1.0f),
mi::Float32_3( 1.0f, 1.0f, -1.0f),
mi::Float32_3( 0.0f, 1.0f, -1.0f),
mi::Float32_3( -1.0f, 1.0f, -1.0f),
mi::Float32_3( -1.0f, 0.0f, -1.0f),
mi::Float32_3( -1.0f, -1.0f, -1.0f),
mi::Float32_3( 0.0f, -1.0f, -1.0f),
mi::Float32_3( 1.0f, -1.0f, -1.0f),
mi::Float32_3( 1.0f, 0.0f, -1.0f),
mi::Float32_3( 1.0f, 0.0f, 0.0f),
mi::Float32_3( 1.0f, 1.0f, 0.0f),
mi::Float32_3( 0.0f, 1.0f, 0.0f),
mi::Float32_3( -1.0f, 1.0f, 0.0f),
mi::Float32_3( -1.0f, 0.0f, 0.0f),
mi::Float32_3( -1.0f, -1.0f, 0.0f),
mi::Float32_3( 0.0f, -1.0f, 0.0f),
mi::Float32_3( 1.0f, -1.0f, 0.0f),
mi::Float32_3( 1.0f, 0.0f, 0.0f),
mi::Float32_3( 1.0f, 0.0f, 1.0f),
mi::Float32_3( 1.0f, 1.0f, 1.0f),
mi::Float32_3( 0.0f, 1.0f, 1.0f),
mi::Float32_3( -1.0f, 1.0f, 1.0f),
mi::Float32_3( -1.0f, 0.0f, 1.0f),
mi::Float32_3( -1.0f, -1.0f, 1.0f),
mi::Float32_3( 0.0f, -1.0f, 1.0f),
mi::Float32_3( 1.0f, -1.0f, 1.0f),
mi::Float32_3( 1.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f),
mi::Float32_3( 0.0f, 0.0f, 1.0f)
};
// Create an empty freeform surface with one surface
= transaction->create<mi::neuraylib::IFreeform_surface>( "Freeform_surface");
// There are two choices for the basis used to parameterize the freeform surface: bezier and
// b-spline. The other data depends on that choice, except for the control points which are
// identical (for this specific case).
// Set up the basis type, degrees, and number of patches
surface->set_basis_type( mi::neuraylib::BASIS_BEZIER);
surface->set_degree( mi::neuraylib::DIMENSION_U, 2);
surface->set_degree( mi::neuraylib::DIMENSION_V, 2);
surface->set_patches_size( mi::neuraylib::DIMENSION_U, 4);
surface->set_patches_size( mi::neuraylib::DIMENSION_V, 2);
// Set up the parameter vectors
surface->set_parameter( mi::neuraylib::DIMENSION_U, 0, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 1, 0.25f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 2, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 3, 0.75f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 4, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 0, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 1, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 2, 1.0f);
// The weights
mi::Float32 weights[n_points_u * n_points_v] = {
1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f,
1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f,
2.0f, 2.0f, 4.0f, 2.0f, 2.0f, 2.0f, 4.0f, 2.0f, 2.0f,
1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f,
1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f
};
// Set up the control points and weights
for( mi::Uint32 i = 0; i < n_points_u; ++i)
for( mi::Uint32 j = 0; j < n_points_v; ++j) {
surface->set_control_point( i, j, control_points[j * n_points_u + i]);
surface->set_weight( i, j, weights[j * n_points_u + i]);
}
} else {
// Set up the basis type, degrees, and number of patches
surface->set_basis_type( mi::neuraylib::BASIS_BSPLINE);
surface->set_degree( mi::neuraylib::DIMENSION_U, 2);
surface->set_degree( mi::neuraylib::DIMENSION_V, 2);
surface->set_patches_size( mi::neuraylib::DIMENSION_U, 7);
surface->set_patches_size( mi::neuraylib::DIMENSION_V, 3);
// Set up the parameter vectors
surface->set_parameter( mi::neuraylib::DIMENSION_U, 0, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 1, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 2, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 3, 0.25f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 4, 0.25f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 5, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 6, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 7, 0.75f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 8, 0.75f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 9, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 10, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_U, 11, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 0, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 1, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 2, 0.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 3, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 4, 0.5f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 5, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 6, 1.0f);
surface->set_parameter( mi::neuraylib::DIMENSION_V, 7, 1.0f);
// The weights
mi::Float32 w = 0.5f * std::sqrt( 2.0f);
mi::Float32 weights[n_points_u * n_points_v] = {
1.0f, w, 1.0f, w, 1.0f, w, 1.0f, w, 1.0f,
w, 0.5f, w, 0.5f, w, 0.5f, w, 0.5f, w,
1.0f, w, 1.0f, w, 1.0f, w, 1.0f, w, 1.0f,
w, 0.5f, w, 0.5f, w, 0.5f, w, 0.5f, w,
1.0f, w, 1.0f, w, 1.0f, w, 1.0f, w, 1.0f
};
// Set up the control points and weights
for( mi::Uint32 i = 0; i < n_points_u; ++i)
for( mi::Uint32 j = 0; j < n_points_v; ++j) {
surface->set_control_point( i, j, control_points[j * n_points_u + i]);
surface->set_weight( i, j, weights[j * n_points_u + i]);
}
}
surface = 0;
// Set up the approximation granularity
sphere->create_attribute<mi::IStructure>( "approx", "Approx"));
mi::base::Handle<mi::ISint8> method( approx->get_value<mi::ISint8>( "method"));
method->set_value( 0);
method = 0;
mi::base::Handle<mi::IFloat32> const_u( approx->get_value<mi::IFloat32>( "const_u"));
const_u->set_value( 12.0f);
const_u = 0;
mi::base::Handle<mi::IFloat32> const_v( approx->get_value<mi::IFloat32>( "const_v"));
const_v->set_value( 12.0f);
const_v = 0;
approx = 0;
return sphere;
}
// Add an instance of a red sphere and an instance of a blue half-sphere.
void setup_scene( mi::neuraylib::ITransaction* transaction, const char* rootgroup)
{
// Create the red sphere
create_sphere( transaction, mi::neuraylib::BASIS_BEZIER));
transaction->store( mesh.get(), "mesh_red");
// Create the instance for the red sphere
transaction->create<mi::neuraylib::IInstance>( "Instance"));
instance->attach( "mesh_red");
// Set the transformation matrix, the visible attribute, and the material
mi::Float64_4_4 matrix( 1.0);
matrix.translate( -0.6, -0.5, 0.7);
mi::Float64_4_4 matrix_scale( 2.0, 0, 0, 0, 0, 2.0, 0, 0, 0, 0, 2.0, 0, 0, 0, 0, 1.0);
matrix *= matrix_scale;
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( "red_material");
transaction->store( instance.get(), "instance_red");
// And attach the instance to the root group
transaction->edit<mi::neuraylib::IGroup>( rootgroup));
group->attach( "instance_red");
group = 0;
// Create the blue sphere
mesh = create_sphere( transaction, mi::neuraylib::BASIS_BSPLINE);
// Trim the sphere to the part above the ground plane
mesh->edit_surface( mi::neuraylib::Surface_handle( 0)));
surface->set_range( mi::neuraylib::DIMENSION_U, 0.0f, 0.5f);
surface = 0;
transaction->store( mesh.get(), "mesh_blue");
// Create the instance for the blue sphere
instance = transaction->create<mi::neuraylib::IInstance>( "Instance");
instance->attach( "mesh_blue");
// Set the transformation matrix, the visible attribute, and the material
matrix = mi::Float64_4_4( 1.0);
matrix.translate( -0.6, 0.0, -1.1);
matrix_scale = mi::Float64_4_4( 2.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 2.0, 0, 0, 0, 0, 1.0);
matrix *= matrix_scale;
instance->set_matrix( matrix);
visible = instance->create_attribute<mi::IBoolean>( "visible", "Boolean");
visible->set_value( true);
material = instance->create_attribute<mi::IRef>( "material", "Ref");
material->set_reference( "blue_material");
transaction->store( instance.get(), "instance_blue");
// And attach the instance to the root group
group = transaction->edit<mi::neuraylib::IGroup>( rootgroup);
group->attach( "instance_blue");
}
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 instances of freeform surfaces
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");
scene = 0;
// 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_freeform_surface.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_freeform_surface <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
This interface represents mi::Float32.
Definition: inumber.h:221
virtual void set_value(bool val)=0
Sets the value of the object via a parameter of type bool.
A reference is an object that acts as a pointer to other database elements.
Definition: iref.h:25
virtual Sint32 set_reference(const base::IInterface *db_element)=0
Sets the reference to db_element.
This interface represents mi::Sint8.
Definition: inumber.h:177
A simple string class.
Definition: istring.h:22
This interface represents structures, i.e., a key-value based data structure.
Definition: istructure.h:44
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
virtual IData * create_attribute(const char *name, const char *type)=0
Creates a new attribute name of the type type.
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 freeform surface.
Definition: ifreeform_surface.h:99
virtual ISurface * add_surface()=0
Adds and returns a new surface.
A group is a container for other scene elements.
Definition: igroup.h:39
virtual Sint32 attach(const char *scene_element)=0
Attaches a scene element to the group.
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
virtual Sint32 attach(const char *scene_element)=0
Attaches a scene element to the instance.
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.
Handle class for type-safety.
Definition: identifier.h:66
#define MI_BASE_DLL_FILE_EXT
The operating system specific default filename extension for shared libraries (DLLs)
Definition: config.h:340
unsigned int Uint32
32-bit unsigned integer.
Definition: types.h:49
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112
float Float32
32-bit float.
Definition: types.h:51
signed int Sint32
32-bit signed integer.
Definition: types.h:46
Color sqrt(const Color &c)
Returns the square root of each element of c.
Definition: color.h:807
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
math::Matrix<Float64, 4, 4> Float64_4_4
4 x 4 matrix of Float64.
Definition: matrix_typedefs.h:330
Basis_type
Different basis types that are supported by freeform surfaces.
Definition: ifreeform_surface.h:30
@ BASIS_BEZIER
Represents a Bezier basis.
Definition: ifreeform_surface.h:32
@ BASIS_BSPLINE
Represents a B-spline basis.
Definition: ifreeform_surface.h:35
@ DIMENSION_V
Represents the V-dimension of the parameter space.
Definition: ifreeform_surface.h:50
@ DIMENSION_U
Represents the U-dimension of the parameter space.
Definition: ifreeform_surface.h:47
Iray SDK API.
[Previous] [Next] [Up]