Clarisse 4.0 SP8 SDK  4.0.0.0.8
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Material/Texture evaluation on point clouds

Table of Contents

This topic overviews how to evaluate and bake the result of a material/textures on point clouds.

Warning
The API used in this page is likely to change in the near future.

Evaluating materials or textures on point clouds

Clarisse API allows you to evaluate a material or a texture directly on point clouds. This can be very handy if you wish to bake the result of a material or a texture without relying on a UV map. The following script evaluate a specified material on the point cloud of a geometry. Depending of the type of the geometry, point cloud can be seen as vertices. In order to run the script properly, you must have in your current selection a geometry as the first item selected and then the material you wish to evaluate.

1 if ix.selection.get_count() != 2 or not (ix.selection[0].is_kindof("Geometry") and ix.selection[1].is_kindof("Material")):
2  ix.application.log_error("You must select a geometry and a material")
3 else:
4  if ix.selection[0].get_module().is_geometry():
5  # only items of class Geometry define point clouds
6  geo = ix.selection[0].get_module().get_geometry()
7  ptc = geo.get_point_cloud()
8  # some geometries such as implicit sphere (OfClass|GeometrySphere) may not define point clouds
9  if ptc and ptc.has_positions():
10  material = ix.selection[1].get_module()
11  count = ptc.get_point_count()
12  material_colors = ix.api.GMathVec3fArray(count)
13  material_opacities = ix.api.GMathVec3fArray(count)
14  # evaluating material on each point of the point cloud
15  ix.api.ShaderHelpers.evaluate_support_material(ptc, material, material_colors, material_opacities)
16  #output the resulting colors and opacities to the Log window
17  for i in range(count) :
18  print("Point " + str(i) + ": \nCi = " + str(material_colors[i]) + "\nOi = " + str(material_opacities[i]))

Here is a typical output of the script:

Point 0:
Ci = (0.235294133424759, 0.317647069692612, 1.000000000000000)
Oi = (1.000000000000000, 1.000000000000000, 1.000000000000000)
Point 1:
Ci = (0.235294133424759, 0.317647069692612, 1.000000000000000)
Oi = (1.000000000000000, 1.000000000000000, 1.000000000000000)
...
Point 1257:
Ci = (0.329411774873734, 0.980392217636108, 0.349019616842270)
Oi = (1.000000000000000, 1.000000000000000, 1.000000000000000)
Point 1258:
Ci = (1.000000000000000, 1.000000000000000, 1.000000000000000)
Oi = (1.000000000000000, 1.000000000000000, 1.000000000000000)
Note
You can optionnally pass as argument a ModuleLayer3d to ShaderHelpers::evaluate_support_material in order to define both lighting and raytracing contexts. When omitted, raytracing calls need by the material evaluation and lights are skipped.
ShaderHelpers::evaluate_support_material is automatically scaling with the number of cores available in the application in runtime. It is best to avoid running a script calling this method when a background evaluation such as a render is already running.

Going further: baking result as point cloud property

In the previous example, we've seen how to evaluate a given material on an arbitrary point cloud. In the next example, we will go further by storing the baked result as a point cloud property. Before, running the script, copy entirely the following project and paste it in an empty context in Clarisse.

#Isotropix_Clarisse_Clipboard_Serialization 0.92
Context "ptc" {
    copy_from "project://ptc"
    GeometryPolygrid { name "polygrid" #version 0.9 copy_from "project://ptc/polygrid" shading_groups "grid" materials "project://ptc/matte" size 25 25 spans 64 64 }
    GeometryPointCloud { name "point_cloud" #version 0.91 copy_from "project://ptc/point_cloud" distribution 3 point_count 10000 geometry "project://ptc/polygrid" }
    TextureMapFile { name "map_file" #version 0.96 copy_from "project://ptc/map_file" projection 6 frame_rate 25 file_color_space "Clarisse|sRGB" }
    MaterialMatte { name "matte" #version 0.91 copy_from "project://ptc/matte" color { value 0.0 0.0 0.0 texture "project://ptc/map_file" } }
    Context "scatterer" { copy_from "project://ptc/scatterer"
        GeometryBox { name "box" #version 0.9 copy_from "project://ptc/scatterer/box" display_visible no scale 0.3 0.3 0.3  shading_groups "surface" materials "project://ptc/scatterer/matte1" }
        MaterialMatte { name "matte1" #version 0.91 copy_from "project://ptc/scatterer/matte1" color { value 0.0 0.0 0.0 texture "project://ptc/scatterer/instance_color" } }
        TextureExtractProperty { name "extract_property" #version 0.9 copy_from "project://ptc/scatterer/extract_property" color 1 1 1 1 property_name "baked_material" }
        TextureInstanceColor { name "instance_color" #version 0.91 copy_from "project://ptc/scatterer/instance_color" color { value 0.0 0.0 0.0 texture "project://ptc/scatterer/extract_property" } parent_level 1 }
        SceneObjectScatterer { name "scatterer" #version 0.92 copy_from "project://ptc/scatterer/scatterer" geometry "project://ptc/scatterer/box" }
    }
}

Here is what you should be seeing in the 3D View.

baked_material_1.png

Next select first the item project://ptc/point_cloud and then project://ptc/matte . Then run the following script

1 if ix.selection.get_count() != 2 or not (ix.selection[0].is_kindof("Geometry") and ix.selection[1].is_kindof("Material")):
2  ix.application.log_error("You must select a geometry and a material")
3 else:
4  if ix.selection[0].get_module().is_geometry():
5  # only items of class Geometry define point clouds
6  item = ix.selection[0]
7  geo = item.get_module().get_geometry()
8  ptc = geo.get_point_cloud()
9  # some geometries such as implicit sphere (OfClass|GeometrySphere) may not define point clouds
10  if ptc and ptc.has_positions():
11  material = ix.selection[1].get_module()
12 
13  count = ptc.get_point_count()
14  material_colors = ix.api.GMathVec3fArray(count)
15  material_opacities = ix.api.GMathVec3fArray(count)
16 
17  # evaluating material on each point of the point cloud
18  ix.api.ShaderHelpers.evaluate_support_material(ptc, material, material_colors.get_data(), material_opacities.get_data())
19 
20  #creating a new RGBA resource property called 'baked_material'
21  baked_material = ix.api.ResourceProperty("baked_material")
22  baked_material.init(ix.api.ResourceProperty.TYPE_FLOAT_32, 4, count)
23 
24  #transferring the baked result to the property
25  for i in range(count):
26  baked_material.set_float(i, material_colors[i][0], 0)
27  baked_material.set_float(i, material_colors[i][1], 1)
28  baked_material.set_float(i, material_colors[i][2], 2)
29  baked_material.set_float(i, material_opacities[i].get_length(), 3) #alpha
30 
31  properties = ix.api.ResourcePropertyArray(1)
32  properties[0] = baked_material
33 
34  positions = ix.api.GMathVec3fArray()
35  ptc.get_positions(positions)
36  # creating an new point cloud
37  parts = ix.api.IOHelpers.create_particles(ix.application, item.get_name() + "_ptc_copy", positions)
38  # setting our baked property in our new point cloud
39  ix.api.IOHelpers.set_particles_properties(parts, properties)

Once the script is executed, it will create a new geometry called project://ptc/point_cloud_ptc_copy. In a nutshell, the script is basically transferring the result of ShaderHelpers::evaluate_support_material in a custom property.

In order to see the result of our baked material, we've prepared a little setup which assigns to each instance of our scatterer a color read from the point cloud property we've just baked. Just go to the scatterer context and set the attribute Geometry Support of the scatterer item to project://ptc/point_cloud_ptc_copy. If everything is done properly you should get this:

baked_material_2.png

Here, each instance of our cube is reading its color from the baked_material property we've baked and stored in our point cloud.