Iray SDK API nvidia_logo_transpbg.gif Up
Example for Subdivision 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 a subdivision surface and three instances of it with different approximation levels.

New Topics

  • Creation of subdivision surfaces
  • Instancing of objects

Detailed Description

Creation of subdivision surfaces


The control mesh of the subdivision surface is exposed as a polygon mesh with the limitation that only triangles and quads are supported (see the previous example for polygon meshes). In this example we create a simple cube. In addition the crease values of the edges of two opposing faces are set to 1.0. This will result in sharp edges in the limit surface which is a cylinder (without the crease values the limit surface would be a sphere).

Instancing of objects


The subdivision is included in the scene similar as the tetrahedron and the cylinder in the previous examples for triangle and polygon meshes. But in contrast, not only a single instance, but three instances are used in this example.

Instances allow to share the geometry of multiple identical objects. Each instance has its own transformation matrix. Furthermore, each instance can have its own attributes. In our example, we use different approximation levels for each instance to show the subdivision process.

Example Source

Source Code Location: examples/example_subdivision_surface.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_subdivision_surface.cpp
//
// Creates three instances of a subdivision surface with different approximation levels.
//
// The example expects the following command line arguments:
//
// example_subdivision_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_subdivision_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 subdivision surface with a cube as control mesh.
{
const mi::Size n_points = 8;
const mi::Size n_quads = 6;
mi::Float32_3 cube_points[n_points] = {
mi::Float32_3( -0.5, -0.5, -0.5),
mi::Float32_3( 0.5, -0.5, -0.5),
mi::Float32_3( 0.5, 0.5, -0.5),
mi::Float32_3( -0.5, 0.5, -0.5),
mi::Float32_3( -0.5, -0.5, 0.5),
mi::Float32_3( 0.5, -0.5, 0.5),
mi::Float32_3( 0.5, 0.5, 0.5),
mi::Float32_3( -0.5, 0.5, 0.5) };
mi::Uint32 cube_quads[n_quads][4] = {
{ 0, 1, 5, 4 },
{ 4, 5, 6, 7 },
{ 7, 6, 2, 3 },
{ 3, 2, 1, 0 },
{ 1, 2, 6, 5 },
{ 3, 0, 4, 7 } };
// Create an empty subdivision surface
= transaction->create<mi::neuraylib::ISubdivision_surface>( "Subdivision_surface");
// Create a cube (points and polygons)
mesh->reserve_points( n_points);
for( mi::Uint32 i = 0; i < n_points; ++i)
mesh->append_point( cube_points[i]);
for( mi::Uint32 i = 0; i < n_quads; ++i)
mesh->add_polygon( 4);
// Map vertices of the polygons to points
for( mi::Uint32 i = 0; i < n_quads; ++i)
mesh_connectivity->set_polygon_indices( mi::neuraylib::Polygon_handle( i), cube_quads[i]);
check_success( mesh->attach_mesh_connectivity( mesh_connectivity.get()) == 0);
// Set crease values to 1.0f on two opposing faces to end up with a cylinder
mi::Float32 crease_values[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
return mesh;
}
// Add three instances of a subdivision surface with different approximation levels
void setup_scene( mi::neuraylib::ITransaction* transaction, const char* rootgroup)
{
// Remove the existing cube from the scene. The unrefined control mesh (in red) will take its
// place.
transaction->edit<mi::neuraylib::IGroup>( rootgroup));
group->detach( "cube_instance");
group = 0;
// Create the subdivision surface
transaction->store( mesh.get(), "mesh");
// Create three instances of the subdivision surface with different materials, approximation
// levels and world-to-object transformation matrices.
const char* names[3] = { "instance0", "instance1", "instance2" };
const char* materials[3] = { "red_material", "green_material", "blue_material" };
mi::Float32 approximation_level[3] = { 0.0f, 1.0f, 2.0f };
const mi::Float32_3 translation[3] = {
mi::Float32_3( 1.1f, -0.5f, 0.9f),
mi::Float32_3( -0.9f, -0.5f, 0.9f),
mi::Float32_3( -0.9f, -0.5f, -1.1f)
};
for( mi::Size i = 0; i < 3; ++i) {
transaction->create<mi::neuraylib::IInstance>( "Instance"));
instance->attach( "mesh");
mi::Float64_4_4 matrix( 1.0);
matrix.translate( translation[i]);
matrix.rotate( 0.0, 0.25 * MI_PI_2, 0.0);
instance->set_matrix( matrix);
instance->create_attribute<mi::IBoolean>( "visible", "Boolean"));
visible->set_value( true);
instance->create_attribute<mi::IRef>( "material", "Ref"));
material->set_reference( materials[i]);
instance->create_attribute<mi::IStructure>( "approx", "Approx"));
mi::base::Handle<mi::ISint8> method( approx->get_value<mi::ISint8>( "method"));
method->set_value( 0);
mi::base::Handle<mi::IFloat32> const_u( approx->get_value<mi::IFloat32>( "const_u"));
const_u->set_value( approximation_level[i]);
transaction->store( instance.get(), names[i]);
transaction->edit<mi::neuraylib::IGroup>( rootgroup));
group->attach( names[i]);
}
}
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 three instances of a subdivision surface with different approximation levels
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_subdivision_surface.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_subdivision_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
A reference is an object that acts as a pointer to other database elements.
Definition: iref.h:25
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
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
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
virtual Uint32 append_point(const Float32_3_struct &p)=0
Adds a point p to the end of all points and returns the index of the new point.
virtual Polygon_handle_struct add_polygon(Uint32 num_vertices, bool hole=false)=0
Adds a polygon to the mesh.
virtual Sint32 attach_mesh_connectivity(IPolygon_connectivity *connectivity)=0
Attaches the mesh connectivity to the mesh.
virtual IPolygon_connectivity * edit_mesh_connectivity()=0
Detaches and returns the mesh connectivity.
virtual void reserve_points(Uint32 n)=0
Reserves space for at least n points.
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
Interface representing a subdivision surface.
Definition: isubdivision_surface.h:58
virtual Sint32 set_crease_values(Polygon_handle_struct p, const Float32 *values)=0
Sets crease values for all edges of a polygon.
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
#define MI_PI_2
Value of Pi / 2.
Definition: types.h:194
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
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
Iray SDK API.
[Previous] [Next] [Up]