【问题标题】:rotate3d shorthandrotate3d 速记
【发布时间】:2015-01-02 06:58:32
【问题描述】:

rotateX(50deg) rotateY(20deg) rotateZ(15deg)如何组合成简写rotate3d()

【问题讨论】:

    标签: css css-transforms


    【解决方案1】:

    rotateX(50deg) 等价于rotate3d(1, 0, 0, 50deg)

    rotateY(20deg) 等价于rotate3d(0, 1, 0, 20deg)

    rotateZ(15deg) 等价于rotate3d(0, 0, 1, 15deg)

    所以...

    rotateX(50deg) rotateY(20deg) rotateZ(15deg)

    等价于

    rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)


    对于一个通用的rotate3d(x, y, z, α),你有矩阵

    在哪里


    您现在获得了 3 个rotate3d 变换中的每一个的矩阵,并将它们相乘。并且得到的矩阵是对应于得到的单个rotate3d的矩阵。不知道从中提取rotate3d 的值有多容易,但提取单个matrix3d 的值肯定很容易。


    在第一种情况下(rotateX(50deg)rotate3d(1, 0, 0, 50deg)),您有:

    x = 1y = 0z = 0α = 50deg

    所以本例中矩阵的第一行是1 0 0 0

    第二个是0 cos(50deg) -sin(50deg) 0

    第三个0 sin(50deg) cos(50deg) 0

    而第四个显然是0 0 0 1


    在第二种情况下,您有x = 0y = 1z = 0α = 20deg

    第一行:cos(20deg) 0 sin(20deg) 0

    第二行:0 1 0 0

    第三行:-sin(20) 0 cos(20deg) 0

    第四:0 0 0 1


    在第三种情况下,您有x = 0y = 0z = 1α = 15deg

    第一行:cos(15deg) -sin(15deg) 0 0

    第二行sin(15deg) cos(15deg) 0 0

    第三行和第四行分别是0 0 1 00 0 0 1


    注意:您可能已经注意到,rotateY 变换的 sin 值的符号与其他两个变换不同。这不是计算错误。这样做的原因是,对于屏幕,y 轴指向下方,而不是向上。


    因此,您需要将这三个 4x4 矩阵相乘,以便为生成的单个 rotate3d 变换获得 4x4 矩阵。正如我所说,我不确定取出 4 个值有多容易,但 4x4 矩阵中的 16 个元素正是链式变换的 matrix3d 等效项的 16 个参数。


    编辑

    实际上,这很容易......您计算rotate3d 矩阵的矩阵的迹线(对角线元素的总和)。

    4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)

    然后计算三个4x4 矩阵的乘积的迹线,将结果等同于提取α2 + 2*cos(α)。然后你计算xyz

    在这种特殊情况下,如果我计算正确,则由三个4x4 矩阵的乘积产生的矩阵轨迹将是:

    T = 
    cos(20deg)*cos(15deg) + 
    cos(50deg)*cos(15deg) - sin(50deg)*sin(20deg)*cos(15deg) + 
    cos(50deg)*cos(20deg) + 
    1
    

    所以cos(α) = (T - 2)/2 = T/2 - 1,这意味着α = acos(T/2 - 1)

    【讨论】:

    • 是的,我什至不知道如何核实这一点。我完全要去,直到我看到罪恶。因为它打开了我的思路。当我看到罪恶。基地的呐喊王牌
    • @AndrewLuhring 太棒了。
    • 请注意,旋转矩阵只有在[x,y,z]向量被归一化时才适用,也就是说,只有当向量长度Math.sqrt(x*x + y*y + z*z)为1时。如果它没有被规范化,它可以很容易地转换成一个规范化的,通过将每个 xyz 按它们的长度进行潜水。
    • 您必须持有数学美术硕士学位。感谢这首诗,安娜!
    • @Andrew:别担心,罪会战胜我们许多人......叹息。
    【解决方案2】:

    语法:

    rotate3d(x, y, z, a)
    

    价值观:

    • x 是一个<number>,描述了表示旋转轴的向量的 x 坐标。
    • y 是一个<number>,描述了表示旋转轴的向量的 y 坐标。
    • z 是一个<number>,描述了表示旋转轴的向量的 z 坐标。
    • a 是一个<angle>,代表旋转的角度。正角表示顺时针旋转,负角表示逆时针旋转。

    点赞:

    .will-distort{
        transform:rotate3d(10, 10, 10, 45deg);
    }
    

    Fiddled here

    Caniuse it here

    More docs about it

    【讨论】:

    • 也许我很厚,但我认为他要求一种算法从链式变换到单个rotate3d,而不是rotate3d的定义。
    • 我想他想知道如何在 CSS 中将 rotateX(50deg) rotateY(20deg) rotateZ(15deg) 组合成简写 rotate3d()
    【解决方案3】:

    取决于你想要做什么,这个“黑客”可以帮助你。假设您正在制作动画,并且您想要在变换之后添加变换等等,并且您不希望 CSS 看起来像是在进行 100 次变换:

    这适用于铬: 1. 对元素应用任何你想要的变换。 2. 下次要添加变换时,将其添加到计算的变换中: “window.getComputedStyle(element).transform” - 但确保将新的变换放在左边。 3. 现在你的变换看起来像“rotateZ(30deg) matrix3d(......)。 4. 下次您想添加另一个变换时,重复该过程 - Chrome 总是将变换简化为 matrix3d 表示法。

    TL;DR- 应用你想要的任何变换,然后得到计算的 matrix3d 变换。

    这个技巧还可以让您快速(即,无需自己进行任何数学运算)创建一个功能,使对象相对于您的参考系向任何方向旋转。请参阅下面的示例:

    编辑:我也添加了 xyz 翻译。使用它,将对象放置在特定方向的特定 3d 位置将非常容易。或者......想象一个立方体会反弹并改变它的旋转轴,每次反弹取决于它的着陆方式!

    	var boxContainer = document.querySelector('.translator'),
    	    cube = document.getElementById('cube'),
    	    optionsContainer = document.getElementById('options');
    	var dims = ['x', 'y', 'z'];
    	var currentTransform;
    	var currentTranslate;
    	var init = function () {
    	    optionsContainer.querySelector('.xRotation input')
    	        .addEventListener('input', function (event) {
    	        if (currentTransform != 'none') {
    	            var newTransform = 'rotateX(' + (360 - event.target.value) + 'deg) ' + currentTransform;
    	        } else {
    	            var newTransform = 'rotateX(' + (360 - event.target.value) + 'deg)';
    	        }
    	        cube.style.transform = newTransform;
    	    }, false);
    
    	    optionsContainer.querySelector('.yRotation input')
    	        .addEventListener('input', function (event) {
    	        if (currentTransform != 'none') {
    	            var newTransform = 'rotateY(' + (360 - event.target.value) + 'deg) ' + currentTransform;
    	        } else {
    	            var newTransform = 'rotateY(' + (360 - event.target.value) + 'deg)';
    	        }
    	        cube.style.transform = newTransform;
    	    }, false);
    
    	    optionsContainer.querySelector('.zRotation input')
    	        .addEventListener('input', function (event) {
    
    	        if (currentTransform != 'none') {
    	            var newTransform = 'rotateZ(' + (360 - event.target.value) + 'deg) ' + currentTransform;
    	        } else {
    	            var newTransform = 'rotateZ(' + (360 - event.target.value) + 'deg)';
    	        }
    	        cube.style.transform = newTransform;
    	    }, false);
    
    	    optionsContainer.querySelector('.xTranslation input')
    	        .addEventListener('input', function (event) {
    
    	        if (currentTranslate != 'none') {
    	            var newTransform = 'translateX(' + (100 - event.target.value) + 'px) ' + currentTranslate;
    	        } else {
    	            var newTransform = 'translateX(' + (100 - event.target.value) + 'px)';
    	        }
    	        boxContainer.style.transform = newTransform;
    	    }, false);
    
    	    optionsContainer.querySelector('.yTranslation input')
    	        .addEventListener('input', function (event) {
    
    	        if (currentTranslate != 'none') {
    	            var newTransform = 'translateY(' + (100 - event.target.value) + 'px) ' + currentTranslate;
    	        } else {
    	            var newTransform = 'translateY(' + (100 - event.target.value) + 'px)';
    	        }
    	        boxContainer.style.transform = newTransform;
    	    }, false);
    	    optionsContainer.querySelector('.zTranslation input')
    	        .addEventListener('input', function (event) {
    
    	        if (currentTranslate != 'none') {
    	            var newTransform = 'translateZ(' + (500 - event.target.value) + 'px) ' + currentTranslate;
    	        } else {
    	            var newTransform = 'translateZ(' + (500 - event.target.value) + 'px)';
    	        }
    	        boxContainer.style.transform = newTransform;
    	    }, false);
    
    
    
    reset();
    
    	};
    
    	function reset() {
    	    currentTransform = window.getComputedStyle(cube).transform;
    	    currentTranslate = window.getComputedStyle(boxContainer).transform;
    	    optionsContainer.querySelector('.xRotation input').value = 360;
    	    optionsContainer.querySelector('.yRotation input').value = 360;
    	    optionsContainer.querySelector('.zRotation input').value = 360;
    	    optionsContainer.querySelector('.xTranslation input').value = 100;
    	    optionsContainer.querySelector('.yTranslation input').value = 100;
    	    optionsContainer.querySelector('.zTranslation input').value = 500;
    
    
    	}
    
    
    	window.addEventListener('DOMContentLoaded', init, false);
    	document.addEventListener('mouseup', reset, false);
    .translator
    {
    	height: 200px;
    	position: absolute;
    	width: 200px;
        transform-style: preserve-3d;
    }
    .threeSpace
    {
    	height: 200px;
    	moz-perspective: 1200px;
    	o-perspective: 1200px;
    	perspective: 200px;
    	position: absolute;
    	transform-origin: 50px 50px 100px;
    	webkit-perspective: 1200px;
    	width: 100px;
        perspective-origin: 100px 25px;
        transform-style: preserve-3d;
    }
    #pointer{
        position:relative;
        height:2px;
        width:2px;
        top:25px;
        left:100px;
        background:blue;
        z-index:9999;
        
    }
    
    
    
    #cube
    {
    	height: 100%;
    	moz-transform-origin: 90px 110px 0px;
    	moz-transform-style: preserve-3d;
    	o-transform-origin: 90px 110px 0px;
    	o-transform-style: preserve-3d;
    	position: absolute;
    	transform-origin: 90px 110px 0px;
    	transform-style: preserve-3d;
    	webkit-transform-origin: 90px 110px 0px;
    	webkit-transform-style: preserve-3d;
    	width: 100%;
    }
    #cube .midPoint{
        position:absolute;
        top:48px;
        left:48px;
        height:1px;
        width:1px;
        background:green;
    }
    
    #cube figure
    {
    	border: 2px solid black;
    	color: white;
    	display: block;
    	font-size: 60px;
    	font-weight: bold;
    	height: 96px;
    	line-height: 96px;
    	position: absolute;
    	text-align: center;
    	width: 96px;
        /* transform-style: preserve-3d; */
    }
    #cube .front
    {
    	background: hsl(0, 100%, 50%);
    }
    
    #cube .back
    {
    	background: hsl(60, 100%, 50%);
    }
    #cube .right
    {
    	background: hsl(120, 100%, 50%);
    }
    #cube .left
    {
    	background: hsl(180, 100%, 50%);
    }
    #cube .top
    {
    	background: hsl(240, 100%, 50%);
    }
    #cube .bottom
    {
    	background: hsl(300, 100%, 50%);
    }
    #cube .front
    {
    	moz-transform: translateZ(50px);
    	o-transform: translateZ(50px);
    	transform: translateZ(50px);
    	webkit-transform: translateZ(50px);
    }
    
    
    
    #cube .back
    {
    	moz-transform: rotateX(-180deg) translateZ(50px);
    	o-transform: rotateX(-180deg) translateZ(50px);
    	transform: rotateX(-180deg) translateZ(50px);
    	webkit-transform: rotateX(-180deg) translateZ(50px);
    }
    #cube .right
    {
    	moz-transform: rotateY(90deg) translateZ(50px);
    	o-transform: rotateY(90deg) translateZ(50px);
    	transform: rotateY(90deg) translateZ(50px);
    	webkit-transform: rotateY(90deg) translateZ(50px);
    }
    #cube .left
    {
    	moz-transform: rotateY(-90deg) translateZ(50px);
    	o-transform: rotateY(-90deg) translateZ(50px);
    	transform: rotateY(-90deg) translateZ(50px);
    	webkit-transform: rotateY(-90deg) translateZ(50px);
    }
    #cube .top
    {
    	moz-transform: rotateX(90deg) translateZ(50px);
    	o-transform: rotateX(90deg) translateZ(50px);
    	transform: rotateX(90deg) translateZ(50px);
    	webkit-transform: rotateX(90deg) translateZ(50px);
    }
    #cube .bottom
    {
    	moz-transform: rotateX(-90deg) translateZ(50px);
    	o-transform: rotateX(-90deg) translateZ(50px);
    	transform: rotateX(-90deg) translateZ(50px);
    	webkit-transform: rotateX(-90deg) translateZ(50px);
    }
    #options{
        position:absolute;
        width:80%;
        top:40%;
        
        
    }
    #options input
    {
    	width: 60%;
    }
    <body>
        
         <div class="threeSpace">
             <div id="pointer"></div>
        <div class="translator">
            <div id="cube">
                <figure class="front"><div class='midPoint'></div></figure>
                <figure class="back"></figure>
                <figure class="right"></figure>
                <figure class="left"></figure>
                <figure class="top"></figure>
                <figure class="bottom"></figure>
            </div>
        </div>
        </div>
        <section id="options">
            <p class="xRotation">
                <label>xRotation</label>
                <input type="range" min="0" max="720" value="360" data-units="deg" />
            </p>
            <p class="yRotation">
                <label>yRotation</label>
                <input type="range" min="0" max="720" value="360" data-units="deg" />
            </p>
            <p class="zRotation">
                <label>zRotation</label>
                <input type="range" min="0" max="720" value="360" data-units="deg" />
            </p>
            <p class="xTranslation">
                <label>xTranslation</label>
                <input type="range" min="0" max="200" value="100" data-units="deg" />
            </p>
            <p class="yTranslation">
                <label>yTranslation</label>
                <input type="range" min="0" max="200" value="100" data-units="deg" />
            </p>
            <p class="zTranslation">
                <label>zTranslation</label>
                <input type="range" min="0" max="1000" value="500" data-units="deg" />
            </p>
        </section>
    </body>

    【讨论】:

    • 这是有史以来最有用的帖子之一,谢谢您
    【解决方案4】:

    确切的值是rotate3d(133,32,58,58deg)

    查看fiddle(对于 chrome 和 Safari,使用 -webkit-transform)

    【讨论】:

    • 究竟是如何计算的
    • @Ana 我不知道,这就是为什么你的答案要好 10 倍 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多