Iray SDK API nvidia_logo_transpbg.gif Up
Example for Polygon meshes
[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 red cylinder as a polygon mesh and tessellates a copy of it.

New Topics

  • Creation of polygon meshes
  • Using the tessellator

Detailed Description

Creation of polygon meshes


To create a polygon mesh you need to at least specify the points (the position of the vertices) of the polygon mesh and the polygons (as point indices). In create_tetrahedron() we create a cylinder with a regular N-gon as base. The actual data (point coordinates, normal directions, etc). is not hardcoded, but computed by a helper class Cylinder based on few input parameters (radius, height, parameter n of the N-gon).

In contrast to the previous example, vertex normals are not specified per point, but per vertex (to get a sharp edge for the top and base face). Hence, we cannot use the mesh connectivity, but have to use a custom connectivity. The vertices are mapped to entries in the attribute vector as follows: All vertices of the top face are mapped to the same normal, same for the vertices of the base face. Each two vertices on the edge between two adjacent side faces share one normal.

The cylinder is included in the scene similar as the tetrahedron in the previous example.

Using the tessellator


The tessellator is a functor which tessellates a polygon mesh and returns the tessellated mesh as a triangle mesh. In this example, the red cylinder is tessellated and the result is added to the scene (with a blue material). Currently, the tessellator does not support any options to control its behavior.

Example Source

Source Code Location: examples/example_polygon_mesh.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_polygon_mesh.cpp
//
// Creates and tessellates a polygon mesh.
//
// The example expects the following command line arguments:
//
// example_polygon_mesh <mdl_path>
//
// mdl_path path to the MDL modules, e.g., iray-<version>/mdl
//
// The rendered image is written to a file named "example_polygon_mesh.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>
// Helper class that represents a cylinder as a polygon mesh with a regular N-gon as base
class Cylinder
{
public:
Cylinder( mi::Uint32 n, mi::Float32 radius, mi::Float32 height)
: m_n( n), m_radius( radius), m_height( height)
{
m_mesh_connectivity = new mi::Uint32[ 2*n + 4*n];
m_normal_connectivity = new mi::Uint32[ 2*n + 4*n];
m_offsets = new mi::Uint32[ n + 2 + 1];
// offsets to the first vertex index of each polygon
m_offsets[0] = 0; // base (n vertices)
m_offsets[1] = n; // top (n vertices)
for( mi::Uint32 i = 0; i <= n; ++i)
m_offsets[2+i] = 2*n + 4*i; // sides (4 vertices each)
// the mesh connectivity
mi::Uint32 index = 0;
for( mi::Uint32 i = 0; i < n; ++i) // base (first n even indices)
m_mesh_connectivity[index++] = 2*i;
for( mi::Uint32 i = 0; i < n; ++i) // top (first n odd indices)
m_mesh_connectivity[index++] = 2*i+1;
for( mi::Uint32 i = 0; i < n; ++i) { // sides (four subsequent indices)
m_mesh_connectivity[index++] = 2*i;
m_mesh_connectivity[index++] = (2*i + 2) % (2*n);
m_mesh_connectivity[index++] = (2*i + 3) % (2*n);
m_mesh_connectivity[index++] = (2*i + 1) % (2*n);
}
// the custom connectivity for normals
index = 0;
for( mi::Uint32 i = 0; i < n; ++i) // base (one constant normal)
m_normal_connectivity[index++] = 0;
for( mi::Uint32 i = 0; i < n; ++i) // top (one constant normal)
m_normal_connectivity[index++] = 1;
for( mi::Uint32 i = 0; i < n; ++i) { // sides (two normals each, shared
m_normal_connectivity[index++] = 2 + i; // with adjacent side face)
m_normal_connectivity[index++] = 2 + (i+1) % n;
m_normal_connectivity[index++] = 2 + (i+1) % n;
m_normal_connectivity[index++] = 2 + i;
}
}
~Cylinder()
{
delete[] m_mesh_connectivity;
delete[] m_normal_connectivity;
delete[] m_offsets;
}
mi::Uint32 num_points() const { return m_n * 2; }
mi::Uint32 num_normals() const { return m_n + 2; }
mi::Uint32 num_polys() const { return m_n + 2; }
mi::Uint32 polygon_size( mi::Uint32 p) const { return m_offsets[p+1] - m_offsets[p]; }
mi::Uint32* polygon_indices( mi::Uint32 p) const { return &m_mesh_connectivity[m_offsets[p]]; }
mi::Uint32* normal_indices( mi::Uint32 p) const { return &m_normal_connectivity[m_offsets[p]]; }
mi::Float32_3 point( mi::Uint32 index)
{
mi::Uint32 i = index / 2;
mi::Float32 angle = static_cast<mi::Float32>( 2.0f * MI_PI * i / m_n);
if( index % 2 == 0)
return mi::Float32_3(
-m_height/2.0f, m_radius * std::sin( angle), m_radius * std::cos( angle));
else
return mi::Float32_3(
m_height/2.0f, m_radius * std::sin( angle), m_radius * std::cos( angle));
}
mi::Float32_3 normal( mi::Uint32 index)
{
if( index == 0) return mi::Float32_3( -1.0f, 0.0f, 0.0f);
if( index == 1) return mi::Float32_3( 1.0f, 0.0f, 0.0f);
mi::Float32 angle = static_cast<mi::Float32>( 2.0f * MI_PI * (index-2) / m_n);
return mi::Float32_3( 0.0f, std::sin( angle), std::cos( angle));
}
private:
mi::Float32 m_radius, m_height;
mi::Uint32* m_mesh_connectivity;
mi::Uint32* m_normal_connectivity;
mi::Uint32* m_offsets;
};
// Create a cylinder with a regular N-gon as base and normal vectors.
mi::Uint32 n, mi::Float32 radius, mi::Float32 height)
{
Cylinder cylinder( n, radius, height);
// Create an empty polygon mesh
= transaction->create<mi::neuraylib::IPolygon_mesh>( "Polygon_mesh");
check_success( mesh);
// Create a cylinder (points and polygons)
mesh->reserve_points( cylinder.num_points());
for( mi::Uint32 i = 0; i < cylinder.num_points(); ++i)
mesh->append_point( cylinder.point( i));
for( mi::Uint32 i = 0; i < cylinder.num_polys(); ++i)
mesh->add_polygon( cylinder.polygon_size( i));
// Map vertices of the polygons to points
for( mi::Uint32 i = 0; i < cylinder.num_polys(); ++i)
mesh_connectivity->set_polygon_indices(
mi::neuraylib::Polygon_handle( i), cylinder.polygon_indices( i));
check_success( mesh->attach_mesh_connectivity( mesh_connectivity.get()) == 0);
// Create a custom connectivity for normal vectors and map vertices to entries in the
// attribute vector
for( mi::Uint32 i = 0; i < cylinder.num_polys(); ++i)
normal_connectivity->set_polygon_indices(
mi::neuraylib::Polygon_handle( i), cylinder.normal_indices( i));
// Create an attribute vector for the normals
normal_connectivity->create_attribute_vector( mi::neuraylib::ATTR_NORMAL));
for( mi::Uint32 i = 0; i < cylinder.num_normals(); ++i)
normals->append_vector3( cylinder.normal( i));
check_success( normals->is_valid_attribute());
check_success( normal_connectivity->attach_attribute_vector( normals.get()) == 0);
check_success( !normals->is_valid_attribute());
check_success( mesh->attach_connectivity( normal_connectivity.get()) == 0);
return mesh;
}
// Add a red cylinder as polygon mesh and a blue cylinder as tessellation of the red cylinder
void setup_scene( mi::neuraylib::ITransaction* transaction, const char* rootgroup)
{
mi::Float32 cylinder_radius = 0.6f;
mi::Float32 cylinder_height = 1.2f;
// Create the red cylinder
transaction, 23, cylinder_radius, cylinder_height));
transaction->store( mesh_red.get(), "mesh_red");
// Create the instance for the red cylinder
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.1, -cylinder_radius, 0.2);
matrix.rotate( 0.0, -0.5 * MI_PI_2, 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( "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");
// Tessellate the polygon mesh of the red cylinder.
transaction->create<mi::neuraylib::ITessellator>( "Tessellator"));
transaction->access<mi::neuraylib::IPolygon_mesh>( "mesh_red"));
tessellator->run( c_mesh_red.get()));
transaction->store( m_mesh_blue.get(), "mesh_blue");
// Create the instance for the blue cylinder
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( -1.1, -cylinder_radius, -1.1);
instance->set_matrix( matrix);
visible = instance->create_attribute<mi::IBoolean>( "visible", "Boolean");
visible->set_value( true);
mi::base::Handle<mi::IRef> ref( instance->create_attribute<mi::IRef>( "material", "Ref"));
ref->set_reference( "blue_material");
transaction->store( instance.get(), "instance_blue");
// And attach the instance to the root group
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 a polygon mesh and a tessellated blue mesh 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_polygon_mesh.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_polygon_mesh <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
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
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
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
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
Interface representing a polygon mesh.
Definition: ipolygon_mesh.h:128
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 IPolygon_connectivity * create_connectivity(Connectivity_map_type map_type=CONNECTIVITY_MAP_GENERIC)=0
Creates a new connectivity for non-per-primitive attributes.
virtual Sint32 attach_connectivity(IPolygon_connectivity *connectivity)=0
Attaches a given connectivity to the mesh.
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
Functor to tessellate a polygon mesh into a triangle mesh.
Definition: itessellator.h:33
A transaction provides a consistent view on the database.
Definition: itransaction.h:81
virtual const base::IInterface * access(const char *name)=0
Retrieves an element from the database.
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
float Float32
32-bit float.
Definition: types.h:51
#define MI_PI
Value of Pi.
Definition: types.h:192
signed int Sint32
32-bit signed integer.
Definition: types.h:46
Color sin(const Color &c)
Returns a color with the elementwise sine of the color c.
Definition: color.h:764
Color cos(const Color &c)
Returns a color with the elementwise cosine of the color c.
Definition: color.h:561
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
@ ATTR_NORMAL
Surface normals of type mi::Float32_3 per point or per vertex.
Definition: iattribute_vector.h:65
Iray SDK API.
[Previous] [Next] [Up]