2017-09-22 5 views
0

私が取り組んでいるプロジェクトでHTML5キャンバス要素を使用しています。私が実際に見たことがあるかどうか疑問に思っている本当に奇妙なアーティファクトに遭遇しました。基本的に、この特定のシナリオ(これは私がこの動作を生成する唯一のケースです)では、私はアプリケーションでパン/ズームしていて、キャンバスの一部に非常に奇妙なレンダリング効果があることに気付きました。さらに、検査時に、私は非常に単純な例での効果を再現することができた:奇妙なHTML5キャンバスクローズパスレンダリングアーティファクト

この場合Strange HTML5 Canvas Rendering Artifact

、Iは(座標変化しない)パスを持っており、すべてのことから変化しています2番目のスクリーンショットへの最初のスクリーンショットは適用された変換マトリックスです(ごくわずかです)。

あなたはJSFiddleにアクセスすることができ、私はhttps://jsfiddle.net/ynsv66g8/でこれらのスクリーンショットを生成するために使用し、ここでは関係レンダリングコードです:

// Clear context 
context.setTransform(1, 0, 0, 1, 0, 0); 
context.fillStyle = "#000000"; 
context.fillRect(0, 0, 500, 500); 

if (showArtifact) { // This transformation causes the artifact 
    context.transform(0.42494658722537976, 0, 0, -0.42494658722537976, 243.95776291868646, 373.14630356628857); 
} else { // This transformation does not 
    context.transform(0.4175650109545749, 0, 0, -0.4175650109545749, 243.70987992043368, 371.06797574381795); 
} 

// Draw path 
context.lineWidth = 3.488963446543301; 
context.strokeStyle = 'red'; 
context.beginPath(); 
var p = path[0]; 
context.moveTo(p[0], p[1]); 
for (var i = 1; i < path.length; ++i) { 
    p = path[i]; 
    context.lineTo(p[0], p[1]); 
} 
context.closePath(); 
context.stroke(); 

それはあなたがcontext.closePath()への呼び出しを削除するためcanvas.closePath()への呼び出しに関連するように見えますとに置き換えます

p = path[0]; 
context.lineTo(p[0], p[1]); 

(したがって、手動で「閉じる」パス)すべてが付与された(正常に動作し、私は複数の上にパスを閉じ依存しているため、これは本当に私の特定の問題を解決しませんpply充てんルール)。

問題を解決するもう1つの興味深い変更は、path配列を逆にすることです(定義の直後にpath.reverse()への呼び出しを追加することによって)。

これはすべて、パスの特性に関連した何らかのブラウザレンダリングのバグを追加していると思われます。特にMacでは、Chrome(v61.0.3163.91)とFirefox(v55.0.3)ではなくSafari(v11)。私はこの問題(または類似のもの)を見つけるためにいくつかの広範な検索を行ってきましたが、それまでは空になっています。

これを引き起こしている可能性のあることについての洞察(または、ブラウザのバグによって引き起こされたと合意した場合、この問題を報告する適切な方法)は非常に高く評価されます。

+0

...とにかく...「ラウンド」や線幅を縮小するたlineJoinを設定することで解決し、私にはレンダラのバグが考えられそうです2つの線分の間の非常に小さい角度によって引き起こされるマイターアーチファクトであり、 'context'の' lineJoin'プロパティを '' round ''または' 'bevel" 'に設定することで排除することができます。デフォルトの 'lineJoin'は制限がある' 'miter ''です。 miterの制限は、miterLimitというプロパティで設定されますが、必ずしもアーティファクトを除去することはできません。ダブルス(64ビット浮動小数点JS番号)から浮動小数点(GPUが使用する32ビット)に変換するときに発生する丸め誤差のため、問題は悪化します。与えられた答えはあなたの問題を解決するでしょう。 – Blindman67

+0

@ blindman67ちょうど私のfirefoxで 'bevel'も失敗すると報告したいと思った。アルファブレンディングされたアーティファクトの三角形を見ると、私はこれが完全にシェイダーの問題であると確信しています。 –

+0

@ Blindman67 'lineJoin'を' 'bevel''に設定すると失敗することもありますが、' 'lineJoin''を' 'round''に設定すると問題が解決されるようです。 – Sanuden

答えて

3

問題があると思われます。つまり、セグメントのサイズ/方向に対して幅が大きすぎる場合、レンダラーは線を正しく結合できません。

これはパスクローズの影響を受けていないようです(オープンパスでアーティファクトを再現できます)。前者の場合は行結合が実行されないため、パスを手動で閉じることはclosePath()と同じではないことに注意してください。

私の知る限り、これだけで私の2セント:)