2013-02-12 55 views
4

我已經使用了「梯形失真」技術描述here成功添加角度轉彎「硬封面的書與HTML5畫布頁。透視轉換

本質上發生的是一個圖像/畫布元素被定義爲源紋理。在每個渲染循環中,這被分割成定義寬度的段(1px是最好的質量),並且每個段的高度根據其在紋理的X軸上的位置而被縮放。

這將創建視角與給定的源圖像/紋理良好的錯覺可以看到下面:

enter image description here

也能正常工作的「精裝」翻頁,質地與任何一起包含的文字給人以深刻的視角印象。不過,我需要將相同類型的keystone應用於「軟」頁面轉彎。問題是,一個簡單的透視變換將不會以自己與曲線所定義的頁面上班可以看到下面:

enter image description here

目前的頁面質感在任何給定縮放到曲線的最大高度點在頁面轉動與設置頁面邊緣二次曲線路徑剪輯圖像/紋理。由於我使用各種標準畫布功能動態地繪製陰影和頁面線,因此頁面線(用二次曲線繪製)爲翻頁提供了一個自然的視角,因此這看起來可以接受。

但是(這是從另一個緩存帆布/圖像元素來源)文本本身看起來並不太好,在任何時候都剩下完全平坦。

我想什麼如上所述,但不知計算內的基於所述二次曲線(繪製爲ctx.quadraticCurveTo();)每1像素段路徑和垂直位置的高度做的是somewhow應用相同的切片/分段/縮放梯形技術帆布。

在我的例子形象,它實際上看起來並不太壞,但是當文本已接近頁面的頂部/底部的變形效果當然應該更大。不僅如此,我們還需要計算水平比例因子來壓縮最接近頁面摺疊的文字。

我不是真的有能力提供任何示例代碼我害怕。但基本上我們做的事情與我在上面提供的鏈接中描述關鍵碼的方式非常相似。並總結我需要能夠使用二次曲線座標/值來計算各段的比例係數在切片/渲染以下功能顯示:

function keystoneAndDisplayImage(ctx, img, x, y, pixelWidth, scalingFactor) { 
     var h = img.height, 
      w = img.width, 

      // The number of slices to draw. 
      numSlices = Math.abs(pixelWidth), 

      // The width of each source slice. 
      sliceWidth = w/numSlices, 

      // Whether to draw the slices in reverse order or not. 
      polarity = (pixelWidth > 0) ? 1 : -1, 

      // How much should we scale the width of the slice 
      // before drawing? 
      widthScale = Math.abs(pixelWidth)/w, 

      // How much should we scale the height of the slice 
      // before drawing? 
      heightScale = (1 - scalingFactor)/numSlices; 

      for(var n = 0; n < numSlices; n++) { 

      // Source: where to take the slice from. 
      var sx = sliceWidth * n, 
       sy = 0, 
       sWidth = sliceWidth, 
       sHeight = h; 

      // Destination: where to draw the slice to 
      // (the transformation happens here). 
      var dx = x + (sliceWidth * n * widthScale * polarity), 
       dy = y + ((h * heightScale * n)/2), 
       dWidth = sliceWidth * widthScale, 
       dHeight = h * (1 - (heightScale * n)); 

      ctx.drawImage(img, sx, sy, sWidth, sHeight, 
          dx, dy, dWidth, dHeight); 
     } 
    } 

...但我真的不知道在哪裏開始。任何幫助將不勝感激。

編輯:

轉念一想多一點什麼我希望能實現,我已經意識到,通過這種方法進行的3D紋理映射的完美表現可能有點過分的要求。因此,對於任何能夠根據html5畫布中定義的二次曲線簡單地改變每個段的高度尺度和y位置的答案,我都會很滿意。

這裏是一個更好的例子形象:

enter image description here

正如你可以看到較大的文本完全撐直,單個非梯形失真的圖像紋理,當我需要通過計算的1px的寬度段曲線因子及其y位置,以便它自然地跟隨翻頁。在這種情況下,如果沒有其他任何「黑客」或方法來實現半實際的透視效果,將會非常有幫助。

回答

4

我已經找到了解決辦法終於....

感謝這裏的夢幻般的答案:Center point on html quadratic curve

我有必要得到二次曲線上任何一點的y值的公式。

然後,這是一個簡單的例子,使用這個y值來計算對文本紋理高度的調整。我有一些調整來找到最好的二次曲線計算,但結果是非常棒的,即使是這樣。

見下圖:

enter image description here

它當前運行在約60fps的在Firefox/Chrome和周圍IE9/10 45FPS。我確信有優化的餘地,但不管我對結果感到滿意。顯然,它不會水平拉伸/擠壓與曲線一致的紋理,但這樣做會需要至少一次額外通過紋理,可能更多,這會削弱性能。

另一種選擇是訴諸實際的仿射3d紋理映射,但在我的嘗試中,我發現這種方法在性能和質量方面遠遠優越,同時顯然犧牲了一點準確性。

循環,這是我的主要渲染循環的翻頁內看起來是這樣的:

for (var i = 0; i < segments; i++) { 
      var sw = i >= segments - 1 ? segmentWidth : segmentWidth + 3; 
      var sourceLeft = texw * ((i * segmentWidth)/texw); 
      var sourceWidth = texw * (sw/texw) 
      var texleft = foldX - foldWidth + (i * segmentWidth);     
      var percent = ((i * segmentWidth)/foldWidth); 
      var curve = self.getQuadraticCurvePoint(foldX - foldWidth, 0, foldX, -verticalOutdent * 2, foldX, 0, percent) 
      var curvedheight = self.PAGE_HEIGHT + Math.abs(curve.y*2); 
      var y = -((curvedheight - self.PAGE_HEIGHT)/2); 

context.drawImage(self.flips[flip.index+1].leftcanvas, sourceLeft, 0, sourceWidth, texh, texleft, y, sw, curvedheight); 

    } 

與相關二次點功能是如下:

getQuadraticCurvePoint : function(startX, startY, cpX, cpY, endX, endY, position) { 
      return { 
       x: this.getQBezierValue(position, startX, cpX, endX), 
       y: this.getQBezierValue(position, startY, cpY, endY) 
      }; 
     }, 

和:

getQBezierValue : function(t, p1, p2, p3) { 
       var iT = 1 - t; 
       return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3; 
     },