开发者

How to load image, create texture, render, and save image asynchronously with WebGL?

I am attempting to write an application that uses very large textures. The idea is that you work on a scaled version of the texture in realtime modifying shaders and when finished the application would apply your changes to the original unscaled (large) texture. The problem is that profiling shows something like the following:

  • img.src = filename (500ms)
  • texImage2d(...) (1500ms)
  • bind/rendering (100ms)
  • readPixels (300ms)
  • Put into canvas (1000ms)
  • Save canvas to file (300ms)

Essentially this means the browser locks up for almost four seconds when saving the larger unscaled texture, with the user unable to do anything. Is it po开发者_如何学Gossible to do this asynchronously so that the browser stays responsive? It needs to all be done in javascript and client-side, as I'm using local files (HTML5 file/filesystem).

Web workers sounded like a good idea, but they are unable to access the DOM, so I can't use the browser's image loading and saving functionality, and they have no access to the WebGL context so they can't call texImage2d, which takes the most time.

Due to the size and number of images I cannot load them all into memory as textures when the page initially loads.

Is there anything that can be done to make this more responsive to the user? I'd like them to be able to continue working on the next image while the previous one renders.


The image loading should happen in the background, and you'll get no idea of progress for it, but you could use texSubImage2D to incrementally upload the texture. That will probably take a little bit longer overall but you should be able to give the user some feedback and respond to other events.

Also, you can just draw the webgl canvas directly into the canvas 2D. drawImage() takes images, video and canvas (2D or webgl) elements as arguments. That should happen almost instantaneously and save about 1300 ms.


This question is old but to others who find it here's some updated info

  • You can consider using OffscreenCanvas which has been shipping in Chrome since January 2019. Unfortunately it's not shipping anywhere else ATM

  • These 3 synchronous steps

    readPixels (300ms)
    Put into canvas (1000ms)
    Save canvas to file (300ms)
    

    can be turned into 1 asynchronous step

    gl.canvas.toBlob((blob) => {
      const url = URL.createObjectURL(blob);
      // url is now something you can give the user to download
    });
    
  • for rendering really large images (say 16k by 16k) you can render smaller portions and assemble them into a larger image.

    There's a library for that here: https://greggman.github.io/dekapng/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