Javascript 使用css3计算透视旋转的div的绝对尺寸

Javascript 使用css3计算透视旋转的div的绝对尺寸,javascript,math,css,perspective,Javascript,Math,Css,Perspective,假设我们有一个大小为500x500px的div,考虑到webkit透视值为1600px,我们通过css将其在x轴上旋转45度 如何计算所显示梯形的绝对尺寸?(宽度、最大高度、角度) 我只算出了一个计算宽度的公式,但没有考虑透视图,因此值与某些像素不同(JavaScript): 编辑:以下是关于-webkit透视功能的规范: 透视图() 指定透视投影矩阵。这个矩阵将一个观察立方体映射到一个金字塔上,该金字塔的底部离目标无限远 查看器,其峰值表示查看器的位置。可视的 区域是由视口的四条边(区域)限

假设我们有一个大小为500x500px的div,考虑到webkit透视值为1600px,我们通过css将其在x轴上旋转45度

如何计算所显示梯形的绝对尺寸?(宽度、最大高度、角度)

我只算出了一个计算宽度的公式,但没有考虑透视图,因此值与某些像素不同(JavaScript):


编辑:以下是关于-webkit透视功能的规范:

透视图()

指定透视投影矩阵。这个矩阵将一个观察立方体映射到一个金字塔上,该金字塔的底部离目标无限远 查看器,其峰值表示查看器的位置。可视的 区域是由视口的四条边(区域)限定的区域 用于在之间呈现网页的浏览器窗口的一部分 观察者的位置和距离目标无限远的点 观众)。作为函数参数给定的深度表示 z=0平面与查看器的距离。较低的值表示 金字塔更加扁平,因此透视效果更加明显 效果。该值以像素为单位,因此值1000表示 适度的缩短和200的值会产生极端的 数量该矩阵由一个单位矩阵开始计算,然后 将第3行第4列的值替换为-1/深度。这个 深度的值必须大于零,否则函数无效 无效


关于“透视投影矩阵”,这是我在维基百科上发现的:

我对矩阵很头疼,所以我用比例来做这个

如果您从上面看到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的中心,角度为弧度

使用透视意味着这些坐标不只是通过丢弃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的中心)将是

从中你可以计算出它的宽度和位置,这是非常重要的,因为它最靠近观察者的那一半会比另一半大

查看以下测试以了解更多细节(当您离对象太近时,它会失败,我不确定原因,可能是一些变量溢出)

var宽度=500;
var P=300;
jQuery(函数(){
功能测试(宽度、角度、p){
$('body')。
追加($('')。
追加($('')。
css({
保证金:“50px 0px”,
边框:“1px纯黑”,
宽度:宽度+px,
“-webkit透视图”:p
}).
追加($('').addClass('the_div').css({'width':width+'px'})))。
追加($('').addClass('u div');
setInterval(函数(){
角度+=1;
$('#real').css({'-webkit transform':'rotateY('+angle+'deg')).html(宽度);
//初始坐标
var A=0;
var B=宽度;
//平移中心(假设-透视原点为50%)
A-=宽度/2;
B-=宽度/2;
//新坐标
A=计算值(A,角度*Math.PI/180,p);
B=计算值(B,角度*Math.PI/180,p);
//翻译回
A+=宽度/2;
B+=宽度/2;
如果(B'+A+','+B).css({
“宽度”:realwidth+'px',
“左边距”:A+“px”
});
//显示调试信息
var debug=function(values){return values.map(function(i){return i+':'+eval(i);}).join('
');} $('#info').html($('').html(调试(['width',p',angle',A',B',realwidth']); }, 40); } 函数计算(oldx、角度、p){ var x=数学cos(角度)*oldx; var z=数学sin(角度)*oldx; 返回x*p/(p+z); } 试验(宽度,0,P); });
*{
边际:0px;
填充:0px;
}
身体{
填充:40px 100px;
}
.分区{
高度:100px;
边框:2件纯黑;
背景色:rgba(255,192,0,0.5);
}

这是一个好问题-我从来都不太清楚透视值是如何工作的。我添加了W3C中透视函数的官方定义。我仍然不知道如何计算。尽管我已经完成了数学学位,并且知道了一些矩阵与线性代数的关系,但我仍然不知道如何将其用于3d图形。如果你知道一些要求,你可以选择垃圾选项,用不同的视角测量宽度,将其放入电子表格,然后手动拟合曲线。无论如何都可能比完整计算更快,并且具有足够的精度(fo
x * p / (p + z)
y * p / (p + z)
0
(-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)