from pythreejs import *
import ipywidgets
from IPython.display import display
--------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) <ipython-input-1-006cfd14fcf2> in <module>() ----> 1 from pythreejs import * 2 import ipywidgets 3 from IPython.display import display ModuleNotFoundError: No module named 'pythreejs'
view_width = 600
view_height = 400
Let's first set up a basic scene with a cube and a sphere,
sphere = Mesh(
SphereBufferGeometry(1, 32, 16),
MeshStandardMaterial(color='red')
)
cube = Mesh(
BoxBufferGeometry(1, 1, 1),
MeshPhysicalMaterial(color='green'),
position=[2, 0, 4]
)
as well as lighting and camera:
camera = PerspectiveCamera( position=[10, 6, 10], aspect=view_width/view_height)
key_light = DirectionalLight(position=[0, 10, 10])
ambient_light = AmbientLight()
First, we set up the keyframes for the position and the rotation separately:
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,
])
Next, we create an animation clip combining the two tracks, and finally an animation action to control the animation. See the three.js docs for more details on the different responsibilities of the different classes.
camera_clip = AnimationClip(tracks=[positon_track, rotation_track])
camera_action = AnimationAction(AnimationMixer(camera), camera_clip, camera)
Now, let's see it in action:
scene = Scene(children=[sphere, cube, camera, key_light, ambient_light])
controller = OrbitControls(controlling=camera)
renderer = Renderer(camera=camera, scene=scene, controls=[controller], width=view_width, height=view_height)
renderer
Failed to display Jupyter Widget of type Renderer
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
camera_action
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
Let's add another animation clip, this time animating the color of the sphere's material:
color_track = ColorKeyframeTrack(name='.material.color',
times=[0, 1], values=[1, 0, 0, 0, 0, 1]) # red to blue
color_clip = AnimationClip(tracks=[color_track], duration=1.5)
color_action = AnimationAction(AnimationMixer(sphere), color_clip, sphere)
color_action
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
Note how the two animation clips can freely be combined since they affect different properties. It's also worth noting that the color animation can be combined with manual camera control, while the camera animation cannot. When animating the camera, you might want to consider disabling the manual controls.
When animating the camera rotation above, we used the camera's quaternion
. This is the most robust method if animating free-form rotations. For example, the animation above was created by first moving the camera manually, and then reading out its position
and quaternion
properties at the wanted views. If you want more intuitive axes control, it is possible to animate the rotation
sub-attributes instead, as shown below.
f = """
function f(origu,origv) {
// scale u and v to the ranges I want: [0, 2*pi]
var u = 2*Math.PI*origu;
var v = 2*Math.PI*origv;
var x = Math.sin(u);
var y = Math.cos(v);
var z = Math.cos(u+v);
return new THREE.Vector3(x,y,z)
}
"""
surf_g = ParametricGeometry(func=f, slices=16, stacks=16);
surf1 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))
surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))
surf = Group(children=[surf1, surf2])
camera2 = PerspectiveCamera( position=[10, 6, 10], aspect=view_width/view_height)
scene2 = Scene(children=[surf, camera2,
DirectionalLight(position=[3, 5, 1], intensity=0.6),
AmbientLight(intensity=0.5)])
renderer2 = Renderer(camera=camera2, scene=scene2, controls=[OrbitControls(controlling=camera2)],
width=view_width, height=view_height)
display(renderer2)
Failed to display Jupyter Widget of type Renderer
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
spin_track = NumberKeyframeTrack(name='.rotation[y]', times=[0, 2], values=[0, 6.28])
spin_clip = AnimationClip(tracks=[spin_track])
spin_action = AnimationAction(AnimationMixer(surf), spin_clip, surf)
spin_action
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
Note that we are spinning the object itself, and that we are therefore free to manipulate the camera at will.
Set up a simple sphere geometry, and add a morph target that is an oblong pill shape:
# This lets three.js create the geometry, then syncs back vertex positions etc.
# For this reason, you should allow for the sync to complete before executing the next cell
morph = BufferGeometry.from_geometry(SphereBufferGeometry(1, 32, 16))
import numpy as np
# Set up morph targets:
vertices = np.array(morph.attributes['position'].array)
for i in range(len(vertices)):
if vertices[i, 0] > 0:
vertices[i, 0] += 1
morph.morphAttributes = {'position': [
BufferAttribute(vertices),
]}
morphMesh = Mesh(morph, MeshPhongMaterial(color='#ff3333', shininess=150, morphTargets=True))
Set up animation for going back and forth between the sphere and pill shape:
pill_track = NumberKeyframeTrack(name='.morphTargetInfluences[0]', times=[0, 1.5, 3], values=[0, 2.5, 0])
pill_clip = AnimationClip(tracks=[pill_track])
pill_action = AnimationAction(AnimationMixer(morphMesh), pill_clip, morphMesh)
camera3 = PerspectiveCamera( position=[5, 3, 5], aspect=view_width/view_height)
scene3 = Scene(children=[morphMesh, camera3,
DirectionalLight(position=[3, 5, 1], intensity=0.6),
AmbientLight(intensity=0.5)])
renderer3 = Renderer(camera=camera3, scene=scene3, controls=[OrbitControls(controlling=camera3)],
width=view_width, height=view_height)
display(renderer3, pill_action)
Failed to display Jupyter Widget of type Renderer
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
First, set up a skinned mesh with some bones:
import numpy as np
N_BONES = 3
ref_cylinder = CylinderGeometry(5, 5, 50, 5, N_BONES * 5, True)
cylinder = Geometry.from_geometry(ref_cylinder)
skinIndices = []
skinWeights = []
vertices = cylinder.vertices
boneHeight = ref_cylinder.height / (N_BONES - 1)
for i in range(len(vertices)):
vertex = vertices[i];
y = vertex[1] + 0.5 * ref_cylinder.height
skinIndex = y // boneHeight;
skinWeight = ( y % boneHeight ) / boneHeight;
# Ease between each bone
skinIndices.append([skinIndex, skinIndex + 1, 0, 0 ])
skinWeights.append([1 - skinWeight, skinWeight, 0, 0 ])
cylinder.skinIndices = skinIndices
cylinder.skinWeights = skinWeights
shoulder = Bone(position=(0, -25, 0))
elbow = Bone(position=(0, 25, 0))
hand = Bone(position=(0, 25, 0))
shoulder.add(elbow)
elbow.add(hand)
bones = [shoulder, elbow, hand]
skeleton = Skeleton(bones)
mesh = SkinnedMesh(cylinder, MeshPhongMaterial(side='DoubleSide', skinning=True))
mesh.add(bones[0])
mesh.skeleton = skeleton
helper = SkeletonHelper(mesh)
Next, set up some simple rotation animations for the bones:
# Rotate on x and z axes:
bend_tracks = [
NumberKeyframeTrack(name='.bones[1].rotation[x]', times=[0, 0.5, 1.5, 2], values=[0, 0.3, -0.3, 0]),
NumberKeyframeTrack(name='.bones[1].rotation[z]', times=[0, 0.5, 1.5, 2], values=[0, 0.3, -0.3, 0]),
NumberKeyframeTrack(name='.bones[2].rotation[x]', times=[0, 0.5, 1.5, 2], values=[0, -0.3, 0.3, 0]),
NumberKeyframeTrack(name='.bones[2].rotation[z]', times=[0, 0.5, 1.5, 2], values=[0, -0.3, 0.3, 0]),
]
bend_clip = AnimationClip(tracks=bend_tracks)
bend_action = AnimationAction(AnimationMixer(mesh), bend_clip, mesh)
# Rotate on y axis:
wring_tracks = [
NumberKeyframeTrack(name='.bones[1].rotation[y]', times=[0, 0.5, 1.5, 2], values=[0, 0.7, -0.7, 0]),
NumberKeyframeTrack(name='.bones[2].rotation[y]', times=[0, 0.5, 1.5, 2], values=[0, 0.7, -0.7, 0]),
]
wring_clip = AnimationClip(tracks=wring_tracks)
wring_action = AnimationAction(AnimationMixer(mesh), wring_clip, mesh)
camera4 = PerspectiveCamera( position=[40, 24, 40], aspect=view_width/view_height)
scene4 = Scene(children=[mesh, helper, camera4,
DirectionalLight(position=[3, 5, 1], intensity=0.6),
AmbientLight(intensity=0.5)])
renderer4 = Renderer(camera=camera4, scene=scene4, controls=[OrbitControls(controlling=camera4)],
width=view_width, height=view_height)
display(renderer4)
Failed to display Jupyter Widget of type Renderer
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
bend_action
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.
wring_action
Failed to display Jupyter Widget of type AnimationAction
.
If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean that the widgets JavaScript is still loading. If this message persists, it likely means that the widgets JavaScript library is either not installed or not enabled. See the Jupyter Widgets Documentation for setup instructions.
If you're reading this message in another frontend (for example, a static rendering on GitHub or NBViewer), it may mean that your frontend doesn't currently support widgets.