jupyter-widgets / pythreejs

A Jupyter - Three.js bridge
https://pythreejs.readthedocs.io
Other
934 stars 185 forks source link

Update colors for buffer geometry #326

Open philliptay opened 4 years ago

philliptay commented 4 years ago

I am trying to change the color of the face of a mesh with buffer geometry when it is clicked on, but nothing I've tried seems to have any effect on the display. Here is my code so far, with the on_picked function attempting to change the color of a picked face. Many of my tries are commented out, from trying to exec the three.js methods to set attributes, to modifying the array of the buffer attribute within python, to changing the entire dict of the buffer geometry - all to no avail. Any guidance would be appreciated.

# Create attributes dictionaries
face_attributes=dict(
    position = BufferAttribute(np.asarray(vertices1, dtype=np.float32), normalized=False),
    index =    BufferAttribute(np.asarray(face_indices, dtype=np.uint32).ravel(), normalized=False),
    normal = BufferAttribute(np.asarray(resolved_normals, dtype=np.float32)),
    color = BufferAttribute(np.asarray(resolved_colors, dtype=np.float32), needsUpdate=True, dynamic=True)
    )

point_attributes = dict(
    position = BufferAttribute(np.asarray(vertices, dtype=np.float32), normalized=False),
    )

edge_attributes=dict(
     position = BufferAttribute(np.asarray(vertices2, dtype=np.float32), normalized=False),
     index =    BufferAttribute(np.asarray(edge_indices, dtype=np.uint32).ravel(), normalized=False),
     )

# create buffer geometries
mesh_geom = BufferGeometry(attributes=face_attributes)
points_geom = BufferGeometry(attributes=point_attributes)
edges_geom = BufferGeometry(attributes=edge_attributes)

# create geometry objects
#g = Geometry(vertices=vertices1.tolist(), faces=tuple(face_indices))
faces_obj = Mesh(geometry=mesh_geom, material=face_mat)
points_obj = Points(geometry=points_geom, material=points_mat)
edges_obj = LineSegments(geometry=edges_geom, material=edges_mat)

#add objects to scene
scene.add([faces_obj, points_obj, edges_obj])
click_picker = Picker(controlling=faces_obj, event='dblclick')
renderer = Renderer(camera=camera, scene=scene, controls=[orbit_controls, click_picker],
                    width=view_width, height=view_height)

def on_picked(change):
    faceIndex = change['new']
    obj = change['owner'].controlling
    obj.geometry.attributes['color'].needsUpdate = True
    new_colors = np.array(obj.geometry.attributes['color'].array, dtype=np.float32)
    new_colors[faceIndex] = [255, 0.5, 0.5]
   # obj.geometry.attributes['color'].array = new_colors
    #obj.geometry.exec_three_obj_method('setAttribute', 'color', BufferAttribute(np.asarray(new_colors, dtype=np.float32), needsUpdate=True))
   # obj.exec_three_obj_method('updateMatrix')
    #obj.geometry.exec_three_obj_method('applyMatrix4', obj.matrix )
    #obj.geometry.attributes['color'].exec_three_obj_method('set', new_colors.tolist())
    #obj.geometry.attributes['color'] = BufferAttribute(np.asarray(new_colors, dtype=np.float32), needsUpdate=True)

   # obj.geometry.attributes['color'].set(new_colors)

    #obj.geometry.exec_three_obj_method('setAttribute','color', obj.geometry.attributes['color'])
    obj.geometry.attributes['color'].needsUpdate = True
    obj.geometry.attributes = dict({key:val for key, val in obj.geometry.attributes.items() if key != 'color'},
                                   color=BufferAttribute(np.asarray(new_colors, dtype=np.float32), needsUpdate=True))

    print(obj.geometry.attributes['color'].array[faceIndex])

click_picker.observe(on_picked, names=['faceIndex'])

display(renderer)
nvaytet commented 1 year ago

This is how I have been setting colors on a Points object. Maybe it helps?

import pythreejs as p3
import numpy as np

N = 1000

geometry = p3.BufferGeometry(
    attributes={
        'position':
        p3.BufferAttribute(array=20.0 * (np.random.random((N, 3)) - 0.5).astype('float32')),
        'color':
        p3.BufferAttribute(array=np.zeros([N, 3], dtype='float32'))
    })

material = p3.PointsMaterial(vertexColors='VertexColors')

points = p3.Points(geometry=geometry, material=material)

width = 800
height = 500
camera = p3.PerspectiveCamera(position=[40.0, 0, 0], aspect=width / height)
scene = p3.Scene(children=[camera, points], background="#f0f0f0")
controls = p3.OrbitControls(controlling=camera)
renderer = p3.Renderer(camera=camera,
                       scene=scene,
                       controls=[controls],
                       width=width,
                       height=height)
renderer

Initially all the points are black: Screenshot at 2022-12-06 12-38-28

Then, by setting the array of the color attribute,

geometry.attributes["color"].array = np.random.random((N, 3)).astype('float32')

I get Screenshot at 2022-12-06 12-38-36