2016-04-27 67 views
0

我想實現這樣的事情:https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript4點圖像變換

我基本上要給出4分的時候在透視正確的方式變換的圖像。我對3D轉換的知識相當有限,所以我很難在使用PerspectiveCamera時正確定位圖像。

我不需要能夠拖動終點,我只是想輕鬆定義那種轉換。

我不想用three.js做這件事,而不使用css轉換的原因是我需要更高的瀏覽器支持和事後保存圖片的能力,所以我想用CanvasRenderer

+0

@Width threejs有一個使用2d函數的畫布渲染器,所以不需要webgl。如果我剛剛獲得了轉型權,那麼工作得很好。 – Nemo64

+0

@好吧,所以瀏覽器的支持不是重點,但是能夠保存圖像是重點。我需要能夠保存爲jpeg。我知道imagemagick支持這種轉換,但比我需要服務器往返+用戶放置在佔位符中的圖像的上傳。我可以做到這一點,但如果我可以在畫布上繪製它,然後使用FileSaver.js來保存它,它會更好。 – Nemo64

+0

如果你想要這個與透視攝像頭一起工作,看看http://jsdo.it/makc/2aVN但我想你根本不需要three.js – makc

回答

1

好的,經過大量的試用後,我發現了一種主要起作用的方式。

我用這個代碼從這個實現中進行了css轉換http://jsfiddle.net/dFrHS/1/並對其進行了更改,以便它返回一個Matrix4。

 function adj(m) { // Compute the adjugate of m 
      return [ 
       m[4]*m[8]-m[5]*m[7], m[2]*m[7]-m[1]*m[8], m[1]*m[5]-m[2]*m[4], 
       m[5]*m[6]-m[3]*m[8], m[0]*m[8]-m[2]*m[6], m[2]*m[3]-m[0]*m[5], 
       m[3]*m[7]-m[4]*m[6], m[1]*m[6]-m[0]*m[7], m[0]*m[4]-m[1]*m[3] 
      ]; 
     } 
     function multmm(a, b) { // multiply two matrices 
      var c = Array(9); 
      for (var i = 0; i != 3; ++i) { 
       for (var j = 0; j != 3; ++j) { 
        var cij = 0; 
        for (var k = 0; k != 3; ++k) { 
         cij += a[3*i + k]*b[3*k + j]; 
        } 
        c[3*i + j] = cij; 
       } 
      } 
      return c; 
     } 
     function multmv(m, v) { // multiply matrix and vector 
      return [ 
       m[0]*v[0] + m[1]*v[1] + m[2]*v[2], 
       m[3]*v[0] + m[4]*v[1] + m[5]*v[2], 
       m[6]*v[0] + m[7]*v[1] + m[8]*v[2] 
      ]; 
     } 
     function basisToPoints(x1, y1, x2, y2, x3, y3, x4, y4) { 
      var m = [ 
       x1, x2, x3, 
       y1, y2, y3, 
       1, 1, 1 
      ]; 
      var v = multmv(adj(m), [x4, y4, 1]); 
      return multmm(m, [ 
       v[0], 0, 0, 
       0, v[1], 0, 
       0, 0, v[2] 
      ]); 
     } 
     function general2DProjection(
       x1s, y1s, x1d, y1d, 
       x2s, y2s, x2d, y2d, 
       x3s, y3s, x3d, y3d, 
       x4s, y4s, x4d, y4d 
     ) { 
      var s = basisToPoints(x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s); 
      var d = basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d); 
      return multmm(d, adj(s)); 
     } 
     function project(m, x, y) { 
      var v = multmv(m, [x, y, 1]); 
      return [v[0]/v[2], v[1]/v[2]]; 
     } 
     function transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4) { 
      var t = general2DProjection 
      (0, 0, x1, y1, w, 0, x2, y2, 0, h, x3, y3, w, h, x4, y4); 
      for(i = 0; i != 9; ++i) t[i] = t[i]/t[8]; 
      var matrix = new THREE.Matrix4(); 
      matrix.fromArray([ 
       t[0], t[3], 0, t[6], 
       t[1], t[4], 0, t[7], 
       0 , 0 , 1, 0 , 
       t[2], t[5], 0, t[8] 
      ]); 
      return matrix; 
     } 

然後,我可以創造我想要這樣的轉換圖像:

 var imageWidth = 650; 
     var imageHeight = 925; 
     var texture = new THREE.TextureLoader().load("2b. neue Anzeige für BP.jpg"); 
     var material = new THREE.MeshBasicMaterial({map: texture, overdraw: 0.5}); 
     var planeGeometry = new THREE.PlaneGeometry(imageWidth, imageHeight, 10, 10); 
     var image = new THREE.Mesh(planeGeometry, material); 

     image.matrixAutoUpdate = false; 
     image.applyMatrix(new THREE.Matrix4().makeTranslation(imageWidth/2, imageHeight/2, 0)); 
     image.applyMatrix(transform2d(
       imageWidth, imageHeight, 
       -180, -373, 
       72, -242, 
       -395, -63, 
       -145, 35 
     )); 

這工作perfektly。竅門是image.applyMatrix(new THREE.Matrix4().makeTranslation(imageWidth/2, imageHeight/2, 0));以algorythm期望的方式移動轉換起點。這個例子確實包括了transform-origin: 0 0;,這在我的第一次嘗試中就不存在了。

相機只是一個簡單的THREE.OrthographicCamera所以沒有fov的問題。

所以現在這個解決方案的唯一問題:似乎使用投影Three.js將導致圖像不正確擬合。因此,按照我原來的計劃使用CanvasRenderer無法正常工作。

我可以嘗試調整圖像,以便它可能再次適合,但webgl渲染器現在與我很好。但由於我現在有一個畫布,我可以使用toBlob方法,並讓用戶保存圖像,而無需服務器往返,這是我想要的。