2016-11-09 1 views
0

J'ai créé un programme pour générer des sprites de la planète. Je fais cela en créant un chemin circulaire, en exécutant ctx.clip() pour garder tous les calques suivants à l'intérieur du cercle, puis en dessinant une couche de texture noire et transparente, puis un rectangle de couleur aléatoire sur la toile, puis une ombre et une lueur sur le dessus de tout. Le problème est qu'une ligne de couleur apparaît également sous le cercle après l'écrêtage, et je ne sais pas pourquoi. J'ai besoin de cela enlevé.HTML5 Canvas ctx.clip() méthode utilisée sur un cercle laisse une ligne sous le cercle

Voici un violon. La dernière ligne définit le code à boucle chaque demi-seconde: https://jsfiddle.net/tzkwmzqu/4/

+0

Ne serait-il aider si je mis à jour avec une image de l'erreur? – Howzieky

+0

Oh mon dieu, j'ai raté le violon! Votre violon semble fonctionner pour l'instant, merci! Si ça casse brusquement comme mes anciens, je vais commenter – Howzieky

Répondre

2

Je ne suis pas sûr de comprendre votre problème, mais je suppose que vous parlez du problème anti-aliasing.

Actuellement, vous dessinez beaucoup sur votre zone découpée.
A chaque tirage, de nouveaux artefacts anti-aliasing viendront lisser le dernier dessin. À la fin, ce qui aurait dû être des pixels semi-transparents sont maintenant complètement opaques.
D'autre part, avec globalCompositeOperation comme 'destination-in', vous avez besoin d'un seul dessin pour effectuer la composition (~ écrêtage). Donc vous n'accumulez pas d'artefacts. Mais même si vous le faisiez, le GCO est mondial et, compte tenu de la transparence, l'accumulation serait moins importante.

var ctx1 = clip.getContext('2d'); 
 
var ctx2 = gCO.getContext('2d'); 
 
var ctx3 = gCO2.getContext('2d'); 
 

 
ctx1.beginPath(); 
 
ctx1.arc(150, 150, 150, 0, Math.PI*2) 
 
ctx1.clip(); 
 
// drawing multiple times on this clipped area will increase artifacts 
 
ctx1.fillRect(0,0,300, 150); 
 
ctx1.fillRect(0,0,300, 150); 
 
ctx1.fillRect(0,0,300, 150); 
 
ctx1.fillRect(0,0,300, 150); 
 

 
ctx2.beginPath(); 
 
ctx2.arc(150, 150, 150, 0, Math.PI*2) 
 
ctx2.fillRect(0,0,300, 150); 
 
ctx2.globalCompositeOperation = 'destination-in'; 
 
//With gCO you only draw once, but even if you did draw multiple times, there would still be less artifacts 
 
ctx2.fill(); 
 
ctx2.fill(); 
 
ctx2.fill(); 
 
ctx2.fill(); 
 
ctx2.globalCompositeOperation = 'source-over'; 
 

 
ctx3.beginPath(); 
 
ctx3.arc(150, 150, 150, 0, Math.PI*2) 
 
ctx3.fillRect(0,0,300, 150); 
 
ctx3.globalCompositeOperation = 'destination-in'; 
 
// only one drawing needed: 
 
ctx3.fill(); 
 
ctx3.globalCompositeOperation = 'source-over'; 
 

 
ctx1.fillStyle = ctx2.fillStyle = ctx3.fillStyle = "white"; 
 
ctx1.fillText('clipping', 120, 100); 
 
ctx2.fillText('compositing', 120, 100); 
 
ctx3.fillText('single compositing', 120, 100);
canvas{ 
 
    border: 1px solid; 
 
    }
<canvas id="clip"></canvas><canvas id="gCO"></canvas><canvas id="gCO2"></canvas>

Quelques notes sans rapport au sujet de votre code:

closePath ne marque pas la fin de votre déclaration de chemin, seul un nouveau beginPath() appel fait. ctx.fillStyle = 'transparent'; ctx.fill() ne fera rien. Seules les méthodes putImageData, clearRect et globalCompositeOperation + procédé de dessin peuvent produire des pixels transparents.

Voici donc tout ce qui précède dans un extrait:

/* Load images */ 
 
var texture = new Image(); 
 
texture.src = "http://i.imgur.com/0qMwa8p.png"; 
 
var shadow = new Image(); 
 
shadow.src = "http://i.imgur.com/pX3HVFY.png"; 
 

 
/* Create the canvas and context references */ 
 
var canvas = document.getElementById("game"); 
 
canvas.style.width = (canvas.width = 512) + "px"; 
 
canvas.style.height = (canvas.height = 512) + "px"; 
 
var ctx = canvas.getContext("2d"); 
 

 
/* render */ 
 
function render() { 
 
    /* Size of planets */ 
 
    var scale = Math.random() + 1 
 

 
    
 
    // We don't need to save/restore the canvas state now, 
 
    // simply remember to set the gCO back to 'source-over' 
 
    // here it done at the end of the function 
 
    
 
    /* Clear canvas for redraw */ 
 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 
    /* Place texture onto planet */ 
 
    ctx.globalAlpha = Math.random() * .5 + .5; 
 
    ctx.drawImage(texture, (Math.round(Math.random() * 256) - 128 * scale), (Math.round(Math.random() * 256) - 128 * scale), texture.naturalWidth * scale, texture.naturalHeight * scale) 
 

 
    /* Color Planet */ 
 
    ctx.globalAlpha = 1; 
 
    ctx.globalCompositeOperation = "multiply"; 
 
    var color = "hsl(" + Math.random() * 256 + ", 100%, 50%)" 
 
    ctx.fillStyle = color; 
 
    ctx.fillRect(0, 0, canvas.width, canvas.height) 
 

 
    /* Give planet its shine and shadow */ 
 
    ctx.globalCompositeOperation = "source-over"; 
 
    ctx.drawImage(shadow, Math.round(Math.random() * 200 - 128 * scale), Math.round(Math.random() * 200 - 128 * scale), shadow.naturalWidth * scale, shadow.naturalHeight * scale) 
 

 
    // instead of clipping, use gCO 
 
    ctx.globalCompositeOperation = 'destination-in'; 
 
    ctx.beginPath(); 
 
    ctx.arc(256, 256, 128 * scale, 0, 2 * Math.PI); 
 
    ctx.fill(); 
 
    // reset gCO 
 
    ctx.globalCompositeOperation = 'source-over'; 
 
} 
 
render() 
 
window.interval = setInterval(render, 500)
#game { 
 
    border: 1px solid black; 
 
    background-color: black; 
 
}
<canvas id="game"></canvas>