The goal of this notebook is to test pythreejs. It appears to be a good bridge between threejs and the ability to do interactive 3D visualization in the notebook format.
import pythreejs
pythreejs.version_info
(2, 2, 0, 'final')
import traitlets
traitlets.__version__
'5.0.4'
from pythreejs import *
from IPython.display import display
from math import pi
BoxGeometry()
Preview(child=BoxGeometry(), shadowMap=WebGLShadowMap())
DodecahedronGeometry()
Preview(child=DodecahedronGeometry(), shadowMap=WebGLShadowMap())
IcosahedronGeometry()
Preview(child=IcosahedronGeometry(), shadowMap=WebGLShadowMap())
OctahedronGeometry()
Preview(child=OctahedronGeometry(), shadowMap=WebGLShadowMap())
view_width = 600
view_height = 600
ball = Mesh(geometry=SphereGeometry(radius=1, widthSegments=32, heightSegments=24),
material=MeshLambertMaterial(color='red'),
position=[2, 1, 0], scale=[1,1,1])
c = PerspectiveCamera(scale=[1,1,1], position=[0, 5, 5], up=[0, 1, 0],
children=[DirectionalLight(color='white', intensity=0.5)])
scene = Scene(scale=[1,1,1], children=[ball, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c,
scene=scene,
alpha=True,
clearOpacity=0,
controls=[OrbitControls(controlling=c)],
width=view_width, height=view_height)
display(renderer)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.5),), position=(0.0, 5…
sphere = Mesh(
SphereBufferGeometry(1, 32, 16),
MeshStandardMaterial(color='red'),
position=[2, 0, 2],
scale=[1, 1, 1]
)
cube = Mesh(
BoxBufferGeometry(1, 1, 1),
MeshPhysicalMaterial(color='green'),
position=[2, 0, 4],
scale=[1, 1, 1]
)
camera = PerspectiveCamera( position=[10, 6, 10], aspect=view_width/view_height, scale=[1, 1, 1])
key_light = DirectionalLight(position=[0, 10, 10])
ambient_light = AmbientLight()
positon_track = VectorKeyframeTrack(name='.position',
times=[0, 2, 5],
values=[10, 6, 10,
6.3, 3.78, 6.3,
-2.98, 0.84, 9.2,
])
rotation_track = QuaternionKeyframeTrack(name='.quaternion',
times=[0, 2, 5],
values=[-0.184, 0.375, 0.0762, 0.905,
-0.184, 0.375, 0.0762, 0.905,
-0.0430, -0.156, -0.00681, 0.987,
])
camera_clip = AnimationClip(tracks=[positon_track, rotation_track])
camera_action = AnimationAction(AnimationMixer(camera), camera_clip, camera)
scene = Scene(children=[sphere, cube, camera, key_light, ambient_light], scale=[1, 1, 1])
controller = OrbitControls(controlling=camera)
renderer = Renderer(camera=camera, scene=scene, controls=[controller],
width=view_width, height=view_height)
renderer
Renderer(camera=PerspectiveCamera(position=(10.0, 6.0, 10.0), scale=(1.0, 1.0, 1.0)), controls=[OrbitControls(…
camera_action
AnimationAction(clip=AnimationClip(duration=5.0, tracks=(VectorKeyframeTrack(name='.position', times=array([0,…
import numpy as np
from IPython.display import display
from ipywidgets import HTML, Text, Output, VBox
from traitlets import link, dlink
ball = Mesh(geometry=SphereGeometry(radius=1, widthSegments=32, heightSegments=24),
material=MeshLambertMaterial(color='red'),
position=[2, 1, 0], scale=[1, 1, 1])
c = PerspectiveCamera(position=[0, 5, 5], up=[0, 1, 0],
children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)],
scale=[1, 1, 1])
scene = Scene(children=[ball, c, AmbientLight(color='#777777')], scale=[1, 1, 1])
renderer = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)])
display(renderer)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.5, position=(3.0, 5.0,…
ball.scale = (0.5,) * 3
import time, math
ball.material.color = '#4400dd'
for i in range(1, 150, 2):
ball.scale = (i / 100.,) * 3
ball.position = [math.cos(i / 10.), math.sin(i / 50.), i / 100.]
time.sleep(.05)
# Generate surface data:
view_width = 600
view_height = 400
nx, ny = (20, 20)
xmax=1
x = np.linspace(-xmax, xmax, nx)
y = np.linspace(-xmax, xmax, ny)
xx, yy = np.meshgrid(x, y)
z = xx ** 2 - yy ** 2
#z[6,1] = float('nan')
# Generate scene objects from data:
surf_g = SurfaceGeometry(z=list(z[::-1].flat),
width=2 * xmax,
height=2 * xmax,
width_segments=nx - 1,
height_segments=ny - 1)
surf = Mesh(geometry=surf_g,
material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')),
scale=[1, 1, 1])
surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),
position=[0, 0, 1e-2], scale=[1, 1, 1]) # Avoid overlap by lifting grid slightly
# Set up picking bojects:
hover_point = Mesh(geometry=SphereGeometry(radius=0.05),
material=MeshLambertMaterial(color='hotpink'), scale=[1, 1, 1])
click_picker = Picker(controlling=surf, event='dblclick')
hover_picker = Picker(controlling=surf, event='mousemove')
# Set up scene:
key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4, scale=[1, 1, 1])
c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,
children=[key_light], scale=[1, 1, 1])
scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)], scale=[1, 1, 1])
renderer = Renderer(camera=c, scene=scene,
width=view_width, height=view_height,
controls=[OrbitControls(controlling=c), click_picker, hover_picker])
# Set up picking responses:
# Add a new marker when double-clicking:
out = Output()
def f(change):
value = change['new']
with out:
print('Clicked on %s' % (value,))
point = Mesh(geometry=SphereGeometry(radius=0.05),
material=MeshLambertMaterial(color='red'),
position=value)
scene.add(point)
click_picker.observe(f, names=['point'])
# Have marker follow picker point:
link((hover_point, 'position'), (hover_picker, 'point'))
# Show picker point coordinates as a label:
h = HTML()
def g(change):
h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])
g({'new': hover_point.position})
hover_picker.observe(g, names=['point'])
display(VBox([h, renderer, out]))
surf_g.z = list((-z[::-1]).flat)
surf.material.map = height_texture(-z[::-1])
Let's try and create a simple cristal lattice.
import numpy as np
view_width = 600
view_height = 600
dx = 1.5
dy = 1.
dz = 1.5
nx = 3
ny = 4
nz = 5
xi = np.arange(nx) * dx
yi = np.arange(nx) * dy
zi = np.arange(nx) * dz
xi -= xi.mean()
yi -= yi.mean()
zi -= zi.mean()
children = []
for x in xi:
for y in yi:
for z in zi:
ball = Mesh(geometry=SphereGeometry(radius=0.6, widthSegments=28, heightSegments=24),
material=MeshNormalMaterial(),
position=[x, y, z], scale=[1,1,1])
children.append(ball)
cube = Mesh(
BoxBufferGeometry(dx, dy, dz),
MeshPhysicalMaterial(color='red', wireframe=True),
position=[x, y, z],
scale=[1, 1, 1],
)
children.append(cube)
lattice = Group(children=[*children], scale=[1, 1, 1])
c = PerspectiveCamera(scale=[1,1,1], position=[15, 15, 15], up=[0, 1, 0],
children=[DirectionalLight(color='white', intensity=0.5)])
scene = Scene(scale=[1,1,1], children=[lattice, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c,
scene=scene,
alpha=True,
clearOpacity=0,
controls=[OrbitControls(controlling=c)],
width=view_width, height=view_height)
display(renderer)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.5),), position=(15.0, …
spin_track = NumberKeyframeTrack(name='.rotation[y]', times=[0, 10], values=[0, 6.28])
spin_clip = AnimationClip(tracks=[spin_track])
spin_action = AnimationAction(AnimationMixer(lattice), spin_clip, lattice)
spin_action
AnimationAction(clip=AnimationClip(tracks=(NumberKeyframeTrack(name='.rotation[y]', times=array([ 0, 10]), val…
One idea: draw elementary Bravais lattices in 3D and show how the bricks fit together. i.e. animate the construction of the lattice.
dx = 1.5
dy = 1.
dz = 1.5
nx = 3
ny = 4
nz = 5
xi = np.arange(nx) * dx
yi = np.arange(nx) * dy
zi = np.arange(nx) * dz
xi -= xi.mean()
yi -= yi.mean()
zi -= zi.mean()
children = []
for x in xi:
for y in yi:
for z in zi:
cube = Mesh(
BoxBufferGeometry(dx, dy, dz),
MeshPhysicalMaterial(color='red', wireframe=True),
position=[x, y, z],
scale=[1, 1, 1],
)
children.append(cube)
lattice = Group(children=[*children], scale=[1, 1, 1])
c = PerspectiveCamera(scale=[1,1,1], position=[15, 15, 15], up=[0, 1, 0],
children=[DirectionalLight(color='white', intensity=0.5)])
scene = Scene(scale=[1,1,1], children=[lattice, c, AmbientLight(color='#777777')])
renderer = Renderer(camera=c,
scene=scene,
alpha=True,
clearOpacity=0,
controls=[OrbitControls(controlling=c)],
width=view_width, height=view_height)
display(renderer)
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.5),), position=(15.0, …
for child in children:
child.visible = not child.visible
time.sleep(0.1)
import pyvista as pv
import numpy as np
import pyvista as pv
def parallelogram3d(origin=None, vectors=None, lengths=None):
"Construct a vtkPolyData from 3 vectors and 3 lenghts"
if origin is None:
origin = [0,0,0]
if vectors is None:
vectors = [
[1,0,0],
[0,1,0],
[0,0,1],
]
if lengths is None:
lengths = [1, 1, 1]
vectors = np.asarray(vectors, dtype=np.float64)
p0 = np.asarray(origin, dtype=np.float64)
p1 = p0 + lengths[0]*vectors[0]
p2 = p0 + lengths[1]*vectors[1]
p3 = p1 + lengths[1]*vectors[1]
p4 = p0 + lengths[2]*vectors[2]
p5 = p1 + lengths[2]*vectors[2]
p6 = p2 + lengths[2]*vectors[2]
p7 = p3 + lengths[2]*vectors[2]
points = np.asarray([p0, p1, p2, p3, p4, p5, p6, p7], dtype=np.float64)
faces = np.asarray([
[5, 0, 1, 3, 2, 0],
[5, 0, 4, 5, 1, 0],
[5, 0, 4, 6, 2, 0],
[5, 1, 3, 7, 5, 1],
[5, 2, 3, 7, 6, 2],
[5, 4, 5, 7, 6, 4],
], dtype=np.int)
parallelogram = pv.PolyData()
parallelogram.points = points
parallelogram.faces = faces
return parallelogram
pl = pv.PlotterITK(notebook=False)
pl.add_mesh(parallelogram3d(vectors=[[1,1,0], [0,1,0], [0,1,-1]], lengths=[1,2,3]))
#pl.show_axes()
#pl.show(interactive=True)
pl.show()
Viewer(geometries=[{'vtkClass': 'vtkPolyData', 'points': {'vtkClass': 'vtkPoints', 'name': '_points', 'numberO…
lengths = [1, 1, 1]
v1 = np.array([1, 0, 0])
v2 = np.array([0, 1, 0])
v3 = np.array([0, 0, 1])
import panel as pn
pn.extension('vtk')
rrrr