820 likes | 1.1k Views
Texture Maps. Jeff Parker Oct 2013. Objectives. Introduce Mapping Methods Texture Mapping Environment Mapping Bump Mapping Billboards Consider basic strategies Forward vs backward mapping Point sampling vs area averaging. Limits of Geometric Modeling.
E N D
Texture Maps Jeff Parker Oct 2013
Objectives Introduce Mapping Methods Texture Mapping Environment Mapping Bump Mapping Billboards Consider basic strategies Forward vs backward mapping Point sampling vs area averaging
Limits of Geometric Modeling We can create well lit spheres and cones, but geometry lacks visual interest Needed to spice things up
Commands ' ' – Toggle animation p – Toggle performance t – Toggle texture mapping m – Toggle Texture Mode f – Toggle filter Mode b – Toggle Background 1-4 – Change Background c - Toggle Culling * - Toggle starfield r – Print pixels/frame Arrow keys left/right change number of spheres Arrow keys up/down change level of details < and > change # of textures Nate Robins - 1997
Basic Stragegy Three steps to applying a texture Specify the texture Read or generate image Assign to texture Enable texturing Assign texture coordinates to vertices "Tack it up" Proper mapping function is left to application Specify texture parameters Wrapping, filtering, sampling
Images and geometry flow through separate pipelines Join at the rasterizer “Complex” textures do not affect geometric complexity geometry pipeline vertices rasterizer image pixel pipeline Texture Mapping and the OpenGL Pipeline
Specifying a Texture Image Define a texture image from an array of texels (texture elements) in CPU memory Define as any other pixel map Scanned image Generate by application code Enable texture mapping OpenGL supports 1-4 dimensional texture maps WebGL is limited to 1-2 dimensional texture maps
Mapping a Texture "Tacking it up" Based on parametric texture coordinates
Mapping a Texture vartexCoord = [ vec2(0, 0), vec2(0, 1), vec2(1, 1), vec2(1, 0) ]; pointsArray.push(vertices[a]); colorsArray.push(vertexColors[a]); texCoordsArray.push(texCoord[0]);
Applying Textures II • specify textures in texture objects • set texture filter (minification/magnification) • set texture function • set texture wrap mode • set optional perspective correction hint • bind texture object • enable texturing • supply texture coordinates for vertex coordinates can also be generated
In practice Let's walk through a simple example We create two textures As we image the object (a cube) we tie a texture coordinate to each vertex We enable texture mapping
textureCubev2.js // Create a checkerboard pattern var image1 = new Array() for (var i =0; i<texSize; i++) image1[i] = new Array(); for (var i =0; i<texSize; i++) for ( var j = 0; j < texSize; j++) image1[i][j] = new Float32Array(4); for (var i =0; i<texSize; i++) for (var j=0; j<texSize; j++) { var c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)); image1[i][j] = [c, c, c, 1]; }
textureCubev2.js // Create a checkerboard pattern using floats ... // Convert floats to ubytes for texture var image2 = new Uint8Array(4*texSize*texSize); for ( var i = 0; i < texSize; i++ ) for ( var j = 0; j < texSize; j++ ) for(var k =0; k<4; k++) image2[4*texSize*i+4*j+k] = 255*image1[i][j][k];
Texture Objects function configureTexture(image) { texture = gl.createTexture(); gl.activeTexture( gl.TEXTURE0 ); gl.bindTexture( gl.TEXTURE_2D, texture ); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, image); gl.generateMipmap( gl.TEXTURE_2D ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); }
Define Image as a Texture void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image ); target: type of texture, e.g. GL_TEXTURE_2D level: used for mipmapping (discussed later) internalformat, format, type: describe texels pixels: pointer to texel array
Converting A Texture Image OpenGL requires texture dimensions to be powers of 2 Even more limited in WebGL If dimensions of image are not powers of 2 gluScaleImage( format, w_in, h_in, type_in, *data_in, w_out, h_out, type_out, *data_out ); data_inis source image data_outis for destination image Image interpolated and filtered during scaling Check your system: GL_ARB_texture_non_power_of_two
In practice var cBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer); gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW ); var vColor = gl.getAttribLocation( program, "vColor" ); gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vColor); var vBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer); gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW); var vPosition = gl.getAttribLocation( program, "vPosition" ); gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vPosition); var tBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, tBuffer); gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoordsArray), gl.STATIC_DRAW ); var vTexCoord = gl.getAttribLocation( program, "vTexCoord"); gl.vertexAttribPointer(vTexCoord, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vTexCoord); configureTexture(image2); Passing in three attributes per vertex
Pin Textures function quad(a, b, c, d) { pointsArray.push(vertices[a]); colorsArray.push(vertexColors[a]); texCoordsArray.push(texCoord[0]); pointsArray.push(vertices[b]); colorsArray.push(vertexColors[a]); texCoordsArray.push(texCoord[1]); ...
t s GL_REPEAT wrapping GL_CLAMP wrapping texture Parameters: Wrapping Mode s, t: parameter space Clamping: if s, t > 1 use 1, if s, t < 0 use 0 Wrapping: use s, t modulo 1 texParameteri( target, type, mode ) texParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ) texParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT )
Texture Polygon Texture Polygon Magnification Minification Magnification and Minification More than one texel can cover a pixel (minification) or more than one pixel can cover a texel (magnification) Can use point sampling (nearest texel) or linear filtering ( 2 x 2 filter) to obtain texture values
Filter Modes Modes defined by calls to texParameteri( target, type, mode ) texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); Linear filtering requires a border of an extra texel for filtering at edges (border = 1)
Mipmapped Textures Mipmapping define prefiltered texture maps of decreasing resolutions Lessens interpolation errors for smaller objects Declare mipmap level of image when defining texture texImage2D( GL_TEXTURE_2D, 0,… ) Mipmap generate will build all the textures from image generateMipmap( gl.TEXTURE_2D ); Can also load your own…
Reading in a Texture OpenGL does not have any way to read images It is equally bad at JPG, TIFF, etc In the past I have spent time showing how to read .ppm files, a very simple graphics format.
PPM Files Portable Pixel Map (PPM) files are a simple, uncompressed format Can be read by xv and gimp (GNU Image Manipulation Program). I use GraphicConverter from Lemksoft Header holds Version String # One or more comments width height maxval Example P6 # Created by Paint Shop Pro 5 128 128 # Could have more comments between values 255 &@#$5%%... OpenGL does not support reading or writing graphical images (JPG, PNG, etc) The .ppm format is simple enough for us to create utility to read a file
ReadPPMFile Header /* Read a P6 PPM File */ int readPPMFile(GLubyte image[MAX][MAX][3], char *filename) { FILE* fp; int i, w, h, m; char head[70]; /* max line <= 70 in PPM (per spec). */ fp = fopen(filename, "rb"); if (!fp) { perror(filename); exit(1); } /* Check for the PPM Magic number, P6 */ fgets(head, 70, fp); if (strncmp(head, "P6", 2)) { fprintf(stderr, "%s: Not a raw PPM file\n", filename); exit(1); }
ReadPPMFile Header /* grab the three elements in the header (width, height, maxval). */ i = 0; while (i < 3) { fgets(head, 70, fp); if (head[0] == '#') /* skip comments. */ continue; if (i == 0) i += sscanf(head, "%d %d %d", &w, &h, &m); else if (i == 1) i += sscanf(head, "%d %d", &h, &m); else if (i == 2) i += sscanf(head, "%d", &m); } if ((w != MAX) || (h != MAX) || (m > 255))
The work in ReadPPMFile /* Read a P6 PPM File */ int readPPMFile(GLubyte img[MAX][MAX][3], char *fname) { ... fread(image, sizeof(unsigned char), w*h*3, fp); fclose(fp); return 1; } int main(int argc, char **argv) { ... if ((argc > 1) && (argv[1][0] != '-')) readPPMFile(image, argv[1]); ...
Where can I get Textures? Paul Bourke has a large collection of images at http://paulbourke.net/ http://paulbourke.net/texture_colour/leaf/
Texture Parameters OpenGL has a variety of parameters that determine how texture is applied We have seen wrapping parameters which determine what happens if s and t are outside the (0,1) range Filter modes allow us to use area averaging instead of point samples Mipmapping allows us to use textures at multiple resolutions Environment parameters determine how texture mapping interacts with shading
Texture Functions Controls how texture is applied glTexEnv{fi}[v](GL_TEXTURE_ENV, prop, param ) GL_TEXTURE_ENV_MODEmodes GL_MODULATE: modulates with computed shade GL_BLEND: blends with an environmental color GL_REPLACE: use only texture color GL(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); Set blend color withGL_TEXTURE_ENV_COLOR
Interpolation OpenGL uses interpolation to find proper texels from specified texture coordinates Can be distortions texture stretched over trapezoid showing effects of bilinear interpolation good selection of tex coordinates poor selection of tex coordinates
Aliasing Point sampling of the texture can lead to aliasing errors point samples in u,v (or x,y,z) space miss blue stripes point samples in texture space
Aliasing Point sampling of the texture can lead to aliasing errors The Nyquist limit point samples in u,v (or x,y,z) space miss blue stripes point samples in texture space
Nyquist Limit To reconstruct a signal, must sample at over twice the frequency
Area Averaging A better but slower option is to use area averaging Acts as a low pass filter pixel preimage Note that preimage of pixel is curved
Some Algorithms We could look for the nearest textel – GL_NEAREST We could average 4 – GL_LINEAR We could MipMap and take best fit – GL_NEAREST_MIPMAP_X Then apply NEAREST of LINEAR We could MipMap and take bracketing maps GL_LINEAR_MIPMAP_X Then apply NEAREST of LINEAR