控制CSS立方体旋转(变换)并从3D矩阵中提取值

我使用向上/向下和向左/向右键制作了CSS旋转的立方体,但是我在旋转方向方面存在问题。

尝试#1

DEMO

使用这篇文章,我设法绑定键并将旋转应用到多维数据集。 我的第一个问题是,CSS transform函数旋转元素轴,所以当,即。 我按了,Y和Z轴改变的地方。 我调整了这种情况下的原始代码,但另一个问题是,由于轴是矢量,当我向上按压2次时,X和Z回到原位,但矢量反转(左键开始向右旋转立方体,反之亦然),所以现在我必须向相反的方向旋转立方体以获得期望的结果,并且我不知道如何检测天线轴是否倒置。

JavaScript的

var xAngle = 0,
    yAngle = 0,
    zAngle = 0,
    cube = $("#cube");

$(document).keydown(function(e) { //keyup maybe better?

  e.preventDefault();

  var key = e.which,
      arrow = {left: 37, up: 38, right: 39, down: 40},
      x = xAngle/90,
      y = yAngle/90;

    switch(key) {
      case arrow.left:
        if (x%2 == 0)
          yAngle -= 90;
        else
          zAngle += 90;
      break;
      case arrow.up:
        if (y%2 == 0)
          xAngle += 90;
        else
          zAngle -= 90;
      break;
      case arrow.right:
        if (x%2 == 0)
          yAngle += 90;
        else
          zAngle -=90;
      break;
      case arrow.down:
        if (y%2 == 0)
          xAngle -= 90;
        else
          zAngle += 90;
      break;
    }

    var rotate = "rotateX(" + xAngle + "deg) rotateY(" + yAngle + "deg) rotateZ(" + zAngle + "deg)";
    cube.css({"transform":rotate});  

});

尝试#2

DEMO

我使用本文中的方法制作了另一个版本,它试图通过分解并更新css 3d矩阵来解决同样的问题,但它还存在其他问题。 在随机方向反复按箭头后,立方体会改变视角(一次可看到多个边)。

当我能从3D矩阵中取回旋转值或矢量方向时,这会很棒,但我发现的解决方案似乎都不起作用。 我猜测是因为3D矩阵是通过传递所有函数(rotateX,rotateY和translateZ)中的多个值来导出的,并且这种数学方式超出了我的头脑。

JavaScript的

var Vector = function(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
}

WebKitCSSMatrix.prototype.transformVector = function(v) {
    var xOut = this.m11*v.x + this.m12*v.y + this.m13*v.z;
    var yOut = this.m21*v.x + this.m22*v.y + this.m23*v.z;
    var zOut = this.m31*v.x + this.m32*v.y + this.m33*v.z;

    return new Vector(xOut, yOut, zOut);
};

function applyRotation(vector, angle) {

    var cube = $('#cube');

    var matrix = new WebKitCSSMatrix(cube.css('webkitTransform'));

    var vector = matrix.transformVector(vector);

    var newMatrix = matrix.rotateAxisAngle(vector.x, vector.y, vector.z, angle);

    cube.get(0).style.webkitTransform = newMatrix;
}

// rotate using arrow keys
$(document).keyup(function(e) {

    e.preventDefault();

    var key = e.which,
            arrow = {left: 37, up: 38, right: 39, down: 40},
            v,
            a;

        switch(key) {
            case arrow.left:
                v = new Vector(0,1,0),
                a = -90;
            break;

            case arrow.right:
                v = new Vector(0,1,0),
                a = 90;
            break;

            case arrow.up:
                v = new Vector(1,0,0),
                a = 90;
            break;

            case arrow.down:
                v = new Vector(1,0,0),
                a = -90;
            break;
        }

        applyRotation(v, a);

});

尝试#3

DEMO

我做的第三个版本分别旋转每边,并在旋转后改变类,所以我总是只将X和Y旋转到正确的方向,但是当旋转发生时,cube会分解,我认为上下旋转是错误的(加上代码有点臃肿和丑陋)。 这种方法的另一方面是对不支持preserve-3d属性的浏览器具有更大的跨浏览器兼容性。

JavaScript的

$(document).keyup(function(e) {

  e.preventDefault();

  var key = e.which,
      arrow = {left: 37, up: 38, right: 39, down: 40},
      front = "rotateX(0deg) translateZ(100px)",
      back = "rotateX(180deg) translateZ(100px)",
      right = "rotateY(90deg) translateZ(100px)",
      left = "rotateY(-90deg) translateZ(100px)",
      top = "rotateX(90deg) translateZ(100px)",
      bottom = "rotateX(-90deg) translateZ(100px)";

    switch(key) {
      case arrow.left:
        $(".front").css({"transform":left});
        $(".back").css({"transform":right});
        $(".left").css({"transform":back});
        $(".right").css({"transform":front});
        var front = $(".front");
        var back = $(".back");
        var left = $(".left");
        var right = $(".right");
        front.removeClass("front").addClass("left");
        back.removeClass("back").addClass("right");
        right.removeClass("right").addClass("front");
        left.removeClass("left").addClass("back");
      break;
      case arrow.up:
        $(".front").css({"transform":top});
        $(".back").css({"transform":bottom});
        $(".top").css({"transform":back});
        $(".bottom").css({"transform":front});
        var front = $(".front");
        var back = $(".back");
        var top = $(".top");
        var bottom = $(".bottom");
        front.removeClass("front").addClass("top");
        back.removeClass("back").addClass("bottom");
        top.removeClass("top").addClass("back");
        bottom.removeClass("bottom").addClass("front");
      break;
      case arrow.right:
        $(".front").css({"transform":right});
        $(".back").css({"transform":left});
        $(".left").css({"transform":front});
        $(".right").css({"transform":back});
        var front = $(".front");
        var back = $(".back");
        var left = $(".left");
        var right = $(".right");
        front.removeClass("front").addClass("right");
        back.removeClass("back").addClass("left");
        right.removeClass("right").addClass("back");
        left.removeClass("left").addClass("front");
      break;
      case arrow.down:
        $(".front").css({"transform":bottom});
        $(".back").css({"transform":top});
        $(".top").css({"transform":front});
        $(".bottom").css({"transform":back});
        var front = $(".front");
        var back = $(".back");
        var top = $(".top");
        var bottom = $(".bottom");
        front.removeClass("front").addClass("bottom");
        back.removeClass("back").addClass("top");
        top.removeClass("top").addClass("front");
        bottom.removeClass("bottom").addClass("back");
      break;
    }

});

