Open Boomer91 opened 4 years ago
The animation system might not be fully compliant with the behavior of threejs at the moment, but do you have any luck following the examples in https://github.com/jupyter-widgets/pythreejs/blob/master/examples/Animation.ipynb more closely? E.g. not using scene
as the local root?
No luck, see below:
from pythreejs import *
scene = Scene()
camera = PerspectiveCamera(position=[5, 0, -2], up=[0, 0, 1])
scene.add(camera)
control = OrbitControls(controlling=camera)
renderer = Renderer(camera=camera,
scene=scene,
controls=[control],
width=400,
height=400)
axes = AxesHelper(size=1)
scene.add(axes)
scene.add(AmbientLight(intensity=0.3))
arrow = ArrowHelper(color='red', dir=[0.5, 0.5, 0.5], length=3)
scene.add(arrow)
arrow_track = NumberKeyframeTrack(name='.length',
times=[0, 0.5],
values=[1, 2])
movement = AnimationClip(tracks=[arrow_track])
animation = AnimationAction(mixer=AnimationMixer(arrow),
clip=movement,
localRoot=arrow)
display(renderer)
display(animation)
For reference, here is my solution for drawing and animating an arrow between two points. One strange thing I noticed was that the arrow.quaternion is not always the unit quaternion after initialization unless dir = [0, 1, 0]
This could also be used to animate lines with moving endpoints, but feels rather convoluted. Is there no way to animate the line/arrow endpoints directly (without kernel roundtrips) instead of using position/quaternion/scale transformations?
from pythreejs import *
import numpy as np
scene = Scene()
camera = PerspectiveCamera(position=[8, 5, 2], up=[0, 0, 1])
scene.add(camera)
control = OrbitControls(controlling=camera)
renderer = Renderer(camera=camera,
scene=scene,
controls=[control],
width=600,
height=600)
axes = AxesHelper(size=1)
scene.add(axes)
scene.add(AmbientLight(intensity=0.3))
origin = [2, 1, -2] # origin of arrow
vector = [-1, 1, 5] # vector (direction & length) of arrow
n_origin = Mesh(
SphereBufferGeometry(radius=0.05),
MeshStandardMaterial(color='red'),
position=origin,
)
scene.add(n_origin)
n_vector = Mesh(
SphereBufferGeometry(radius=0.05),
MeshStandardMaterial(color='red'),
position=list(np.array(origin) + np.array(vector)),
)
scene.add(n_vector)
arrow = ArrowHelper(
dir=[0, 1, 0],
origin=[0, 0, 0],
length=1,
color='red',
name='arrow',
)
scene.add(arrow)
print(arrow.quaternion)
positions_track = NumberKeyframeTrack(name='scene/arrow.position',
times=[0, 1],
values=[[0, 0, 0], origin])
scale_array = [[1, 1, 1], 3 * [np.linalg.norm(vector)],
3 * [np.linalg.norm(vector)]]
scale_track = NumberKeyframeTrack(name='scene/arrow.scale',
times=[2, 3, 4],
values=scale_array)
# https://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another
vector = vector / np.linalg.norm(vector)
v0 = [0, 1, 0] # initial arrow direction
xyz = np.cross(v0, vector)
w = 1 + np.dot(v0, vector)
q = [*xyz, w]
q = q / np.linalg.norm(q)
print(q)
quat_array = [(0, 0, 0, 1), q]
print(q[0]**2 + q[1]**2 + q[2]**2 + q[3]**2)
quat_track = NumberKeyframeTrack(name='scene/arrow.quaternion',
times=[1, 2],
values=quat_array)
movement = AnimationClip(tracks=[positions_track, quat_track, scale_track])
animation = AnimationAction(mixer=AnimationMixer(scene),
clip=movement,
localRoot=scene,
timeScale=1)
display(renderer)
display(animation)
I'm trying to animate length and direction of an ArrowHelper, but these attributes don't seem animateable. Why is this the case?
Alternatively, I can use position, rotation and scale attributes (those inherited from Object3D) to do what I want. However I am still interested to know if this could be done using the other arrow attributes.
Related; How can I make a custom arrow class (I want an animateable circular arrow), and how can I make its attributes animateable?
Related 2: How can I animate the endpoints a of Line segment?