假设我们有一个500x500px大小的div,我们将它在x轴上通过css旋转45度,考虑到webp-perspective值为1600px。
您如何计算显示的梯形的绝对尺寸? (宽度,最大高度,角度)
我只计算出一个计算宽度但不考虑透视的公式,因此值会有所不同(JavaScript):
var absoluteWidth = Math.cos(45 * (Math.PI / 180)) * 500);
编辑:这是关于-webkit-perspective函数的规范:
透视(小于数&GT)
指定透视投影矩阵。该矩阵将观察立方体映射到金字塔上,金字塔的底部距离金字塔无限远 观众及其峰值代表观众的位置。可见 area是由视口的四个边界限定的区域( 用于在其间呈现网页的浏览器窗口的一部分 观察者的位置和距离无穷远的点 观众)。作为函数的参数给出的深度表示 z = 0平面距观察者的距离。较低的值给出了 更扁平的金字塔,因此更明显的视角 影响。该值以像素为单位,因此值1000表示a 适量的透视和200的价值给了极端 量。通过以单位矩阵开始计算矩阵 用值-1 / depth替换第3行第4列的值。该 深度值必须大于零,否则函数为 无效。
关于“透视投影矩阵”,这是我在维基百科上发现的:http://en.wikipedia.org/wiki/3D_projection#Perspective_projection
答案 0 :(得分:8)
我对矩阵很头疼,所以我按比例做这个。
如果从上方看到div(因此看到它发生在两个维度中的旋转),您将其视为xz平面上的一个段,坐标为(-250, 0) (250, 0)
,或者一般(-w/2, 0) (w/2, 0)
在y轴上旋转后,坐标将变为,与您所说的相似
(-Math.cos(angle) * w/2, -Math.sin(angle) * w/2)
( Math.cos(angle) * w/2, Math.sin(angle) * w/2)
,逆时针旋转,原点位于div的中心,且是angle
弧度。
使用透视意味着这些坐标不会仅通过丢弃z来显示,而是首先根据它们与观察者的距离进行投影。
现在,投影平面是未旋转的东西所在的位置,z = 0.我从这个事实推断出这一点,即当未旋转的div投影时,它们保持相同的大小。
如果从z平面获取距离为p
(透视值)的点,则使用xz坐标(0,-p),并从此点绘制一条直线到旋转线段的顶点,直到当它穿过投影计划时,你得到的点是新的线段坐标,它产生div最终尺寸。
在三角形(0, -p) (0, 0) (x, 0)
和(0, -p) (0, sin*w/2) (cos*w/2, sin*w/2)
之间有一个比例,你得到那个
p : x = (p + sin*w/2) : cos*w/2
x = (p * cos*w/2) / (p + sin*w/2)
这通常意味着当您将点(x, y, z)
投影到计划上时
x * p / (p + z)
y * p / (p + z)
0
所以你的最终div坐标(在xz上,相对于div的中心)将是
(-Math.cos(angle) * w/2 * p / (p + -Math.sin(angle) * w/2), 0)
( Math.cos(angle) * w/2 * p / (p + Math.sin(angle) * w/2), 0)
你可以从中计算它的宽度以及它的位置 - 这是非常重要的,因为它最接近观察者的一半看起来会比另一半更大。
请查看以下测试以获取更多详细信息(当您太靠近对象时,它会失败,我不确定为什么,可能是某些变量溢出)
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
var WIDTH = 500;
var P = 300;
jQuery(function(){
function test(width, angle, p) {
$('body').
append($('<div id="info" />')).
append($('<div id="container" />').
css({
margin: '50px 0px',
border: '1px solid black',
width: width+'px',
'-webkit-perspective': p
}).
append($('<div id="real" />').addClass('the_div').css({ 'width': width+'px' }))).
append($('<div id="fake" />').addClass('the_div'));
setInterval(function() {
angle += 1;
$('#real').css({ '-webkit-transform': 'rotateY('+angle+'deg)' }).html(width);
// initial coordinates
var A = 0;
var B = width;
// translate the center (assuming -perspective-origin at 50%)
A -= width/2;
B -= width/2;
// new coordinates
A = calc(A, angle*Math.PI/180, p);
B = calc(B, angle*Math.PI/180, p);
// translate back
A += width/2;
B += width/2;
if(B < A) { var tmp = A; A = B; B = tmp; } // swap
var realwidth = B-A;
$('#fake').html(width+'<br/>'+A+', '+B).css({
'width': realwidth+'px',
'margin-left': A+'px'
});
// shows debug information
var debug = function(values) { return values.map(function(i){ return i+': '+eval(i); }).join('<br />'); }
$('#info').html($('<div />').html(debug(['width', 'p', 'angle', 'A', 'B', 'realwidth'])));
}, 40);
}
function calc(oldx, angle, p) {
var x = Math.cos(angle) * oldx;
var z = Math.sin(angle) * oldx;
return x * p / (p+z);
}
test(WIDTH, 0, P);
});
</script>
<style type="text/css">
* { margin: 0px; padding: 0px; }
body { padding: 40px 100px; }
.the_div { height: 100px; border: 2px solid black; background-color: rgba(255, 192, 0, 0.5); }
</style>
</head>
<body></body>
</html>
请注意,如果您未提供透视值,则结果将等于具有无限值。