meshcat-dev / meshcat

Remotely-controllable 3D viewer, built on top of three.js
MIT License
256 stars 48 forks source link

set_animation fails for animations with visible and/or material properties, binding to the wrong property #105

Closed RussTedrake closed 3 years ago

RussTedrake commented 3 years ago

Symptom: I have an animation that sets a visible property to be true or false. It works great. I have another animation that sets the material property opacity to linearly interpolate through a trajectory. It works great. If I put them together (in the array of animations), the second one always fails.

This has proven to be true of many pairs of animations. Setting position twice works, but setting position and then visible breaks the visible, etc.

I've pasted an .html file (I call it test/animation2.html), which shows the issue. The commented out animation demonstrates that the second animation would have worked fine on its own. It's easy to come up with other examples that fail, too.

I dug in a bit to the three.js parsing on this, and see that PropertyBinding.js seems to be binding to the wrong (previous) property. If you inspect, e.g. viewer.animator.actions[1]._propertyBindings[0].binding.parsedPath in the browser javascript console, you will see that the second action is still trying to bind to the property name from the first action. (If my first animation was a position command, and then I sent a visible command, then the visible command will have incorrectly bound to position).

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8>
        <title>MeshCat</title>
    </head>
    <body>
        <div id="meshcat-pane">
        </div>

        <script src="main.min.js"></script>
        <script>
            var viewer = new MeshCat.Viewer(document.getElementById("meshcat-pane"));

let obj_contents = `
mtllib ./cube.mtl
usemtl material_0

v 0.0 0.0 0.0
v 1.0 0.0 0.0
v 1.0 1.0 0.0
v 0.0 1.0 0.0
v 0.0 0.0 1.0
v 1.0 0.0 1.0
v 1.0 1.0 1.0
v 0.0 1.0 1.0

vt 0.3 0.875
vt 0.2 0.625
vt 0.3 0.625
vt 0.6 0.625
vt 0.3 0.375
vt 0.3 0.125

vn 0 0 -1
vn 0 0 1
vn 0 -1 0
vn 1 0 0
vn 0 1 0
vn -1 0 0

f 3/5/1 2/5/1 1/5/1
f 1/5/1 4/5/1 3/5/1
f 5/1/2 6/1/2 7/1/2
f 7/1/2 8/1/2 5/1/2
f 1/3/3 2/3/3 6/3/3
f 6/3/3 5/3/3 1/3/3
f 2/4/4 3/4/4 7/4/4
f 7/4/4 6/4/4 2/4/4
f 3/6/5 4/6/5 8/6/5
f 8/6/5 7/6/5 3/6/5
f 4/2/6 1/2/6 5/2/6
f 5/2/6 8/2/6 4/2/6
`;

        viewer.handle_command({
            type: "set_object",
            path: "/meshcat/box1",
            object: {
                metadata: {version: 4.5, type: "Object"},
                geometries: [
                    {
                        uuid: "cef79e52-526d-4263-b595-04fa2705974e",
                        type: "_meshfile_geometry",
                        format: "obj",
                        data: obj_contents
                    }
                ],
                materials: [],
                object: {
                    uuid: "00c2baef-9600-4c6b-b88d-7e82c40e004f",
                    type: "Mesh",
                    geometry: "cef79e52-526d-4263-b595-04fa2705974e"
                }
            }
        });
        viewer.handle_command({
            type: "set_object",
            path: "/meshcat/box2",
            object: {
                metadata: {version: 4.5, type: "Object"},
                geometries: [
                    {
                        uuid: "def79e52-526d-4263-b595-04fa2705974e",
                        type: "_meshfile_geometry",
                        format: "obj",
                        data: obj_contents
                    }
                ],
                materials: [],
                object: {
                    uuid: "10c2baef-9600-4c6b-b88d-7e82c40e004f",
                    type: "Mesh",
                    geometry: "def79e52-526d-4263-b595-04fa2705974e"
                }
            }
        });
        viewer.handle_command({
            type: "set_property",
            path: "/meshcat/box1",
            property: "color",
            value: [0, 1, 0, 0.5]
        });
        viewer.handle_command({
            type: "set_property",
            path: "/meshcat/box2",
            property: "color",
            value: [1, 0, 0, 0.5]
        });
        viewer.handle_command({
            type: "set_transform",
            path: "/meshcat/box1",
            matrix: [1.0, 0, 0, 0, 
                     0, 1, 0, 0, 
                     0, 0, 1, 0, 
                     0, -2, 0, 1] // transposed
        });
        viewer.handle_command({
            type: "set_transform",
            path: "/meshcat/box2",
            matrix: [1, 0, 0, 0,
                     0, 1, 0, 0,
                     0, 0, 1, 0,
                     0, 1, 0, 1] // transposed
        });
        viewer.handle_command(cmd = {
            type: "set_animation",
            animations: [{
                path: "/meshcat/box1/<object>",
                clip: {
                    fps: 32,
                    name: "default",
                    tracks: [{
                        name: ".material.opacity",
                        type: "number",
                        keys: [{
                            time: 0,
                            value: 0
                          },{
                            time: 20,
                            value: 1
                        },{
                            time: 40,
                            value: 0
                        }]
                    }],
                }
            }, {
                path: "/meshcat/box2",
                clip: {
                    fps: 32,
                    name: "default",
                    tracks: [{
                        name: ".visible",
                        type: "bool",
                        keys: [{
                            time: 0,
                            value: true
                          },{
                            time: 20,
                            value: false
                          },{
                            time: 40,
                            value: true
                        }]
                    }]
                }
            }],
            options: {
                play: true,
                repetitions: 2,
                clampWhenFinished: true,
            }
        });
/*
        viewer.handle_command(cmd = {
            type: "set_animation",
            animations: [{
                path: "/meshcat/box2",
                clip: {
                    fps: 32,
                    name: "default",
                    tracks: [{
                        name: ".visible",
                        type: "bool",
                        keys: [{
                            time: 0,
                            value: true
                          },{
                            time: 20,
                            value: false
                          },{
                            time: 40,
                            value: true
                        }]
                    }]
                }
            }],
            options: {
                play: true,
                repetitions: 2,
                clampWhenFinished: true,
            }
        });
*/        
        </script>

         <style>
            body {
                margin: 0;
            }

            #meshcat-pane {
                width: 100vw;
                height: 100vh;
                overflow: hidden;
            }
        </style>
    </body>
</html>