参考资料:

  • 创建基本的CSS立方体
  • MDN文档介绍transform属性
  • W3.org有关3D变换的文档
  • 3dmatrix文档
  • webkitCSSMatrix文档

  • 尝试2的问题在于rotateAxisAngle以您想要的相反顺序进行矩阵乘法。 而且,更糟糕的是,班级中没有按照您想要的顺序进行乘法的功能。

    作为一种替代方法,我选择使用浏览器来进行数学计算。 我创建一个将被隐藏的div,以及我将在哪里应用变换以获取新矩阵。

    使用这种方法,JavaScript会变得更短:

    function applyTransform (transform) {
    
        var cubeCalculator = $('.cubecalculator');
        var cube = $('#cube');
    
        var matrix = cubeCalculator.css('webkitTransform');
        var composite = transform + ' ' + matrix;
        cubeCalculator.get(0).style.webkitTransform = composite;
    
        matrix = cubeCalculator.css('webkitTransform');
        cube.get(0).style.webkitTransform = matrix;
    }
    
    // rotate using arrow keys
    $(document).keyup(function(e) {
    
        e.preventDefault();
    
        var key = e.which,
            arrow = {left: 37, up: 38, right: 39, down: 40},
            t;
    
        switch(key) {
            case arrow.left:
                t = 'rotateY(-90deg)';
            break;
    
            case arrow.right:
                t = 'rotateY(90deg)';
            break;
    
            case arrow.up:
                t = 'rotateX(90deg)';
            break;
    
            case arrow.down:
                t = 'rotateX(-90deg)';
            break;
        }
    
        applyTransform (t);
    
    });
    

    我认为代码是非常自我解释的:我将变换应用到元素,作为新变换和当前变换的组合(您不需要从矩阵中提取值,可以按原样应用)

    演示

    (我不知道为什么,它在codepen中不起作用,把它移到了小提琴...)

    最后,我得到了* Firefox的行为!

    function applyTransform (transform1, transform2) {
        var matrix, composite1, composite2;
        var cubeCalculator = $('.cubecalculator');
        var cube = $('#cube');
    
        matrix = cubeCalculator.css('transform');
        composite1 = transform1 + ' ' + matrix;
        composite2 = transform2 + ' ' + matrix;
        cubeCalculator.get(0).style.transform = composite2;
        cube.get(0).style.transition = 'none';
        cube.get(0).style.transform = composite1;
    
        window.setTimeout (function() {
            cube.get(0).style.transform = composite2;
            cube.get(0).style.transition = 'transform 1s';
        }, 10   );
    }
    
    // rotate using arrow keys
    $(document).keyup(function(e) {
    
        e.preventDefault();
    
        var key = e.which,
            arrow = {left: 37, up: 38, right: 39, down: 40},
            t1, t2;
    
        switch(key) {
            case arrow.left:
                t1 = 'rotateY(0deg)';
                t2 = 'rotateY(-90deg)';
            break;
    
            case arrow.right:
                t1 = 'rotateY(0deg)';
                t2 = 'rotateY(90deg)';
            break;
    
            case arrow.up:
                t1 = 'rotateX(0deg)';
                t2 = 'rotateX(90deg)';
            break;
    
            case arrow.down:
                t1 = 'rotateX(0deg)';
                t2 = 'rotateX(-90deg)';
            break;
        }
    
        applyTransform (t1, t2);
    
    });
    

    一些更复杂的代码,但使浏览器完全清楚你想要它做什么......只要你等到转换结束,就可以正常工作。


    演示2几乎在那里。 你的问题是你正在使用多维数据集的中间动画状态来计算新的位置:

    var matrix = new WebKitCSSMatrix(cube.css('webkitTransform'));
    

    相反,您应该存储并更新内部目标矩阵:

    此外,它似乎是这段代码:

    var vector = matrix.transformVector(vector);
    var newMatrix = matrix.rotateAxisAngle(vector.x, vector.y, vector.z, angle);
    

    不按预期工作。 这就是你要找的东西:

    var newMatrix = new WebKitCSSMatrix().rotateAxisAngle(...).multiply(matrix)
    

    http://codepen.io/eric-wieser/pen/BoeyD

    链接地址: http://www.djcxy.com/p/71221.html

    上一篇: Controling CSS cube rotation(transform) and extracting values from 3d matrix

    下一篇: Why does CSS work with fake elements?