2

我以前没有玩过 WebKitCSSMatrix 属性,所以我决定给自己一个挑战,制作一个基于 Web 的魔方。这是以前做过的事情,但我想我会从头开始尝试(不查看任何其他来源)。但是,在旋转每个单独的立方体时,我现在遇到了一些困难。

这是我目前拥有的:JSFiddle。(是的,现在这只是一个 2x2 立方体)。

请注意,轴本身还没有作为一个整体旋转,我现在只专注于单个立方体旋转。

为了旋转每一边,您只需单击并拖动。因此,例如,如果您单击左上角的红色方块并向右拖动光标,您将逆时针向右旋转顶行的每个立方体。

如您所见,如果仅以一种方式(或相反的方式)进行,则每个轴的每个立方体都可以正确旋转,但是当您组合两个轴时,旋转就会混乱。发生这种情况是因为我假设我对该rotateAxisAngle()方法的使用没有与之前的轮换叠加。

例如,如果我们抓住正面左上角的红色方块并向右拖动,我们最终会得到:

红色左上前右旋转

此处case ('right')已触发并rotateAxisAngle(0, 1, 0, 90)应用了旋转。红色立方体已逆时针向右旋转,现在白色面根据需要位于前面。这个红色立方体现在有以下内容style

<div
    class="cube"
    style="
        -webkit-transform: matrix3d( 0,  0, -1,  0,
                                     0,  1,  0,  0,
                                     1,  0,  0,  0,
                                     0,  0,  0,  1 );
"> ... </div>

如果我们现在抓住同一个正方形并将其向下移动,顶部的蓝色面应该在前面结束。这就是问题所在。在这样做时,我们最终得到:

向右旋转后相同的红色方块向下旋转

立方体不是顺时针向下旋转,而是逆时针向右旋转。矩阵已转换为:

-webkit-transform: matrix3d( 0,  0, -1,  0,
                            -1,  0,  0,  0,
                             0,  1,  0,  0,
                             0,  0,  0,  1 );

所需的矩阵应该是:

-webkit-transform: matrix3d( 0, -1,  0,  0,
                             0,  0, -1,  0,
                             1,  0,  0,  0,
                             0,  0,  0,  1 );

我需要做什么才能将新旋转堆叠在前一个旋转之上,就好像前一个旋转是立方体的默认旋转一样?

4

2 回答 2

1

问题是,在进行矩阵变换时(在您的情况下是旋转),您将原始矩阵乘以变换。

而且,当你这样做时,你可以在右乘法和左乘法之间进行选择。

不幸的是, rotateAxisAngle 正在做你想要的相反乘法。

据我所知,无论如何都没有告诉 rotateAxisAngle 改变行为,所以你需要手动完成。

我选择在一个单独的变量中有一个单位矩阵,然后进行旋转,旋转单位矩阵并将结果乘以元素的当前变换。

那是:

var identity = new WebKitCSSMatrix();
identity.m11 = 1;
identity.m22 = 1;
identity.m33 = 1;
identity.m44 = 1;

    
$(function() {
    var
        $body = $('body'),
        $wrapper = $('#rubiks > .wrapper'),
        $rubiks = $('#rubiks'),
        spinable = true
    ;
    $.fn.extend({
        spin: function(x,y,z,direction) {
            if(this.selector === '#rubiks') {
                switch(direction) {
                    case ('left'):
                        $('div.axis[data-y="'+y+'"]').each(function() { 
                            var $this = $(this);
                            $cube = $this.find('.cube');
                            transformMatrix = $this.css('transform').split(', ');
                            matrix = new WebKitCSSMatrix($cube[0].style.webkitTransform);
                            transform = identity.rotateAxisAngle(0, 1, 0, -90);
                            matrix = transform.multiply(matrix);
                            $cube[0].style.webkitTransform = matrix.toString();
                        });
                        break;
                    case ('right'):
                        $('div.axis[data-y="'+y+'"]').each(function() {
                            var $this = $(this);
                            $cube = $this.find('.cube');
                            transformMatrix = $this.css('transform').split(', ');
                            matrix = new WebKitCSSMatrix($cube[0].style.webkitTransform);
                            transform = identity.rotateAxisAngle(0, 1, 0, 90);
                            matrix = transform.multiply(matrix);
                            $cube[0].style.webkitTransform = matrix.toString();
                        });
                        break;

我只发了2个案例,其余的都一样。

更新的演示

于 2013-10-01T17:43:26.717 回答
0

我的答案被删除了,所以我无法改进它..

我发现使用 Chrome(可能还有其他浏览器)的 getComputedStyle 方法在允许您对一组对象进行局部或全局旋转方面很有用。(见下文:不是完整的代码,而是它的要点(小提琴中的完整代码)。

关于确切的问题 - 有两种方法可以将转换添加到当前转换值,我在下面概述了它们:

想象你的对象是魔方。围绕 y 轴的全局旋转意味着立方体围绕平行于您的身体长度矢量(或只是您自己的 UP)的轴旋转。围绕 y 轴的局部旋转将是立方体围绕从标记为“原始 Y”的一侧出来的任何矢量旋转。换句话说,如果您定义立方体时红色中心面朝上,那么您可以任意移动立方体,并且局部 y 轴旋转不会改变红色中心正方形的朝向。

<div id="someForm">
  ...any number of 3d transformed objects...
</div>
.someForm{
      transform: someTransform();
      webkit-transform-origin: 50% 50%;
      moz-transform-origin: 50% 50%;
      o-transform-origin: 50% 50%;
      transform-origin: 50% 50%;

      webkit-transform-style: preserve-3d;
      moz-transform-style: preserve-3d;
      o-transform-style: preserve-3d;
      transform-style: preserve-3d;
}
var someForm = document.getElementById('someForm');
function rotateAroundAxis(axis,angle,coordSys){  
   //axis in ['X','Y','Z'];
   //angle is numeric;
   //coordSys in ['local','global']
   var oldTransform = window.getComputedStyle(someForm).transform;
       oldTransform = oldTransform!='none' ? oldTransform : ''; 
   var newTransform = ' rotate' + axis + '('+angle+'deg) ';
   var totalTransform;
   if(coordSys==='global'){
        totalTransform = oldTransform + newTransform;
   }else{ // coordSys==='local'
        totalTransform = newTransform + oldTransform+;
   }
   someForm.style.transform = totalTransform;
}

https://jsfiddle.net/weya02t3/

于 2015-03-07T18:00:37.147 回答