2017-09-22 3 views
0

내가 작업중인 HTML5 Canvas 요소를 사용하고 있는데, 많은 사람들이 렌더링하는 동안 누군가가 전에 본적이 있는지 궁금해하는 이상한 유물을 만났습니다. 기본적으로이 특정 시나리오 (이 동작을 생성하는 유일한 경우)에서 응용 프로그램을 패닝/확대/축소하고 캔버스 부분에 매우 기괴한 렌더링 효과가 있음을 알았습니다. 추가 검사시에, I는 매우 간단한 예에서 효과를 재현 할 수 있었다 :이상한 HTML5 Canvas closePath 렌더링 아티팩트

이때 Strange HTML5 Canvas Rendering Artifact

, I는 (좌표 변화하지 않음)의 경로를 가지며 모든은 변하고 두 번째 스크린 샷의 첫 번째 스크린 샷은 적용된 변형 행렬입니다 (매우 작은 양).

당신은 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 작성 규칙).

문제를 해결할 수있는 또 다른 흥미로운 변화는 path 배열을 뒤집어서 (즉, 정의 직후에 path.reverse()에 대한 호출을 추가하여)입니다.

이 모든 것들이 경로의 특성과 관련된 일종의 브라우저 렌더링 버그를 추가하는 것 같습니다. 특히 내 Mac에서는 Chrome (v61.0.3163.91)과 Firefox (v55.0.3)는 아니지만 Safari (v11)는 지원하지 않습니다. 나는이 문제 (또는 비슷한 것)를 찾으려고 광범위한 조사를 해왔지만 지금까지는 아무 것도 나오지 않았다.

무엇이 원인인지에 대한 통찰력 (또는 일부 브라우저 버그로 인해 합의가 이루어진 경우이 문제를보고하는 적절한 방법)에 큰 도움이됩니다.

+0

이를 ... 나에게 렌더링 버그를 보인다 lineJoin을 설정하여 해결 보인다 말할 수있는 은 두 선분 사이의 아주 작은 각에 의해 발생하는 마이 터 아티팩트이며'context'의'lineJoin' 속성을''round ''나''bevel''로 설정함으로써 제거 될 수 있습니다. 디폴트'lineJoin'은 제한이있는 "miter"입니다. miter 제한은 'miterLimit' 속성을 통해 설정됩니다.하지만 항상 인공물을 제거 할 수있는 것은 아닙니다. double (64 비트 부동 소수점 JS 번호)에서 부동 (GPU에서 사용하는 32 비트)로 변환 할 때 발생하는 반올림 오류로 인해 문제가 악화되었습니다. 주어진 대답은 당신의 문제를 해결하고 진드기가 마땅합니다. – Blindman67

+0

@ blindman67 그냥 'bevel'도 내 파이어 폭스에서 실패했다고보고하고 싶었습니다. 알파 블렌딩 된 인공물 삼각형을 보면, 이것은 전체적으로 마이 터링 로직의 버그가 아니라 쉐이더 문제라고 설득력을 얻었습니다. –

+0

@ Blindman67'lineJoin'을'bevel''로 설정할 때 실패하는 것을 볼 수 있습니다 만,'lineJoin'을''round''로 설정할 때 문제가 해결되는 것 같습니다. – Sanuden

답변

3

문제가있는 것 같습니다. 즉, 너비가 세그먼트 크기/방향에 비해 너무 큰 경우 렌더러가 행을 올바르게 결합하지 못합니다.

이것은 경로 닫힘에 영향을받지 않는 것 같습니다 (열린 경로로 이슈를 재현 할 수 있음). 앞의 경우에는 라인 조인이 수행되지 않으므로 경로를 수동으로 닫는 것은 closePath()와 동일하지 않습니다.

지금까지 내가, 그것은 '원형'또는 어쨌든 라인 폭 ...을 감소에, 그냥 내 두 센트 :