Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace Color With Texture in WebGL

In video games only color is applied to help speed up the loading process. After textures are ready, they replace the current colors. Is there a way to do this in WebGL? All the tutorials I've seen so far only show how to load in color or texture (not one after the other).

I'd guess that the buffer for each shape needs to be altered after its texture is fully loaded. I would assume this is keyed via an AJAX call that the texture is available, then applied via some kind of JavaScript function. Does WebGL have a built in way of doing this without a complicated image loading process?

like image 698
Ash Blue Avatar asked Nov 11 '11 06:11

Ash Blue


2 Answers

In most games that I've seen with the behavior you describe they'll typically start with either per-vertex coloring or a VERY low res texture and "blend up" to the full texture when it becomes available. That sort of smooth transition is tricky, but if all you want is a quick "pop" from one to the other it shouldn't be too much trouble.

The basic route I would take is to create a vertex buffer that has both texture coord and color information, as well as two different shaders. One shader will use the color information, the other will ignore it and use the texture instead. You would signal the mesh to start using the texture-based one as soon as the texture is ready.

As for detecting the image load, that's not hard at all and you don't even need AJAX for it:

var image = new Image();
image.addEventListener("load", function() {
    // Image is done loading, push to texture
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    // Set up any other state needed, such as switching the shader for the mesh
}, true);
image.src = src;

I'm not sure how much more help I can give on this subject without posting really large code blocks, but if you're still struggling I can detail some of the other parts.

like image 189
Toji Avatar answered Oct 23 '22 00:10

Toji


The approach I would take is as follows

loadTexture(url, initialColor) {

  var tex = gl.createTexture();

  // start with a single color.
  gl.bindTexture(gl.TEXTURE_2D, tex);
  var pixel = new Uint8Array(initialColor);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, pixel);

  // start loading the image
  var img = new Image();
  img.onload = function() {

    // when the image has loaded update the texture.          
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
    gl.generateMipmap(gl.TEXTURE_2D);
  }
  img.src = url;
  return tex;
}

// Load a tree texture, use brown until the texture loads.
var treeTexture = loadTexture("tree.png", [255, 200, 0, 255]);
// Load a water texture, use blue until it loads.  
var waterTexture = loadTexture("water.jpg", [0, 0, 255, 255]);

This is how most of the samples on http://webglsamples.googlecode.com work although they all default to blue textures.

You could easily extend that idea to use a solid color, the load a low-res texture, then when that finishes load a high-res texture.

Note: the code above assumes you are loading power-of-2 textures. If not you'll need to setup your texture parameters correctly.

like image 31
gman Avatar answered Oct 23 '22 01:10

gman