I have a rubiks-cube-like puzzle I am trying to model in webgl using Three.js:
Each of the two-color centers can rotate. When they rotate, they bring all of the pieces around them along on the rotation. For example, if we rotate the orange-blue center, this is what happens:
When you complete a rotation, everything lines up:
However, now when I try to rotate the Orange-White center, I get strange behavior for the two pieces it inherited from the Orange-Blue center after the first rotation:
I expect them to rotate like the other pieces, but instead they rotate differently.
I am using Three.js's Object3D.rotateOnAxis() function to do my rotations:
function rotate ( center, distance ) {
var axis = center.axis;
center.model.rotateOnAxis ( axis, distance );
for ( var i in center.stickers ) {
center.stickers[i].rotateOnAxis ( axis, distance );
}
for ( var i in center.children ) {
center.children[i].model.rotateOnAxis ( axis, distance );
//Note: the stickers are just the colored faces
for ( var s in center.children[i].stickers ) {
center.children[i].stickers[s].rotateOnAxis ( axis, distance );
}
}
}
Here is what my key-press code looks like:
function showCube() {
//set stuff up, then...
count = 0;
parent.onkeypress = function(event) {
if ( count < 6 ) {
rotate( blocks.centers [ "BO" ], Math.PI / 6 );
count++;
if ( count == 6 ) {
moveFace ( blocks, "O1", "OY", "BW" );
moveFace ( blocks, "O2", "OW", "BY" );
moveFace ( blocks, "B1", "BW", "OY" );
moveFace ( blocks, "B2", "BY", "OW" );
moveCorner ( blocks, "BOW", "OW", "OY" );
moveCorner ( blocks, "BOW", "BW", "BY" );
moveCorner ( blocks, "BOY", "OY", "OW" );
moveCorner ( blocks, "BOY", "BY", "BW" );
}
} else {
rotate( blocks.centers [ "OW" ], Math.PI / 6 );
}
}
}
function moveFace ( blocks, child, oldParent, newParent ) {
var index = blocks.centers [ oldParent ].children.indexOf ( blocks.faces [ child ] );
blocks.centers [ oldParent ].children.splice ( index, 1 );
blocks.centers [ newParent ].children.push ( blocks.faces [ child ] );
}
function moveCorner ( blocks, child, oldParent, newParent ) {
var index = blocks.centers [ oldParent ].children.indexOf ( blocks.corners [ child ] );
blocks.centers [ oldParent ].children.splice ( index, 1 );
blocks.centers [ newParent ].children.push ( blocks.corners [ child ] );
}
Interestingly, to get the Blue-Orange-Yellow corner to rotate correctly, I need to do the rotation around the difference between the BO vector and the OW vector.
That is to say:
- Blue-Orange axis is the normalized vector of: (0, 1, 1)
- Orange-White axis is the normalized vector of: (1, 0, 1)
- After the first rotation is complete, if I try to rotate the BOY corner around the normal of (1, 0, 1), I get the behavior shown in the pictures.
- However, if I try to rotate it around (0, 1, 1) - (1, 0, 1), i.e. (-1, 1, 0), I get the desired behavior.
I don't understand what's happening. Can you help me update my rotate function so I get the behavior I want, without having to keep a long list of past rotations that a piece has experienced?
I suspect that after I do my first rotation, I need to tell the piece to "zero" its rotation state without causing any motion, but I'm not quite sure how to do that, or if it's the right approach.
You can play with the thing here: http://joshuad.net/clover-cube/so-question/
Thanks!




I fixed it by changing my rotate method to this:
The idea is that the function applyStatesToMatrixDirectly() applies the rotation directly to the model matrix and then reset all of the rotation data (as well as everything else). This allows the model to "forget" that it has been rotated, allowing the new rotateOnAxis to work.