2016-01-06 36 views
1

我正在處理基於畫布的動畫,並試圖在2D畫布中獲得3D效果。將視角添加到假3D動畫中

到目前爲止,事情進展順利!我有我的工作非常好「三角形的軌道線」:

var c = document.createElement('canvas'); 
 
c.width = c.height = 100; 
 
document.body.appendChild(c); 
 
var ctx = c.getContext("2d"); 
 

 
function Triangles() { 
 
    this.rotation = { 
 
    x: Math.random()*Math.PI*2, 
 
    y: Math.random()*Math.PI*2, 
 
    z: Math.random()*Math.PI*2 
 
    }; 
 
    /* Uncomment this for testing perspective... 
 
    this.rotation = { 
 
    x: Math.PI/2, 
 
    y: 0, 
 
    z: 0 
 
    }; 
 
    */ 
 
} 
 
Triangles.prototype.draw = function(t) { 
 
    this.rotation.z += t/1000; 
 
    var i, points; 
 
    for(i=0; i<15; i++) { 
 
    points = [ 
 
     this.computeRotation(Math.cos(0.25*i),-Math.sin(0.25*i),0), 
 
     this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),-0.1), 
 
     this.computeRotation(Math.cos(0.25*(i+1)),-Math.sin(0.25*(i+1)),0.1) 
 
    ]; 
 
    ctx.fillStyle = "black"; 
 
    ctx.beginPath(); 
 
    ctx.moveTo(50+40*points[0][0],50+40*points[0][1]); 
 
    ctx.lineTo(50+40*points[1][0],50+40*points[1][1]); 
 
    ctx.lineTo(50+40*points[2][0],50+40*points[2][1]); 
 
    ctx.closePath(); 
 
    ctx.fill(); 
 
    } 
 
}; 
 
Triangles.prototype.computeRotation = function(x,y,z) { 
 
    var rz, ry, rx; 
 
    rz = [ 
 
    Math.cos(this.rotation.z) * x - Math.sin(this.rotation.z) * y, 
 
    Math.sin(this.rotation.z) * x + Math.cos(this.rotation.z) * y, 
 
    z 
 
    ]; 
 
    ry = [ 
 
    Math.cos(this.rotation.y) * rz[0] + Math.sin(this.rotation.y) * rz[2], 
 
    rz[1], 
 
    -Math.sin(this.rotation.y) * rz[0] + Math.cos(this.rotation.y) * rz[2] 
 
    ]; 
 
    rx = [ 
 
    ry[0], 
 
    Math.cos(this.rotation.x) * ry[1] - Math.sin(this.rotation.x) * ry[2], 
 
    Math.sin(this.rotation.x) * ry[1] + Math.cos(this.rotation.x) * ry[2] 
 
    ]; 
 
    return rx; 
 
}; 
 

 
var tri = new Triangles(); 
 
requestAnimationFrame(function(start) { 
 
    function step(t) { 
 
    var delta = t-start; 
 
    ctx.clearRect(0,0,100,100) 
 
    tri.draw(delta); 
 
    start = t; 
 
    requestAnimationFrame(step); 
 
    } 
 
    step(start); 
 
});

正如你可以看到它使用旋轉矩陣其旋轉後計算點的位置,和我使用這個來繪製使用輸出x和y座標的三角形。

我想通過使用z座標和向該動畫添加透視來進一步深化,這會使三角形在前景中稍大一點,在背景中較小。但是,我不知道如何去做這件事。

我想這是一個數學問題比編程更多,對此感到抱歉!

回答

1

定義焦距來控制透視量。價值越大,透視的數量越少。然後

var fl = 200; // focal length; 
var px = 100; // point in 3D space 
var py = 200; 
var pz = 500; 

然後讓屏幕上的X,Y

var sx = (px * fl)/pz; 
var sy = (py * fl)/pz; 

,所以你需要把它中心到畫布將所得點是相對於教職員的中心。

sx += canvas.width/2; 
sy += canvas.height/2; 

這是一個觀點。

它假設被觀察的點位於視野的前方,並且遠離焦點的焦距。

+0

啊哈,所以看起來我應該與z成反比,與我自己的嘗試不成比例。這是有道理的,因爲當距離接近零時,感知的大小應該接近無窮大,並且當距離接近無窮大時,感知的大小應該接近於零。很高興知道這很簡單! –

+0

嗯,有趣的是,我的「壞」視角實際上最終在這個特定情況下產生了更好的視覺效果(在一個更完整的動畫中),所以我會堅持這個例子,但是很高興知道如何正確地做透視。謝謝! –

+0

奇怪的是,你在答案中給出的公式有一個線性結果,而隨着z變大,'x *(z + 2)/ 2'的結果變得更大,因此距離越遠的對象變得越大?或者你將x,y與'x *(z + 2)/ 2'的結果相除,那麼你就和我的相同,其中2是焦距,'(z + 2) '是沿着Z – Blindman67

0

我設法找出了一個基本的解決方案,但我相信有更好的,所以如果你有一個更完整的答案,隨時添加它!但現在......

由於座標系統已經根據各地直接在Z軸看(x,y)平面的觀點的起源,它實際上足以成正比z值只是乘以(x,y)座標。例如,x * (z+2)/2在這種情況下可以做得很好

雖然這肯定會有一個更合適的通用解決方案!