0

随着时间的推移,我为场景中的每个对象生成 4x4 变换矩阵,并使用VectorKeyframeTrackMesh 对象设置变换矩阵。我可以AnimateAction为每个对象单独设置动画,但无法弄清楚如何让所有对象通过一次.play()调用同时动画并保持同步。据我所知,希望从第二个循环开始,对象将是时间同步的,但它们不是:

import pythreejs as pjs

rod_mesh = pjs.Mesh(
    pjs.CylinderBufferGeometry(0.005, 0.005, sys.constants[lB] - sys.constants[h] / 2,),
    pjs.MeshStandardMaterial(color='red')
)

plate_mesh = pjs.Mesh(pjs.PlaneBufferGeometry(sys.constants[h], sys.constants[w]),
                      pjs.MeshStandardMaterial(color='blue', side='DoubleSide'))
# Animation will not update without this set.
rod_mesh.matrixAutoUpdate = False
plate_mesh.matrixAutoUpdate = False
# Set initial position/orientation
rod_mesh.matrix = rod_matrices[0]
plate_mesh.matrix = plate_matrices[0]

# Setup scene
view_width = 600
view_height = 400
camera = pjs.PerspectiveCamera(position=[0.25, 0.25, 0.25], aspect=view_width/view_height)
key_light = pjs.DirectionalLight(position=[0, 10, 10])
ambient_light = pjs.AmbientLight()
scene_pjs = pjs.Scene(children=[rod_mesh, plate_mesh, camera, key_light, ambient_light])
controller = pjs.OrbitControls(controlling=camera)
renderer = pjs.Renderer(camera=camera, scene=scene_pjs, controls=[controller], width=view_width, height=view_height)

# Specify KeyframeTracks
rod_track = pjs.VectorKeyframeTrack(name='.matrix', times=list(sys.times), values=rod_matrices)
plate_track = pjs.VectorKeyframeTrack(name='.matrix', times=list(sys.times), values=plate_matrices)

rod_clip = pjs.AnimationClip(tracks=[rod_track])
plate_clip = pjs.AnimationClip(tracks=[plate_track])

rod_mixer = pjs.AnimationMixer(rod_mesh)
plate_mixer = pjs.AnimationMixer(plate_mesh)

rod_action = pjs.AnimationAction(rod_mixer, rod_clip, rod_mesh)
plate_action = pjs.AnimationAction(plate_mixer, plate_clip, plate_mesh)

# Try to enforce syncronization among actions at each loop start
plate_action.exec_three_obj_method('syncWith', 'IPY_MODEL_' + rod_action.get_view_spec()['model_id'])
rod_action.exec_three_obj_method('syncWith', 'IPY_MODEL_' + plate_action.get_view_spec()['model_id'])

listener_func = '() => {{ {}.syncWith({}); }}'.format('IPY_MODEL_' + plate_action.get_view_spec()['model_id'], 'IPY_MODEL_' + rod_action.get_view_spec()['model_id'])

rod_mixer.exec_three_obj_method('addEventListener', 'loop', listener_func)

syncWith()必须在每个帧转换时调用,但我不确定如何影响 pythreejs 的动画帧循环。

4

1 回答 1

0

这里给出了一个解决方案:

https://github.com/jupyter-widgets/pythreejs/issues/262

关键是动画场景而不是单个网格,这样做的技巧是命名网格,然后scene/<mesh name>.<attribute to change>在设置 KeyFrameTracks 时使用。这是我重新设计的示例:

rod_mesh = pjs.Mesh(pjs.CylinderBufferGeometry(0.005, 0.005, sys.constants[lB] - sys.constants[h] / 2),
                    pjs.MeshStandardMaterial(color='red'),
                    name='rod'  # name each mesh!
)

plate_mesh = pjs.Mesh(pjs.PlaneBufferGeometry(sys.constants[h], sys.constants[w]),
                      pjs.MeshStandardMaterial(color='blue', side='DoubleSide'),
                      name="plate"  # name each mesh!
)

# For updating the transform matrices directly set:
rod_mesh.matrixAutoUpdate = False
plate_mesh.matrixAutoUpdate = False

# Scene setup
view_width = 600
view_height = 400
camera = pjs.PerspectiveCamera(position=[0.25, 0.25, 0.25], aspect=view_width/view_height)
key_light = pjs.DirectionalLight(position=[0, 10, 10])
ambient_light = pjs.AmbientLight()
scene_pjs = pjs.Scene(children=[rod_mesh, plate_mesh, camera, key_light, ambient_light])
controller = pjs.OrbitControls(controlling=camera)
renderer = pjs.Renderer(camera=camera, scene=scene_pjs, controls=[controller], width=view_width, height=view_height)

# Key thing here is to set the attribute you want to change as a sub-item of the scene. Use the names of the meshes above.
rod_track = pjs.VectorKeyframeTrack(name='scene/rod.matrix',
                                    times=list(sys.times),
                                    values=rod_matrices)
plate_track = pjs.VectorKeyframeTrack(name='scene/plate.matrix',
                                      times=list(sys.times),
                                      values=plate_matrices)

# Now create a single clip with both tracks and animate the scene:
clip = pjs.AnimationClip(tracks=[rod_track, plate_track], duration=sys.times[-1])
action = pjs.AnimationAction(pjs.AnimationMixer(scene_pjs), clip, scene_pjs)

这是我的完整工作示例:

https://gist.github.com/moorepants/c5ebb846499c4002744b8c101705015f

于 2019-11-24T16:26:34.973 回答