簡體   English   中英

調整畫布中圖像大小時的視覺閃爍

[英]Visual flicker when resizing image in canvas

我有一個簡單的JS動畫,它的圖像大小更改為小數點后3位,並且在圖像的某些部分上引起惱人的閃爍效果。 我發現某些圖像會產生這種效果,而其他圖像則不會。

我想知道動畫師如何解決此問題,以消除視覺效果,尤其是在Javascript中。

您將需要查看對JSFiddle的影響。 我在此處創建了動畫,以查看建築物上的視覺效果: http : //jsfiddle.net/qerwsn07/

function draw() {
    debug.innerHTML = 'Scale: '+scale;
    if(!dir){ 
        scale += 0.001; 
        if(scale > 1.09){ 
            dir = true;
        }
    } else if(dir) {
        scale -= 0.001;
        if(scale < 1){
            dir = false;   
        }
    }
    ctx.clearRect(0, 0, element.width, element.height);
    ctx.save()
    ctx.translate(element.width/2 - (camera.x / 500),element.height/2 - (camera.y / 500));      
    var x       =  - ((img.width * scale) / 2);
    var y       =  - ((img.height* scale) / 2);
    var width   = img.width * scale;
    var height  = img.height*scale;

    ctx.drawImage(img,x,y,img.width*scale,img.height*scale);
    ctx.restore();
    requestAnimationFrame(draw);
}
draw();

是否有消除或減少效果的方法?

盡管在我現在使用的計算機上看不到此錯誤,但我知道您的問題是什么。 有兩種減少它的方法。

首先,問題是由像素采樣引起的。 縮放圖像時,屏幕像素(設備顯示器上的物理像素)與圖像中的像素之間不再存在一對一的匹配。 縮小(縮小圖像)時,圖像中的像素多於顯示的像素。 放大(放大圖像)時,像素分布超過一個。

最基本的解決方案稱為最近像素采樣。 硬件計算縮放后的圖像上每個設備顯示像素的位置,然后選擇最接近圖像中該點的像素。

最常見的替代方法是雙線性插值。 在這種方法中,硬件在放大(使圖像放大)時使用最接近的4個像素,並通過在左右之間,然后在上下之間進行簡單線性插值並顯示平均顏色來計算顏色。 縮小時,將平均顯示像素以下的像素。 此方法可大大減少閃爍,但不能完全消除。

畫布使您可以在最接近的像素和硬件的平滑模式之間進行選擇。 用於平滑的內容取決於硬件配置。

若要使用平滑方法,請將2D上下文的imageSmoothingEnabled屬性設置為true

ctx.imageSmoothingEnabled = true;

要關閉它

ctx.imageSmoothingEnabled = false;

但是默認情況下,對畫布而言這是“ true”。 因此,我認為這不會立即解決您的問題。

如果您使用的是PC,則您的圖形驅動程序可能附帶有用於調整渲染性能的實用程序。 這些實用程序通常可以在Windows控制面板中找到。 根據硬件和使用的驅動程序,選項會有所不同。 通常,他們有一個性能面板,您可以在其中設置硬件以提高性能或質量。 性能設置將超過畫布的平滑選項,並且僅使用最近的像素(或設備最快的像素)。 如果已將其設置為最佳質量,請查看是否會改變閃爍。

此外,其中一些實用程序還允許您為每個應用程序設置質量設置。 因此,請檢查圖形設備是否具有該選項以及瀏覽器是否在列表中。 如果是這樣,則將其更改為最佳質量。

一些驅動程序允許您設置各個圖形選項。 因此,請外觀並將像素過濾更改為適合您的過濾。 您可能必須通過將像素過濾設置為應用程序設置來強制瀏覽器使用它。 (如果您使用的是Mac,請咨詢幫助)

如果一切設置正確,但是仍然閃爍,那么您將不得不使用其他方法來減少問題。

圖像模糊;

縮小時使用。 Mip映射的修改。 您需要在內存中創建圖像的第二個副本,並稍微模糊該圖像。 縮小時,渲染模糊的圖像。 您可能還希望在模糊的圖像和原始圖像之間進行較小的過渡,以防止由於縮放比例從放大切換到縮小而被注意到。 這可以通過使用ctx.globalAlpha將一個圖像淡入另一個圖像來完成。

Mip映射;

此方法涉及創建圖像的許多副本。 每個分辨率是前一個分辨率的一半。 您將必須使用良好的降采樣器(photoshop,Gimp,Paint.net),所有采樣器均具有降采樣選項。 或者,您也可以自己編寫一個代碼。

當顯示縮小的圖像時,您將繪制與縮放尺寸最接近的兩個圖像,並且兩者之間的淡入度取決於縮放與下采樣圖像側的接近程度。

無論您做什么,縮放時始終仍然會有些偽像。 每種方法都有其優點和缺點。 為了獲得最佳質量,請從分辨率為最大縮放像素的兩倍的圖像開始。 然后,在渲染時,您可以使用首選的采樣方法在代碼中對圖像進行采樣(JavaScript不能在2D上下文中完成該工作,您需要使用GPU和webGL)

編輯添加了瀏覽器平滑測試

我添加了一個小測試,以查看計算機上的圖形設備驅動程序是否覆蓋了平滑處理。 左側測試圖案已平滑,另一方已平滑。 如果兩者看起來相同,則說明瀏覽器無法控制平滑。

 // this code is not intended as an answer but as a way of checking // device smoothing is avalible or not. var canvas = document.getElementById("canV"); var ctx = canvas.getContext("2d"); // not commented as not a code answer. var currentSurface = ctx; var createImage = function (w, h) { var image = document.createElement("canvas"); image.width = w; image.height = h !== undefined?h:w; currentSurface = image.ctx = image.getContext("2d"); return image; } var img = createImage(256,256); var imageDat = img.ctx.getImageData(0,0,255,255); var dat = imageDat.data; var ind = 0; var lines = 2; var grow = 2; var black = 0 var white = 255 for(var y = 0; y < 256; y++){ for(var x = 0; x < 256; x++){ if(x%lines < lines-1){ dat[ind++] = black; dat[ind++] = black; dat[ind++] = black; }else{ dat[ind++] = white; dat[ind++] = white; dat[ind++] = white; } dat[ind++] = 255; } if(y%lines < lines-1){ black = 0; white = 255; }else{ black = 255; white = 0; } grow += 0.04; lines = Math.floor(grow); } img.ctx.putImageData(imageDat,0,0); var count = 1000; var tick = 0; function update(){ tick += 0.01; zoom = Math.sin(tick)*64; ctx.imageSmoothingEnabled = false; ctx.drawImage(img,64-zoom,64-zoom,zoom*2+128,zoom*2+128,0,0,200,200) ctx.imageSmoothingEnabled = true; ctx.drawImage(img,64-zoom,64-zoom,zoom*2+128,zoom*2+128,205,0,200,200) requestAnimationFrame(update) } update(); 
 #canV { width:405px; height:200px; } .smallText { font-size:small; } b { color:blue; } 
 <div class="smallText">Image on the left is <b>ctx.imageSmoothingEnabled = false;</b> and image on the right is <b>ctx.imageSmoothingEnabled = true;</b>. If they both look the same then the divice driver is overwriting the browser smoothing.</div> <canvas id="canV" width=405 height=200></canvas> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM