最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML canvas double buffering frame-rate issues - Stack Overflow

programmeradmin0浏览0评论

I have a full-screen canvas with 3 images drawn on it. When I resize the window, these images change position; however, it appears to be very glitchy, more so in Firefox.

I've been reading that double-buffering should resolve this issue, but I'm wondering how I would double buffer when the next position is unknown. That is to say, I cannot determine what should be buffered in the future, so how would this be possible?

Here is one source that seems doable, but I do not fully understand the concept Fedor is trying to explain.

Does HTML5/Canvas Support Double Buffering?

So far I have,

    $canvas = $('#myclouds')[0];
    $canvas_buffer = $('canvas')[0].insertAfter($canvas).css('visibility', 'hidden');
    context = $canvas.getContext('2d');
    context_buffer = $canvas_buffer.getContext('2d');
    clouds_arr = [$canvas, $canvas_buffer];

$(window).resize(function () {
    drawCanvas();
};

function initCanvas() {

    // Sources for cloud images
    var cloud1 = '/js/application/home/images/cloud1.png',
        cloud2 = '/js/application/home/images/cloud2.png',
        cloud3 = '/js/application/home/images/cloud3.png';

    // add clouds to be drawn
    // parameters are as follows:
    // image source, x, y, ratio, adjustment)
    addCloud(cloud1, null, 125, .03);
    addCloud(cloud2, null, 75, .15);
    addCloud(cloud3, null, 50, .55);
    addCloud(cloud1, null, 125, .97, 300);
    addCloud(cloud2, null, 70, .85, 300);
    addCloud(cloud3, null, 45, .5, 300);

    // Draw the canvas
    drawCanvas();
}

function drawCanvas() {
    // Reset
    $canvas.attr('height', $window.height()).attr('width', $window.width());

    // draw the clouds
    var l = clouds.length;
    for (var i = 0; i < l; i++) {
        clouds[i].x = ($window.width() * clouds[i].ratio) - clouds[i].offset;
        drawimage(context, clouds[i]);
    }
}

function Cloud() {
    this.x = 0;
    this.y = 0;
}

function addCloud(path, x, y, ratio, offset) {
    var c = new Cloud;
    c.x = x;
    c.y = y;
    c.path = path;
    c.ratio = ratio || 0;
    c.offset = offset || 0;
    clouds.push(c);
}

function drawimage(ctx, image) {
    var clouds_obj = new Image();
    clouds_obj.src = image.path;

    clouds_obj.onload = function() {
        ctx.drawImage(clouds_obj, image.x, image.y);
    };
}

I have a full-screen canvas with 3 images drawn on it. When I resize the window, these images change position; however, it appears to be very glitchy, more so in Firefox.

I've been reading that double-buffering should resolve this issue, but I'm wondering how I would double buffer when the next position is unknown. That is to say, I cannot determine what should be buffered in the future, so how would this be possible?

Here is one source that seems doable, but I do not fully understand the concept Fedor is trying to explain.

Does HTML5/Canvas Support Double Buffering?

So far I have,

    $canvas = $('#myclouds')[0];
    $canvas_buffer = $('canvas')[0].insertAfter($canvas).css('visibility', 'hidden');
    context = $canvas.getContext('2d');
    context_buffer = $canvas_buffer.getContext('2d');
    clouds_arr = [$canvas, $canvas_buffer];

$(window).resize(function () {
    drawCanvas();
};

function initCanvas() {

    // Sources for cloud images
    var cloud1 = '/js/application/home/images/cloud1.png',
        cloud2 = '/js/application/home/images/cloud2.png',
        cloud3 = '/js/application/home/images/cloud3.png';

    // add clouds to be drawn
    // parameters are as follows:
    // image source, x, y, ratio, adjustment)
    addCloud(cloud1, null, 125, .03);
    addCloud(cloud2, null, 75, .15);
    addCloud(cloud3, null, 50, .55);
    addCloud(cloud1, null, 125, .97, 300);
    addCloud(cloud2, null, 70, .85, 300);
    addCloud(cloud3, null, 45, .5, 300);

    // Draw the canvas
    drawCanvas();
}

function drawCanvas() {
    // Reset
    $canvas.attr('height', $window.height()).attr('width', $window.width());

    // draw the clouds
    var l = clouds.length;
    for (var i = 0; i < l; i++) {
        clouds[i].x = ($window.width() * clouds[i].ratio) - clouds[i].offset;
        drawimage(context, clouds[i]);
    }
}

function Cloud() {
    this.x = 0;
    this.y = 0;
}

function addCloud(path, x, y, ratio, offset) {
    var c = new Cloud;
    c.x = x;
    c.y = y;
    c.path = path;
    c.ratio = ratio || 0;
    c.offset = offset || 0;
    clouds.push(c);
}

function drawimage(ctx, image) {
    var clouds_obj = new Image();
    clouds_obj.src = image.path;

    clouds_obj.onload = function() {
        ctx.drawImage(clouds_obj, image.x, image.y);
    };
}
Share Improve this question edited May 23, 2017 at 12:26 CommunityBot 11 silver badge asked Dec 27, 2010 at 15:04 RyanRyan 22.3k7 gold badges26 silver badges28 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

I think maybe you are misunderstanding what double buffering is. Its a technique for smooth real-time rendering of graphics on a display.

The concept is you have two buffers. Only one is visible at any one time. When you go to draw the elements that make up a frame you draw them to the invisible buffer. In you case the clouds. Then you flip the buffers making the hidden one visible and the visible one hidden. Then on the next frame you draw to the now newly hidden buffer. Then at the end of drawing you flip back.

What this does is stop the user seeing partial rendering of elements before a frame is plete. On gaming systems this would also be synced up with the vertical refresh of the display to be really smooth and stop artefacts such as tearing to occur.

Looking at you code above you seem to have created the two canvas elements, but you're only using the first Context object. I assume this is inplete as no flipping is taking place.

Its also worth noting that the window resize event can fire continuously when dragging which can cause frantic rendering. I usually create a timer on the resize event to actually re-render. This way the re-render only happens once the user stops resizing for a few milliseconds.

Also, your draw routine is creating new Image objects every time which you don't need to do. You can use one image object and render to the canvas multiple times. This will speed up your render considerably.

Hope this helps.

发布评论

评论列表(0)

  1. 暂无评论