2011-12-27 55 views
17

可以說我們有一個500x500px的div尺寸,我們將它在x軸上通過css 45度旋轉,考慮webkit-perspective值爲1600px。計算用css3旋轉透視的div的絕對尺寸

如何計算顯示的梯形的絕對尺寸? (寬度,最大高度,角度)

我確實只弄清楚,計算的寬度,但不考慮立體的公式,因此該值不同的一些像素(的JavaScript):

var absoluteWidth = Math.cos(45 * (Math.PI/180)) * 500); 

編輯:這裏是關於-webkit視角函數的規格:

透視(<數>)

指定透視投影矩陣。該矩陣將觀察立方體映射到金字塔上,金字塔的底部離觀察者無限遠,並且其峯值表示觀察者的位置。可見的 區域是由視口的四個邊緣(瀏覽器窗口的 部分用於呈現瀏覽器的位置的 和距離 查看器的無窮遠處的點之間的網頁部分)所限定的區域。作爲函數的參數給出的深度表示z = 0平面距觀察者的距離。較低的值給出了一個更平坦的金字塔 ,因此一個更明顯的角度 的影響。該值以像素爲單位給出,因此1000的值會產生 中等數量的縮短值,而200的值會產生極端的數量。該矩陣通過以單位矩陣開始並且用值-1 /深度替換第3行第4列的值來計算。深度值 必須大於零,否則函數 無效。

關於「透視投影矩陣」這是我在維基百科上找到:http://en.wikipedia.org/wiki/3D_projection#Perspective_projection

+2

這是一個很好的問題 - 我從未很清楚透視值的工作原理。 – 2011-12-27 22:15:25

+2

我添加了來自W3C的透視函數的官方定義。仍然不知道如何計算。 – Elias 2011-12-28 11:06:43

+0

儘管已經完成了數學學位並瞭解了矩陣如何與線性代數相關,但我仍然不確定如何在3D圖形中使用它。如果您知道某些要求,則可以選擇垃圾選項,並以不同的角度測量寬度,然後將其放入電子表格中,然後手動調整曲線。無論如何可能會比完整的計算更快,並且會有足夠的準確性(對於像素來說,無論如何你都必須四捨五入到最接近的一個,所以小於0.5的誤差並不會產生影響) – 2011-12-28 12:05:44

回答

8

我與矩陣頭疼,所以我用的比例這樣做。

如果你看到從上面(因此看到它發生在兩個維度的旋轉),你看到它在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, sin*w/2) (cos*w/2, sin*w/2)三角形之間的比例(0, -p) (0, 0) (x, 0),你得到

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> 

請注意,如果你是沒有給出一個視角值,結果將是相等的,因爲它具有無限的價值。

+0

當然,這是爲支持-webkit-perspective屬性的瀏覽器而設計的,目前它是Safari上的瀏覽器或Mac上的瀏覽器 - 我猜。否則,只需使用p = infinity,這意味着用x替換calc()方法的返回表達式,因此丟棄z(當你無限遠時,它是無關緊要的)。 – djjeck 2011-12-29 15:19:03

+0

哇,真的很棒!它像一個魅力!你認爲你的算法對於計算旋轉的div的(顯示的)高度和角度也很有用嗎? – Elias 2011-12-30 22:27:10

+0

有了角度,你的意思是由投影多邊形組成的,對嗎?您可以使算法適應所有三個維度,而不僅僅是xz平面。您應該通過角度函數找到旋轉後矩形的四個座標,然後使用座標* = p /(p + z)獲取投影座標。然後你有多邊形,並可以做你想要的=) – djjeck 2011-12-30 22:39:13