three.js: Weird Rotation of child objects

2019-09-02 06:10发布

I'm trying to implement an experimental version of a 2x2x2 Rubiks Cube. I have adopted instructions from two previous posts with issues regarding child objects attachment and detachment: Three.js: Proper way to add and remove child objects using THREE.SceneUtils.attach/detach functions and Three.js: Adding and Removing Children of Rotated Objects and have been able to successfully understand how to rotate two faces independently.

However, when I implement the same in code, I get weird results when the rotations are applied in succession, which suggests that some transforms are getting wrong somewhere, though I can't seem to understand where. But then again, every matrix related to the parent object is reset after the rotation ends, so I don't really understand why it should happen. The rotations work appropriately when applied independently, though, which confirms that I did about 50% things right :). The sample can viewed here: sample 2x2x2 cube.

Here are the relevant code samples: --> For the event handler for rotating the right face

function rotateR()
{
    for(var i = 0; i < cubies.length; i++)
            if((pos(cubies[i]).x >= 53) && (pos(cubies[i]).x <= 55))
                active.push(cubies[i]);

        for(var i = 0; i < active.length; i++)
            console.log(active[i]);

        //reset pivot rotation
        pivot.rotation.set( 0, 0, 0 );
        pivot.updateMatrixWorld();

        //attach active[i] cubies to the pivot
        for (var i = 0; i < 4; i++)
            THREE.SceneUtils.attach(active[i], scene, pivot);   
        console.log("attached!");
        attachedR = true;
    }

And in the render function:

if((pivot.rotation.x <= 1.580000000000001) && (attachedR === true))
{
            pivot.rotation.x += 0.02;
            console.log(pivot.rotation.x);
            if(pivot.rotation.x == 1.580000000000001)
            {
                attachedR = false;
                for(var i = 0; i < active.length; i++)
                    console.log(pos(active[i]).x + ", " + pos(active[i]).y + ", " + pos(active[i]).z);

                //Detach active[i] cubies from the parent pivot
                pivot.updateMatrixWorld();
                for(var i = 0; i < active.length; i++)
                {
                    active[i].updateWorldMatrix();
                    THREE.SceneUtils.detach(active[i], pivot, scene);
                }
            }
        }

The event handler and incremental animation functions for the Upper face are the same and in the same place. The pos(cubies[i]) function returns the world coordinates of the mesh object. Where am I going wrong with the rotations of the faces? Any help would be highly appreciated. Thank you.

1条回答
贪生不怕死
2楼-- · 2019-09-02 06:29

I think that the biggest problem was that the active array never got emptied

Also, you are doing extensive matrix update, when there is none really needed

I have redone your javaScript, now it just attaches the cubes, does the rotation, and finally detaches the cubes and resets the rotation.

JavaScript

        //Rotate Right face of cube
        function rotateR()
        {
            //Find cubies that lie in the right face of cube and store them in active[i]
            for(var i = 0; i < cubies.length; i++) {
                var x = pos(cubies[i]).x; 
                if(x >= 54 && x <= 56)
                    active.push(cubies[i]);
            }

            if (active.length != 4) alert ("active num wrong");
            //attach active[i] cubies to the pivot
            for (var i = 0; i < 4; i++)
                THREE.SceneUtils.attach(active[i], scene, pivot);   
            attachedR = true;
        }

//Rotate Upper face of the cube
function rotateU()
{
    //Find cubies that lie in the up face of cube and store them in active[i]
    for(var i = 0; i < cubies.length; i++) {
        var position = pos(cubies[i]); 
        if(position.y >= 54 && position.y <= 56) {
            active.push(cubies[i]);
        }
    }

    if (active.length != 4) alert ("active num wrong");

    //attach active[i] cubies to the pivot
    for (var i = 0; i < 4; i++)
        THREE.SceneUtils.attach(active[i], scene, pivot);
    attachedU = true;
}

function detachAndReset()
{
    for(var i = 0; i < active.length; i++)
    {
        THREE.SceneUtils.detach(active[i], pivot, scene);
    }
    active.length = 0;
    attachedR = false;
    attachedU = false;
    pivot.rotation.x = 0;
    pivot.rotation.y = 0;

}

        //get world position of cubies[i]
        function pos(object)
        {
            var position = new THREE.Vector3();
            position.setFromMatrixPosition( object.matrixWorld );
            return position;
        }

        function render()
        {
            var endAnimation = false;
            //Math.PI / 2 == 1.580000000000001
            //Rotate Right face of cube
            if(attachedR === true)
            {
                pivot.rotation.x += 0.02;
                if(pivot.rotation.x >= Math.PI / 2.0) {
                    pivot.rotation.x = Math.PI / 2.0;
                    endAnimation = true;
                }
            }

            //Math.PI / 2 == 1.580000000000001
            //Rotate Upper face of cube
            if(attachedU === true)
            {
                pivot.rotation.y += 0.02;
                if(pivot.rotation.y >= Math.PI / 2.0) {
                    pivot.rotation.y = Math.PI / 2.0;
                    endAnimation = true;
                }
            } 
            renderer.render(scene, camera);
            if (endAnimation) {
                detachAndReset();
            }
}
查看更多
登录 后发表回答