Clarisse 5.0 SP8 SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Introduction to Clarisse Object Model

Table of Contents

This topic introduces Clarisse Object Model which is a key concept to master before starting to look at Clarisse API.

What's in a Clarisse project?

In Clarisse, a project is a collection of instances OfObject of different types or classes OfClass organized in a hierarchy of contexts OfContext. A context is a concept very similar to folders in a file system except that it handles visibility too. Please refer to the user guide to learn more about contexts.

The entry point of the project is accessed through the object factory OfObjectFactory. In Python you can get the object factory by calling ix.application.get_factory() or AppObject::get_factory in C++.

What are classes?

The type and the properties of an item defines what Classes OfClass are. They also define the behavior of Clarisse when it deals with items. Classes and their properties, called attribute, can be inherited. For example, the OfClass|ProjectItem is a very important class in Clarisse. When an instance of a class inherits, directly or indirectly, from the OfClass|ProjectItem class, it is automatically saved in the project file.

To avoid any confusion between C++ classes and OfClass, we've decided to prefix all reference to OfClass by 'OfClass|' in this documentation. This way the OfClass GeometryPolymesh will be referred as OfClass|GeometryPolymesh.

For example, the class OfClass|GeometryPolyfile which defines a Polygonal Mesh stored in an external file indirectly inherits from OfClass|ProjectItem. This explains why items of OfClass|GeometryPolyfile are stored in the project file. If you wish to see the hierarchy of all the classes defined in Clarisse, you can use the Class Explorer widget. Just click on Window > Class Explorer... from the main window menu to open it.

The Class Explorer doesn't display the real OfClass names. Instead, it tries to display them in a more human friendly way based on their real names. If you wish to display the real class name of your items, just enable the Type column of the Browser. To enable or disable columns in the Browser, right click on an empty space on the header located at the right part of the Browser.

If you look at the Polyfile (OfClass|GeometryPolyfile) class hierarchy, we can see that:

Polyfile (OfClass|GeometryPolyfile) < Polymesh (OfClass|GeometryPolymesh) < OfClass|Geometry < OfClass|SceneObject < Scene Item (OfClass|SceneItem) < Project Item (OfClass|ProjectItem)

Where: OfClass|GeometryPolyfile is the specialized class defining a polygonal mesh defined by an external file. OfClass|GeometryPolymesh defines a special class of geometry defining a generic polygonal mesh. OfClass|Geometry defines what's the concept of geometry in Clarisse. OfClass|SceneObject defines all objects that are renderable by Clarisse renderer. OfClass|SceneItem defines an element of a 3D scene. It defines everything related to item kinematics. OfClass|ProjectItem defines an abstract class defining instance that can be saved in the Clarisse project.

Most Clarisse classes define their own sets of attributes among those inherited by the class hierarchy. For example, the GeometryPolyfile will inherited from the attributes defined by the GeometryPolymesh class that itself inherits from its parent class Geometry and so on. Moreover, instances of a same class will always inherit from the same set of attributes. These attributes are defined in the class definition itself.

What are attributes?

Attributes OfAttr are parameters that can be generally modified by the user to modify the instance. Attribute of an instance are displayed using the Attribute Editor. Attributes can be of multiple types and define for example:

As attributes can as well be directly accessed in scripting languages as if they were class members or variables, their real name is constrained to common valid variable/member names. That way, like with OfClass, attributes real names aren't directly displayed and, instead, Clarisse UI displays them in a human friendly way. For example, the attribute enable_subdivision_surface is displayed Enable Subdivision Surface in the Attribute Editor.

Objects can also be extended by Custom Attributes. Even if they are directly meaningless to Clarisse, they can be very useful if you wish to add meta/custom data read by a custom script for example.

Attributes are usually used as interfaces to let the user modify his objects. In fact, each time an attribute is modified, the change is notified to the instance of the object. For example, if a user is modifying the Translate attribute of a OfClass|SceneItem, the OfClass|SceneItem Class is notified that the Translate attribute of this specific instance of the object has been modified. The construction of the new transformation matrix, in this example, will then be performed by the module defining the OfClass|SceneItem class.

Examples: If you wish to change default attribute values for a specific class just add in the start-up script:

1 # getting the base polyfile class
2 polymesh_class = ix.application.get_factory().get_classes().get("GeometryPolyfile")
3 # setting the base attribute smooting angle of the polyfile class to 0.0
4 polymesh_class.get_attribute("smoothing_angle").set_double(0.0)
5 # now each time a polyfile is created its default smoothing angle value will be set to 0.0 instead of 89.0

If you wish to add a custom attribute each time an instance of a classes is created just:

1 # getting the polyfile class
2 polymesh_class = ix.application.get_factory().get_classes().get("GeometryPolyfile")
3 # adding a custom attribute to the polymesh class
4 polymesh_class.add_attribute("asset_id", ix.api.OfAttr.TYPE_STRING, ix.api.OfAttr.CONTAINER_SINGLE, ix.api.OfAttr.VISUAL_HINT_DEFAULT, "Custom Attributes")
5 # now each time a polyfile is created it will have an extra attribute asset_id that will be saved in the project.
When adding an attribute to an existing class A, it is not automatically added to the class inheriting from A. Moreover, each time Clarisse is launched these attributes will always need to be added to the original classes: during project loading, attributes defined in objects that are not found in the object class are lost. This doesn't apply to custom attributes directly added to objects.

One type of attributes that is extremely important is the attribute of type reference. Attributes of type reference are used to connect objects together. Basically, each time an attribute references another object, a dependency link is created. For example, when you set the Parent attribute of a OfClass|SceneItem to another object, a link is created and the two objects become connected. Then, each time the parent object is modified, the child object is notified. These types of connections end up creating the dependency graph of Clarisse. While many 2D and 3D software forbids the creation of circular dependencies by imposing directed acyclic graphs (DAG), you'll learn later that Clarisse allows cyclic dependencies under certain circumstances.

What are modules?

Modules are interfaces to implementations of classes which are, most of the time, directly declared in a module. The implementation of a class, defines what the class is supposed to do when, among other things, an attribute has changed. For example, the implementation of the OfClass|SceneItem class "knows" it has to rebuild the transformation matrix of the object when its Translate attribute is modified.

Built-in interfaces to built-in modules are found in the Module library. By convention the interface of a module is always prefixed by Module. For example, the interface to the OfClass|SceneItem class is called ModuleSceneItem. While this convention can be applied to all modules that are shipped with Clarisse, this naming convention is not mandatory.

Modules are usually defined in dynamic libraries that contains both the class definition and the implementation. Clarisse discovers available Modules during start-up. When Clarisse starts up, it scans the specified module path (given by the command line argument -module_path) which registers all available modules.

Multiple modules can be declared in a single dynamic library. Modules must be implemented in C++.

Finally modules defines their own methods that can be used to access the internal data of the object. For example, the ModuleSceneItem::get_global_matrix_at is used to retrieve the global matrix of the object at the specified time. To access the module of an object, use OfObject::get_module. For example, in Python:

1 # Returns the name of the ModuleObject class of the first item in the selection
2 if (ix.selection.get_count() > 0): print ix.selection[0].get_module().get_class_info_name()