Isotropix Forums

Accessing Point Cloud information...?

Clarisse Scripting related topics

Accessing Point Cloud information...?

Unread postby freule » Wed May 04, 2022 10:20 pm

Hello,

I'm still pretty green at Python inside Clarisse, but I'm trying to make a script that replaces objects scattered in a pointcloud with combiners in the same position/rotation/scale as the scatterer.
For that, the first thing I'm trying to do is getting a list with each individual point's properties (position, rotation, scale and ID). Then I could loop through them, adding the combiners for each point.

Following https://clarissewiki.com/3.6/sdk/manipulating_point_clouds.html#:~:text=What%20are%20point%20clouds%3F,and%20hair%20and%20fur%20interpolation I found a way to get the pointcloud properties, but now I have no idea where to go from here.

The result I get from running this with the pointcloud selected is:

Code: Select all
<framework.GeometryPointPropertyCollection; proxy of <Swig Object of type 'GeometryPointPropertyCollection *' at 0x113aba80> >


I (think) understand that this is the collection of properties of this clarisse point cloud object, correct? But I don't know how to access a readable version of it to iterate with.

This is what I have so far (straight from the Clarisse help page):

python code

if ix.selection.get_count() > 0:
item = ix.selection[0]
if item.get_module().is_geometry():
# only items of class Geometry define point clouds
geo = item.get_module().get_geometry()
ptc = geo.get_point_cloud()
# some geometries such as implicit sphere (OfClass|GeometrySphere) may not define point clouds
if ptc:
prop_collection = item.get_module().get_properties()
print prop_collection


Any light would be greatly appreciated!
freule
 
Posts: 5
Joined: Thu Jun 15, 2017 7:14 am

Re: Accessing Point Cloud information...?

Unread postby anemoff » Thu May 05, 2022 5:16 pm

Hi,

If I understand correctly, for a given scatterer, you want to:
- get instances data: position, rotation, scale, point ID;
- for each instance, create a combiner with the same position, rotation, etc., and contains the instance object(s).

I'll come up with something.
In the meantime, you can take a look at the Bake Scatterer script in the Scatterer shelf (at "CLARISSE_5_INSTALL_DIR/clarisse/python3/shelves/scatterer/bake_scatterer.py").
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 482
Joined: Wed Jan 13, 2016 10:10 am

Re: Accessing Point Cloud information...?

Unread postby freule » Thu May 05, 2022 9:34 pm

Thanks Anthony, I appreciate it. You understood it correctly, yes.

The idea is to make it a quick to adjust individual elements pos/rot/scale in a previously scattered-populated environment.

The setup to create the pointclouds in Houdini and transfer it to Clarisse is awesome. But the set dressing I'm working on at the moment requires me to "bake" the point cloud and iterate quickly different elements of the scatterers, without having to go back to Houdini.

We're not using Clarisse 5 in the pipeline yet, but I'll check if we have a version there for studying this. "Bake Scatter" sounds exactly like what I want.

Thanks!
freule
 
Posts: 5
Joined: Thu Jun 15, 2017 7:14 am

Re: Accessing Point Cloud information...?

Unread postby anemoff » Fri May 06, 2022 10:11 am

That script exists in previous Clarisse versions. Maybe slightly different.
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 482
Joined: Wed Jan 13, 2016 10:10 am

Re: Accessing Point Cloud information...?

Unread postby anemoff » Fri May 06, 2022 3:09 pm

Here's a proof of concept that should get you started.
In this example I didn't need to create properties, I just extract the scatterer data and use it to set the attributes of the created combiners.

python code

def get_scatterer_data(sc):
"""
Extract the following data, as a tuple, from the specified scatterer `sc`.
- data[0]: instance IDs
- data[1]: support point IDs
- data[2]: instance translation
- data[3]: instance rotation
- data[4]: instance scale
- data[5]: instance object

Returns None on failure.
"""

if not sc or not sc.is_kindof("SceneObjectScatterer"):
ix.log_warning("Please select a Scatterer.")
return None

scmod = sc.get_module()

instance_count = scmod.get_instance_count()
if instance_count == 0:
ix.log_warning("Scatterer is empty")
return None

# scatterer's source objects
base_objects = scmod.get_base_objects() # type = ix.api.ModuleSceneObjectArray

instance_ids = scmod.get_instances() # type = ix.api.UIntArray
support_ids = scmod.get_support_point_indices() # type = ix.api.UIntArray

t = ix.api.GMathVec3dArray(instance_count)
r = ix.api.GMathVec3dArray(instance_count)
s = ix.api.GMathVec3dArray(instance_count)
objects = ix.api.CoreStringArray(instance_count)

for i in range(instance_count):
m = scmod.get_instance_matrix(i)

# extract translation
ix.api.GMathMatrix4x4d.extract_translation(m, t[i])

# extract rotation
# warning rotation are not normalized, they are between [-180, 180]
ix.api.GMathMatrix4x4d.compute_euler_angles(m, r[i])

# extract scale
ix.api.GMathMatrix4x4d.extract_scaling(m, s[i])

# get instanced object
objects[i] = base_objects[instance_ids[i]].get_object().get_full_name()

# for debug
#print("#{}: instance ID = {}, support ID = {}, T = {}, R = {}, S = {}, object = '{}'".format(i, instance_ids[i], support_ids[i], t[i], r[i], s[i], objects[i]))

return (instance_ids, support_ids, t, r, s, objects)

#scatterer = ix.selection[0]
scatterer = ix.get_item('build://project/scene/scatterer')
data = get_scatterer_data(scatterer)
if data:
assert len(data) == 6, "Invalid scatterer data."
instance_ids = data[0] # unused in this example
support_ids = data[1] # unused in this example
t = data[2]
r = data[3]
s = data[4]
objects = data[5]


output_ctx_path = "build://project/bake"

# optional: clear existing output context
output_ctx = ix.item_exists(output_ctx_path)
if output_ctx:
ix.cmds.DeleteItem(output_ctx_path)

# create output context
output_ctx = ix.cmds.CreateContext("bake", "", "build://project")
assert output_ctx, "Failed to create the output context."

instance_count = instance_ids.get_count()
for i in range(instance_count):
# create the combiner
combiner_name = "baked_combiner_{}".format(i)
combiner = ix.cmds.CreateObject(combiner_name, "SceneObjectCombiner", "Global", output_ctx.get_full_name())
assert combiner, "Failed to create combiner #{}".format(i)

# set combiner kinematics
combiner.get_attribute("translate").set_vec3d(t[i])
combiner.get_attribute("rotate").set_vec3d(r[i])
combiner.get_attribute("scale").set_vec3d(s[i])

# set the combiner object
ix.cmds.AddValues([combiner.get_full_name() + ".objects"], [objects[i]])


Let us know if you need further help.

Cheers,
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 482
Joined: Wed Jan 13, 2016 10:10 am

Re: Accessing Point Cloud information...?

Unread postby freule » Fri May 06, 2022 11:25 pm

Hey Anthony, thank you SO MUCH for this. Works like a charm!

Need to update some variables for paths and names, but other than that, worked beautifully! Thanks a lot!

Cheers
freule
 
Posts: 5
Joined: Thu Jun 15, 2017 7:14 am


Return to Scripting
cron