Texture Mapping and Texture Coordinates

 In today's lecture, I want to understand texture coordinates and the use of textures from within shaders. 

I want to discuss important technicalities about how to load and access texture files and slightly more complicated uses of textures. 

Afterwards, I wanted to discuss slightly more complicated use of textures (textures that are significantly more complicated will be the main focus next week).

Textures allow us to "wallpaper" triangles with images. It has more fine-grained control of the appearance than vertex colors alone.




First, we start from a "texture image" and consider a canvas-like coordinate system affixed to it, such that the maximum dimension is 1. 

Then we consider a triangle we want "textured with this image, and supply the texture coordinates for each vertex".


Then we consider a triangle we want "textured". These coordinates indicate where in the system the triangle draws. Lastly, the triangle inherits that same texture content when placed back into the 3D world.

Shaders need to be adjusted accordingly to accommodate textures. Texture coordinates are also another attribute that will be interpolated from vertices to fragments. The lines of code that do that are:

attribute vec22 vTexCoord;
varying vec2 fTexCoord;

and fTexCoord = vTexCoord after having stuff inside of the fragment shader.

Now samplers are textures that are seen from the shader's perspective as evidence. Samplers support "lookup"operations with float-valued coordinates that retrieve the underlying color from a texture image. 

This is interpolated like 

vec3 textColor = texture2D(texSampler1, fTexCoord).xyz;



From a hardware point of view, these samplers reside in GPU's texture memory, which reside in the graphics pipeline. 




Texture coordinates need to be treated as any other attribute, as far as initialization/buffering is concerned. Here is the coordinates for the texture 

// vertex texture coordinates
 var vertexTextureCoords = new Float32Array(
 [ 0, 0, 1, 0, 1, 1, 0, 1,
 1, 0, 1, 1, 0, 1, 0, 0,
 0, 1, 0, 0, 1, 0, 1, 1,
 0, 0, 1, 0, 1, 1, 0, 1,
 1, 1, 0, 1, 0, 0, 1, 0,
 1, 1, 0, 1, 0, 0, 1, 0 ]);
[...]
 // a buffer for textures
 var textureBuffer = gl.createBuffer();
 gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer);
 gl.bufferData(gl.ARRAY_BUFFER, vertexTextureCoords, gl.STATIC_DRAW);
 textureBuffer.itemSize = 2;
 textureBuffer.numItems = 24; 
 
Finally, texture images need to be loaded into JavaScript. This is also evidenced in the homework. 

[...]
 // Set up texture
 var texture1 = gl.createTexture();
 gl.activeTexture(gl.TEXTURE0);
 gl.bindTexture(gl.TEXTURE_2D, texture1);
 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
 var image1 = new Image();
 var texture2 = gl.createTexture();
 gl.activeTexture(gl.TEXTURE1);
 gl.bindTexture(gl.TEXTURE_2D, texture2);
 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
 var image2 = new Image();
 function initTextureThenDraw()
 {
 image1.onload = function() { loadTexture(image1,texture1); };
 image1.crossOrigin = "anonymous";
 image1.src = "https://farm6.staticflickr.com/5564/30725680942_e3bfe50e5e_b.jpg";
 image2.onload = function() { loadTexture(image2,texture2); };
 image2.crossOrigin = "anonymous";
 image2.src = "https://farm6.staticflickr.com/5726/30206830053_87e9530b48_b.jpg";
 window.setTimeout(draw,200);
 }
[...]

this code loads everything.

The first step is the create a Graphics Library "Texture object", indicating to the library that I am working with a specific texture mapping unit and associate the WebGL texture to the texture mapping unit (tmu).

GPUs have at least 8 Texture Mapping Units, if not more. 




Then load a placeholder image and create a JavaScript object to hold the actual image once we have a chance to do it.

Afterwards, a function is written to do the actual "loading" of the texture images. It is the function initTextureThenDraw(). Afterwards, I call it at the end of the setup function to invoke the commands. 

We should specify that images be downloaded from a URL, as follows: 

function initTextureThenDraw()
 {
 image1.onload = function() { loadTexture(image1,texture1); };
 image1.crossOrigin = "anonymous";
 image1.src = "https://farm6.staticflickr.com/5564/30725680942_e3bfe50e5e_b.jpg";
 image2.onload = function() { loadTexture(image2,texture2); };
 image2.crossOrigin = "anonymous";
 image2.src = "https://farm6.staticflickr.com/5726/30206830053_87e9530b48_b.jpg";
 window.setTimeout(draw,200);
 }

Afterwards, we can use MipMapping to avoid aliasing. 

If your shader or texture goes outside of the [0,1] range you have to control it using the following lines of code: 

// Optional ... if your shader & texture coordinates go outside the [0,1] range
 // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 


The final thing I need to do is to handle the textures during the draw() loop. This is the code respresented by the following lines: 

gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer);
 gl.vertexAttribPointer(shaderProgram.texcoordAttribute, textureBuffer.itemSize,
 gl.FLOAT, false, 0, 0);
 // Bind texture
 gl.activeTexture(gl.TEXTURE0);
 gl.bindTexture(gl.TEXTURE_2D, texture1);
 gl.activeTexture(gl.TEXTURE1);
 gl.bindTexture(gl.TEXTURE_2D, texture2); 





Comments

Popular Posts