2
$\begingroup$

My object is originally a spherical MESH, and it is transformed into a point cloud using several geometry nodes (mesh to points, raycast, etc).

Then I would like to access the data associated to this point cloud : I can see those data in the datasheet of the UI like shown on the image, and the UI shows a perfectly fine cloud, but impossible for me to acccess the data via python API.

I have tried using depsgraph_get and evaluated_get but the result is always of MESH type, and no vertices in it (object_evaluated.data.vertices), it is like nothing has been evaluated.

One side note is that, adding a PointToVertices node at the end, I can access the vertices location, but the object is not Point Cloud anymore, and it is difficult to color a purely vertex object...

enter image description here

enter image description here

If someone has an idea how to get those point cloud data (in particular location) that would be great.

Edit : An interesting thing is that on a very simple example : a cube with 1/ node scale by two 2/ mesh to point. Then I read attribute position obj.data.attributes['position'] -> the points are (-1,1),(1,1), etc. instead of (2,2),(-2,2) like it is on datasheet => blender bug I suppose enter image description here

$\endgroup$
10
  • $\begingroup$ You should be able to access the mesh attributes with obj.data.attributes["attr_name"]. Does that not work? $\endgroup$ Commented Sep 5, 2024 at 20:01
  • $\begingroup$ "One side note is that, adding a PointToVertices node at the end, I can access the vertices location, but the object is not Point Cloud anymore, and it is difficult to color a purely vertex object..." - so convert it back to points after you set the color $\endgroup$ Commented Sep 5, 2024 at 20:38
  • $\begingroup$ @Jakemoyo thanks for the answer, I have tried using attributes, with a Store Named Attribute but the vector returned obj.data.attributes['position_pts'].data are all (0,0,0).. I have put Input Position node as Value, $\endgroup$ Commented Sep 6, 2024 at 8:46
  • $\begingroup$ It does look like you're trying to store a different amount of point data than you have vertices in the mesh. You might have to use a "Sample Nearest X" type node to convert the point position data into a per-vert value. I'm not totally sure but I think that might also be part of your problem. $\endgroup$ Commented Sep 6, 2024 at 19:06
  • $\begingroup$ @Jakemoyo There is a big difference between the original and evaluated geometry: original is a small sphere, and the evaluated is projected sphere on the scene like disco ball would do. I don't think I could use Nearest node. It seems like a blender bug that doesn't want to evaluate for POINT type, (but OK for MESH); obj.data.attributes['position'].data is giving the location of the original mesh instead of the output geometry (position_pts was giving zero but maybe my custom attribute was wrong..) $\endgroup$ Commented Sep 6, 2024 at 19:24

1 Answer 1

1
$\begingroup$

I'm not sure I understand what you want. As I wrote in a comment, you can:

  • convert points to vertices
  • modify as you want
  • convert back to points

which on a high level is expressed as such:

ob = C.object
points_to_verts(target=ob)
    
# modify the points to your liking
for v in ob.data.vertices:
    v.co *= 2

verts_to_points(target=ob, radius=0.05)

👉 The whole code then becomes:

from bpy import context as C, data as D


def main():
    ob = C.object
    points_to_verts(target=ob)
    
    # modify the points to your liking
    for v in ob.data.vertices:
        v.co *= 2
        
    verts_to_points(target=ob, radius=0.05)


def points_to_verts(*, target):
    temp_name = "Temporary datablock - delete it"
    
    ob = target
    mod = ob.modifiers.new(name=temp_name, type='NODES')

    tree = D.node_groups.new(name=temp_name, type='GeometryNodeTree')    
    tree.interface.new_socket(
        name='Geometry', in_out='OUTPUT', socket_type='NodeSocketGeometry')
    tree.interface.new_socket(
        name='Geometry', in_out='INPUT', socket_type='NodeSocketGeometry')        

    node_in = tree.nodes.new(type='NodeGroupInput')
    node_points_to_verts = tree.nodes.new(type='GeometryNodePointsToVertices')
    node_out = tree.nodes.new(type='NodeGroupOutput')

    tree.links.new(
        output = node_in.outputs['Geometry'],
        input  = node_points_to_verts.inputs['Points']
    )
    tree.links.new(
        output = node_points_to_verts.outputs['Mesh'],
        input  = node_out.inputs['Geometry']
    )
    
    mod.node_group = tree
    dg = C.evaluated_depsgraph_get()
    oldme = ob.data
    newme = ob.evaluated_get(dg).data.copy()
    ob.modifiers.clear()
    ob.data = newme
    newme.name = oldme.name
    D.meshes.remove(oldme)
    D.node_groups.remove(tree)


def verts_to_points(*, target, radius):
    tree_name = 'Verts to Points'
    ob = target
    mod = ob.modifiers.new(name='geonodes', type='NODES')
    
    tree = D.node_groups.get(tree_name)
    
    if not tree:
        tree = D.node_groups.new(name=tree_name, type='GeometryNodeTree')
        
        tree.interface.new_socket(
            name='Geometry', in_out='OUTPUT', socket_type='NodeSocketGeometry')
        tree.interface.new_socket(
            name='Geometry', in_out='INPUT', socket_type='NodeSocketGeometry')        

        node_in = tree.nodes.new(type='NodeGroupInput')
        node_mesh_to_points = tree.nodes.new(type='GeometryNodeMeshToPoints')
        # you may want to (re)store radii using a named attribute
        node_mesh_to_points.inputs['Radius'].default_value = radius
        node_out = tree.nodes.new(type='NodeGroupOutput')

        tree.links.new(
            output = node_in.outputs['Geometry'],
            input  = node_mesh_to_points.inputs['Mesh']
        )
        tree.links.new(
            output = node_mesh_to_points.outputs['Points'],
            input  = node_out.inputs['Geometry']
        )
    
    mod.node_group = tree


main()
$\endgroup$
6
  • $\begingroup$ Thank you, I could indeed use set_verts_to_points. My last node in the UI would be point to vertice, then I get my vertices in python (which works), and I use your function set_verts_to_points to get back to points, which would allow me to see the color in the UI. I will test that and get back to you if that work to solve the topic. However this is really a pity that there is no way to get in python, data that is printed in the UI (see edit part of my first post). $\endgroup$ Commented Sep 7, 2024 at 9:35
  • $\begingroup$ Just for the precision: what I want basically, is to get data of my cloud point in python, and visualize this cloud point in color in the UI, given the fact that my object is a mesh initially, converted into a cloud point in GN via raycast and so on. $\endgroup$ Commented Sep 7, 2024 at 9:36
  • $\begingroup$ @GottfriedBerton still not clear... To "get" the points, just convert them to verts and read in python from evaluated copy, without the need to change the original object. To display, there's a lot of approaches - you could do it within geonodes without ever touching python. $\endgroup$ Commented Sep 7, 2024 at 10:27
  • $\begingroup$ you are right, I can indeed convert point2verts, access the vertices in python, and vert2point using your script it works.. except that it delete the initial geometry, unlink my geometry node workflow and so on (but I work on copy project of course), but on the principle it is OK. I could even don't need vert2points: just point2vertice in python on copy object to access vertices, and for display nothing to do as the object is pointcloud $\endgroup$ Commented Sep 7, 2024 at 11:18
  • $\begingroup$ @GottfriedBerton you don't need to display both objects, in the end of the day it's hard to help if you say you want to "get" point data without a broader context. $\endgroup$ Commented Sep 7, 2024 at 11:49

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.