CSS高级3D旋转控件

时间:2018-05-08 06:45:27

标签: javascript math 3d css-transforms rotational-matrices

我目前正在尝试找出一种方法来沿轴相对于用户旋转对象,而不是相对于对象。我正在使用Javascript(jQuery)和CSS转换旋转。

我已经构建了一个用于测试它的codepen。

var bX = 0; //bufferX (user scroll input)
var bY = 0; //bufferY (user scroll input)
var cX = 0; //currentX (effective X rotation)
var cY = 0; //currentY (effective Y rotation)

var bBX = 0; // same second rotation properties
var bBY = 0; 
var cBX = 0; 
var cBY = 0; 
var cBZ = 0; // currentZ (effective Z rotation)

var pi = 3.1416

// Fidget animation
function fidget() {
	if (!(bX + bY == 0)) {
		var dX = bX * 0.1; // how much we rotate this frame
		var dY = bY * 0.1; 
    
		cX = (cX + dX) % (2 * pi); // set rotation value
    cY = (cY + dY) % (2 * pi); 
    
		bX -= dX; // update buffer
		bY -= dY;
	}
	$('#one').css('transform', 'rotateX(' + cX + 'rad) rotateY(' + cY + 'rad)');
  window.requestAnimationFrame(fidget);
}

function fidgetB() {
	if (!(bBX + bBY == 0)) {
		var dBX = bBX * 0.1;
		cBX = (cBX + dBX) % (2 * pi);

		var rBY = Math.cos(cBX); //Y ratio
		var rBZ = Math.sin(cBX); //Z ratio

		var dBY = bBY * 0.1; // deltaY 
		var dBZ = bBY * 0.1;
		cBY = (cBY + rBY * dBY) % (2 * pi); // current
		cBZ = (cBZ - rBZ * dBZ) % (2 * pi);

		bBX -= dBX; // buffer
		bBY -= (dBY);
	}
	$('#two').css('transform', 'rotateX(' + cBX + 'rad) rotateY(' + cBY + 'rad) rotateZ(' + cBZ + 'rad)');
  window.requestAnimationFrame(fidgetB);
}

var init = function () {
  
  // Fidget
	requestAnimationFrame(fidget);
  requestAnimationFrame(fidgetB);
  
  // scroll detection script 
!function(window,document){var prefix="",_addEventListener,support;function _addWheelListener(elem,eventName,callback,useCapture){elem[_addEventListener](prefix+eventName,"wheel"==support?callback:function(originalEvent){!originalEvent&&(originalEvent=window.event);var event={originalEvent:originalEvent,target:originalEvent.target||originalEvent.srcElement,type:"wheel",deltaMode:"MozMousePixelScroll"==originalEvent.type?0:1,deltaX:0,deltaY:0,deltaZ:0,preventDefault:function(){originalEvent.preventDefault?originalEvent.preventDefault():originalEvent.returnValue=!1}};return"mousewheel"==support?(event.deltaY=-.025*originalEvent.wheelDelta,originalEvent.wheelDeltaX&&(event.deltaX=-.025*originalEvent.wheelDeltaX)):event.deltaY=originalEvent.deltaY||originalEvent.detail,callback(event)},useCapture||!1)}window.addEventListener?_addEventListener="addEventListener":(_addEventListener="attachEvent",prefix="on"),support="onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll",window.addWheelListener=function(elem,callback,useCapture){_addWheelListener(elem,support,callback,useCapture),"DOMMouseScroll"==support&&_addWheelListener(elem,"MozMousePixelScroll",callback,useCapture)}}(window,document);

	window.addWheelListener(window, function (e) {
		e.preventDefault();
		bY -= e.deltaX / window.innerWidth;
		bX += e.deltaY / window.innerWidth;
    bBY -= e.deltaX / window.innerWidth;
		bBX += e.deltaY / window.innerWidth;
	});
};

jQuery(document).ready(function ($) {
	init();
});
html, html * {
	margin: 0;
	padding: 0;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
  color:white;
  text-align: center;
  font-size: 6vmin;
  font-family: sans-serif;
}

#intro {
	position:absolute;
	width: 100%;
	height: 100%;
  -webkit-perspective: 200vmax;
	perspective: 200vmax;
	-webkit-perspective-origin: 50% 50%;
	perspective-origin: 50% 50%;
  transform-style: preserve-3d;
}

#one {
  left: 33%;
}

#two {
  left: 66%;
}

.square {
  background-color: black;
  width: 50vmin;
  height: 50vmin;
  line-height: 50vmin;
  top: 50%;
  margin-top: -25vmin;
  margin-left: -25vmin;
  
	transform-style: preserve-3d;
	
	position: absolute;
	-webkit-backface-visibility: visible;
	backface-visibility: visible;
	-webkit-transform-origin: 50% 37%;
	transform-origin: 50% 37%;
	/* -webkit-animation: rotate 25s linear infinite;
	animation: rotate 25s linear infinite; */
	pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="intro">
  <div id="one" class="square">Object</div>
  <div id="two" class="square">User</div>
</div>

[https://codepen.io/rsepierre/pen/XqVJKR][1]

要控制任何这些方块的旋转,请使用鼠标滚轮/触控板滚动(移动+滚轮以滚动Y轴。在整理时添加触摸支持)

  • 左方的旋转相对于对象:

如果你只向左滚动&lt; - &gt;对,没问题,它可行。同样可以向上&lt; - &gt;向下。

现在,如果您将项目平放(向下滚动90°&lt; - &gt;向上),然后尝试在另一个轴上旋转(左&lt; - &gt;右),它将自动旋转。这意味着对于用户来说,它看起来像Z轴旋转(就像时钟一样)。

  • 右方的旋转是我尝试进行旋转 相对于用户:

如果向左滚动&lt; - &gt;向右,没问题,它可以正常工作。同样可以向上&lt; - &gt;向下。

如果您再次将项目平放(向上滚动90°&lt; - &gt;向上),然后尝试在另一个轴上旋转(向左滚动&lt; - &gt;向右),它将相对于用户旋转。 该项目在“Z”轴上旋转,但从用户角度看,它将显示为Y轴旋转。

它实际上是有效的: 如果您只向上滚动&lt; - &gt;向下90度,从不介入。 当你向上&gt;向下滚动时,即使你得到89°角而不是90°角,它也会慢慢变得一团糟。

  • 我最好的解决方案:

我开始明白3D旋转不是可交换的(应用旋转的顺序会影响最终结果,这就是为什么只有Y轴旋转被拧紧,而X轴旋转从不这样做)。

一个简单的解决方法是将每个新用户输入添加到新的旋转中(rotateX(100)rotateY(5)rotateY(20)rotateX(105)...无限期。

但显然我这样做每秒60次,很快就会变成你曾经看过的那种恶心的CPU / GPU韭菜。

因此我相信我应该以某种方式在JS中完成场景背后的所有数学运算,并且只应用一个rotate3D(X,Y,Z,角度)css旋转。

事情是我对旋转矩阵背后的数学一无所知。 我发现这个转换器将3D旋转事物转换成其他3D旋转事物,但我想我需要了解什么是开始做任何数学运算。

任何有助于避免的帮助。

1 个答案:

答案 0 :(得分:0)

找到此stackoverflow帖子。这不是完全相同的情况,但实际上是同样的问题。

当我到达那里时会发布更新的代码。

同时:

Rotating CSS cube on fixed axes