jupyter-widgets / pythreejs

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

CloneArray children empty #298

Open gmonet opened 4 years ago

gmonet commented 4 years ago

Hi! I'm trying to visualize an atomic structure composed of about 1000 atoms with pythreejs. Knowing that I model atoms by the same mesh (a simple sphere), I tried to use the InstancedMesh class of three.js but there is no such equivalent in pythreejs. By adding the spheres one by one, it takes far too long (see #154). So I used CloneArray which is, indeed, much more efficient.

import pythreejs as tjs

view_width = 200
view_height = 200

camera = tjs.PerspectiveCamera(position=[10, 6, 10], aspect=view_width/view_height)
key_light = tjs.DirectionalLight(position=[0, 10, 10])
ambient_light = tjs.AmbientLight()
controller = tjs.OrbitControls(controlling=camera)

pos = [(0,0,0),(2,0,0),(4,0,0)]
sphere = tjs.SphereBufferGeometry()
atom = tjs.Mesh(sphere, tjs.MeshStandardMaterial())
atoms = tjs.CloneArray(atom, positions=pos, merge=False)

scn = tjs.Scene(children=[camera, key_light, ambient_light, atoms])
renderer = tjs.Renderer(camera=camera, scene=scn, controls=[controller],
                    width=view_width, height=view_height)

renderer

image

However, I can no longer access the spheres individually. For example, I can no longer change their position. Changing the "positions" attribute creates clones:

atoms.positions = [(0,3,0),(2,3,0),(4,3,0)]
renderer

image

And the CloneArray object has no children contrary to what is indicated here:

atoms.children

()

Is there a bug or did I miss something? If you have another idea to implement my problem, I'm a taker! Thanks!

vidartf commented 4 years ago

Thanks for the report!

For context, CloneArray was made as a workaround before InstancedMesh was a thing (that seems to have been introduced in r109 of threejs). The CloneArray has no children synced back to the kernel, as that would defeat the performance gains of the workaround (ref #154).

That the original clones are kept when updating the positions is likely a bug. This line is supposed to remove the old children, but I assume that might not be the right way?

vidartf commented 4 years ago

Actually, it seems the clearing logic was never implemented:

https://github.com/jupyter-widgets/pythreejs/blob/0ee2ca3034d617a06be5a8e9cb0e0a1ec60c257d/js/src/objects/CloneArray.js#L21-L23

gmonet commented 4 years ago

Thank you for your fast answer ! I see now where the problem is. Then I will try to make a custom widget from your blackbox object. Thank again 👍

vidartf commented 4 years ago

It would be better if someone did a PR that implemented the clear function though.

nvaytet commented 4 years ago

Adding InstancedMesh to pythreejs would also be super useful!

@gmonet and @vidartf: Any ideas how I could make 5000 little spheres that each have a different color?

I was using a Points geometry which was working for me until now, but I need something more flexible with different shapes, and a geometry that is not always facing the camera. I'd managed to make points of various shapes using textures, such as in this example, but it was more of a quick fix.

And once you created the spheres, is it then possible to modify their colors, just like it's possible to change their positions?

Basically, I think this example is pretty close (https://threejs.org/examples/?q=instan#webgl_buffergeometry_instancing) but I can't seem to get this to work with pythreejs.

Many thanks!