`‘ M
`-rI»""§L 3; L
`= a >s"**=:'
`rt-v*4=,,.§
`
`« r \
`E:
`
`'x..a-"'we
`
`__
`fig. 3‘
`’SK|P_‘7_FIOWS
`V‘
`
`“kl
`"_‘1"‘i
`
`‘
`
`""‘
`
`Figure 8-9
`
`*SKIP_ROWS, *SI(IP_PlXlJ.S, and *ROW_LENGTH Parameters
`
`Often a particular machine's hardware is optimized for moving pixel data
`to and from memory, ifthe data is saved in memory with a particular byte
`' alignment. For example, in a machine with 32-bit words, hardware can
`often retrieve data much faster if it’s initially aligned on a 32-bit‘ boundary,
`which typically has an address that is a multiple of 4. Likewise, 64-bit
`architectures might work better when the data is aligned to 8-byte
`boundaries. On some machines, however, byte alignment makes no
`difference.
`
`As an example, suppose your machine works better with pixel data aligned
`to a 4-byte boundary. Images are most efficiently saved by forcing the data
`for each row of the image to begin on a 4-byte boundary. If the image is 5
`pixels wide and each pixel consists of 1 byte each of red, green, and blue
`information, a row requires 5 x 3 = 15 bytes of data. Maximum display
`efficiency can be achieved if the first row, and each successive row, begins
`on a 4-byte boundary, so there is 1 byte of waste in the memory storage for
`each row. if your data is stored like this, set the *ALlGNMENT parameter
`appropriately (to 4, in this case).
`
`If *ALIGNMENT is set to 1, the next available byte is used. If it’s 2, a byte is
`skipped if necessary at the end of each row so that the first byte of the next
`row has an address that's a multiple of 2. In the case of bitmaps (or 1-bit
`images) where a single bit is saved for each pixel, the same byte alignment
`works, although you have to count individual bits. For example, if you’re
`saving a single bit per pixel, the row length is 75, and the alignment is 4,
`then each row requires 75/8, or 9 3/3 bytes. Since 12 is the smallest multiple
`of 4 that is bigger than 9 3/8, 12 bytes of memory are used for each row. If
`the alignment is 1, then 10 bytes are used for each row, as 9 3/8 is rounded
`
`
`
`0351
`
`Volkswagen 1021 - Part 2 of 2
`
`Imaging Pipeline
`
`301
`
`
`
`
`
`Parameter Name
`
`Type
`
`Initial Value
`
`Valid Range
`
`GL_INDEX_SHlF_l‘
`
`GI.-_INDEX_OFI~‘SET
`
`GL_RE-D_SCALE
`
`GLint
`
`GLint
`
`GLfloat
`
`GL_GREEN_SCALE
`
`GLfloat
`
`GL_BLUs_sc.ALE
`
`GLfloat
`
`GL_ALPHA_SCALE
`
`G1;float
`
`GL_DEl’TH_SCALE
`
`GLfloat
`
`GL_RED_BlA5
`
`GLfloat
`
`GL_GREEN_BLAS
`
`GLfloat ‘
`
`GL_BLUE_BIAS
`
`GLfloat
`
`GL_ALPl-lA_BlAS
`
`GLfloat
`
`GL_DEI»’I‘H#BIAS
`
`GLfloat
`
`0
`
`0
`
`1.0
`
`1.0
`
`1.0
`
`1.0
`
`1.0
`
`0
`
`0
`
`0
`
`0
`
`0
`
`(—oo, oo)
`
`(—oo, oo)
`
`‘
`
`(—oo, oo)
`
`(—c», an)
`
`(—m, on)
`
`.
`
`(—«=, no)
`
`(—o«», co)
`
`(—m, an)
`
`(—m, on)
`
`(—m, an)
`
`(—«n, so)
`
`(_oo, oo)
`
`Table 8-4
`
`glPixel'1‘ransfer*0 Parameters (continued)
`
`If the GL_MAP_COLOR or GL__MAP_STENCIL parameter is TRUE, then
`mapping is enabled. See the next subsection to learn how the mapping is
`done and how to change the contents of the maps. All the other parameters
`directly affect the pixel component values.
`
`V
`
`- A scale and bias can be applied to the red, green, blue, alpha, and depth
`components. For example, you may wish to scale red, green, and blue
`components that were read from the framebuffer before converting them to
`a luminance format in processor memory. Luminance is computed as the
`sum of the red, green, and blue components, so if you use the default value
`for GL_RED_SCALE, GL_GREEN_SCALE and GL__BLUE_SCALE, the
`components all contribute equally to the final intensity or luminance
`value. If you want to convert RGB to luminance, according to the NTSC
`standard, you set GL_RED__SCALE to .30,.GL_GR}:‘.EN_SCALE to .59, and
`GL_BLUE_SCALE to '.1 1.‘
`
`lndices (color and stencil) can also be transformed. In the case of indices a
`shift and offset are applied. This is useful if you need to control which
`portion of the color table is used during rendering.
`
`Imaging Pipeline
`
`303
`
`0353
`
`
`
`Pixel Mapping
`
`All the color components, color indices, and stencil indices can be modified
`by means of a table lookup before they are placed in screen memory. The
`‘ command for controlling this mapping is glPixelMap*0.
`
`void 'glP-ixe_lMa'p'{ui us f}v(GLenum map, GLint m.apsize{
`const T-'YPE *vaIues);
`
`Loads the pixel map-indicated by map‘ with;-mzipsize entriesg; whose values.
`are pointed to by values. Table 8.-5~lists the;I'nap names and values; the
`default sizes areal] 1 and the default vaiue_s_are.'_'al-l-.0. Each --ruap’s' size. must
`be a power of 2.
`_
`-
`
`Map Name
`
`Address
`
`Value
`
`GL_PIXEL_MAP_I_TO__l
`
`color index
`
`color index
`
`GL_PIXEL_MAP_S_TO_S
`
`stencil index
`
`stencil index
`
`GL*PIXEL_MAP_I_TO_R
`
`Color index
`
`GL_PlXEL_MAP_i_TO_G
`
`color index
`
`GL_PlXEL_MAP_I_T0_B
`
`color index
`
`GL_PIXEL_MAP_l_TO_A
`
`color index
`
`GL_PIXEL_MAP_R_TO_R
`
`GL_PlXEL_MAP_G_TO_G
`
`GL_PIXEL,_MAPHB_TO_B
`
`GL_PlXEL_MAP_A_TO_A
`
`R
`
`G
`
`B
`
`A
`
`R
`
`G
`
`B
`
`A
`
`R
`
`G
`
`B
`
`A
`
`Table B-5
`
`glPixelMap*0 Parameter Names and Values
`
`The maximum size of the maps is machine-dependent. You can find the
`sizes of the pixel maps supported on your machine with glGetlntegerv0.
`Use the query argument GL_MAX_PIXEL_MAP_TABLE to obtain the
`maximum size for all the pixel map tables, and use
`GL__PIXEL_MAP_*_TO_*_SiZE to obtain the current size of the specified
`map. The six maps whose address is a color index or stencil index must
`always be sized to an integral power of 2. The four RGBA maps can be any
`size from 1 through GL_MAX_PlXEL_MAP_TABLE.
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts. and Images
`
`0354
`
`
`
`To understand how a table works, consider a simple example. Suppose that
`you want to create a 256-entry table that maps color indices to color indices
`using GLHPlXEL_MAP_l_'l‘O_l. You create a table with an entry for each of
`the values between 0 and 255 and initialize the table with glPixelMap*0.
`Assume you're using the table for thresholding and want to map indices
`below 101 (indices 0 to 100) to 0, and all indices 101 and above to 255. In
`this case, your table consists of 101 0s and 155 2555. The pixel map is
`enabled using the routine glPixelTransfer*0 to set the parameter
`GL_MAP_COLOR _to TRUE. Once the pixel map is loaded and enabled,
`incoming color indices below 101 come out as 0, and incoming pixels
`between 101 and 255 are mapped to 255. If the incoming pixel is larger than
`255, it’s first masked by 255, throwing out all the bits above the eighth, and
`the resulting masked value is looked up in the table. If the incoming index
`is a floating-point value (say 88.145 85), it’s rounded to the nearest integer
`value (giving 88), and that number is looked up in the table (giving 0).
`
`Using pixel maps, you can also map stencil indices or convert color indices
`to RGB. (See “Reading and Drawing Pixel Rectangles” on page 309 for
`information about the conversion of indices.)
`
`Magnifying, Reducing, or Flipping an Image
`
`After the pixel—storage modes and pixel-transfer operations are applied,
`images and bitmaps are rasterized. Normally, each pixel in an image is
`written to a single pixel on the screen. However, you can arbitrarily
`magnify, reduce, or even flip (reflect) an image by using glPixelZoom().
`
`void glPixelZoom(GLfloa_t zoomx, GLfloat zoomfi);
`
`Sets the magnification or reduction factors for pixel-write operations
`-(glDrawPixels()~or:glCopyPixels0), in the x— and y-dimensions. By
`default, zoomx andzoomy are 1.0. If they.’re both 2.0, each image pixel is
`drawn to 4-screen pixels. Note that fractionalmagnification or reduction
`factors are allowed, as are negative factors. Negative zoom factors reflect
`the resulting image about the current raster position.
`
`During rasterization, each image pixel is treated as a zoom, >< zoom),
`rectangle, and fragments are generated for all the pixels whose centers lie
`within the rectangle. More specifically, let (x , y,_,,) be the current raster
`position. If a particular group of elements (in ex or components) is the nth
`in a row and belongs to the mth column, consider the region in window
`coordinates bounded by the rectangle with corners at
`
`Imaging Pipeline
`
`305
`
`
`
`0355
`
`
`
`' (x,,, + zoomx * n, y,p + zoom’, * m) and (x,_,, + z0om,,(n+1), y“, + zoomy(m+1))
`
`Any fragments whose centers lie inside this rectangle (or on its bottom or
`left boundaries) are produced in correspondence with this particular group
`of elements.
`-
`
`A negative zoom can be useful for flipping an image. OpenGL describes
`images from the bottom row of pixels to the top (and from left to right). If
`you have a “top to bottom” image, such as a frame of video, you may want
`to use glPixelZoom(1.0, -1.0) to make the image right side up for OpenGL.
`Be sure that you reposition the current raster position appropriately, if
`needed.
`
`Example 8-4 shows the use of glPixelZ.oom0. A checkerboard image is
`initially drawn in the lower-left corner of the window. Pressing a mouse
`button and moving the mouse uses gICopyPixels() to copy the lower-left
`corner of the window to the current cursor location. (If you copy the image
`onto itself, it looks wacky!) The Copied image is zoomed, but initially it is
`zoomed by the default value of 1 .0, so you won't notice. The '2' and ‘Z’ keys
`increase and decrease the zoom factors by 0.5. Any window damage causes
`the contents of the window to be redrawn. Pressing the ‘r’ key resets the
`image and the zoom factors.
`
`Example 8-4 Drawing, Copying, and Zooming Pixel Data: irnage.c
`
`#include <GL/g1.h>
`#inc1ude <GL/g1u.h>
`#inc1ude <GL/g1ut.h>
`#include <stdlib.h>
`#include <stdio.h>
`
`#define checklmagewidth 64
`#define checknnagei-ieight 64
`GLubyte checkImage[checklmagefleight][checkImagewidth][3]:
`
`static GLdoub1e zoomFactor = 1.0;
`
`static GLint height;
`
`void makeCheckImage(void]
`{
`
`int i. j, c;
`
`i++} {
`for (i = 0; i < checkImageHeight;
`for (j = 0;
`j < checkImageWidth;
`j++} {
`C = {(({i&0x8)== }“{(j&Dx8))==0)}*255;
`checkImageIi][j]IU] = (Gnubytel c;
`
`306
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images
`
`0356
`
`
`
`
`
`checkImage[i][j][1]
`checkImage[i] {j] [2]
`
`(GLubyte} c;
`(GLubyte} c;
`
`}
`
`void init(void)
`{
`
`glclearcolor (0.0, 0.0, 0.0, 0.0);
`g1ShadeMode1{GLHFLAT);
`makeCheckImage();
`g1PixelStorei(GL;UNPACK_ALIGNMENT, 1);
`
`}
`
`void display(void)
`{
`
`glClear{GL_COLOR_BUFFER_BIT};
`glRasterPos2i{0, 0];
`g1DrawPixe1s(checklmagewidth, checklmagefleight, GL_RGB.
`GL_UNSIGNED_BYTE,
`checklmage};
`
`g1F1ush[ )
`
`,-
`
`J
`
`void reshape(int w,
`{
`
`int h)
`
`glviewporttfl, O, {GLsizei} w,
`height = (GLint) h;
`g1MatrixMode {GL_PROJECTION} ,-
`g1LoadIdentityf):
`gluOrtho2D(0.0,
`(GLdouble} w,
`glMatrixMode(GL_MODELVIEW};
`glLoadIdentity();
`
`1
`
`void motionfint x,
`{
`
`int y)
`
`static GLint screeny;
`
`{GLsizei} h);
`
`0.0,
`
`(GLdoub1e} h}:
`
`screeny 2 height — {GLintJ y;
`g1RasterPos2i {x, screeny);
`g1Pixe1Zoom {zoomFactor, zoomFactor};
`glCopyPixels [0, 0, checklmagewidth,'checkImageHeight,
`. GL_COLOR);
`glPixe1Zoom (1.0, 1.0};
`g1F1ush (};
`
`
`
`0357
`
`Imaging Pipeline
`
`307
`
`
`
`
`
`...-__....-,....-....—..,.......u...,-M,»
`
`
`
`
`
`void keyboard(unsigned char key,
`{
`
`int x,
`
`int y]
`
`switch (key)
`case ‘r’:
`case ‘R’:
`
`{
`
`zoomFactor = 1.0;
`
`g1utPostRedisp1ay();
`printf {'zoomFactor reset to 1.0\n”}:
`break;
`case ‘z’:
`
`zoomFactor += 0.5:
`if (zoomFactor >= 3.0}
`zoomFactor = 3.0;
`
`printf (“zoomFactor is now %4.1f\n". zoomFactor);
`break;
`case ‘Z’:
`
`zoomFactor —= 0.5;
`if (zoomFactor <= 0.5}
`zoomFactor = 0.5;
`
`printf [“zoomFactor is now %4.1f\n", zoomFactor1;
`break;
`case 2?:
`
`exit[0];
`break;
`default:
`
`break;
`
`} i
`
`{
`
`nt main(int argc, char** argv)
`
`g1utInit{&argc, argv};
`g1utInitDisp1ayMode(GLUT_SINGLE I GLUT_RGB}:
`glutInitWindowSize{250, 250);
`glutInitWindowPosition(100, 100):
`g1utCreateWindow(argv[0]};
`initil;
`g1utDisp1ayFunc{disp1ay);
`g1utReshapeFunc{reshape);
`g1utKeyboardFunc{keyboard};
`glutMotionFunc{motion):
`glutmainboopi):
`return 0;
`
`303
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images
`
`0358
`
`
`
`
`
`Reading and Drawing Pixel Rectangles
`
`This section describes the reading and drawing processes in detail. The pixel
`conversions performed when going from framebuffer to memory (reading)
`are similar but not identical to the conversions performed when going in
`the opposite direction (drawing), as explained in the following sections.
`You may wish to skip this section the fi1st—t1'me through, especially if you
`do not plan to use the pixe1—transfer operations right away.
`
`The Pixel Rectangle Drawing Process
`
`Figure 8-10 and the following list describe the operation of drawing pixels
`into the frarnebuffer.
`
`Reading and Drawing Pixel Rectangies
`
`309
`
`0359
`
`
`
`byte shod int float
`Data Stream
`(index or component)
`
`index-II-index
`_
`looku
`0 i
`
`P
`
`RGBA
`2
`
`Pixel Data Out
`
`Index
`(slenr,-if, color index)
`
`Figure 8-10
`
`Drawing Pixels with glDrawPixels0
`
`3'10
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images
`
`0360
`
`
`
`If the pixels aren't indices (that is, the format isn’t GL_COLOR_INDEX
`or GL_STENCIL_INDEX), the first step is to convert the components to
`floating-point format if necessary. (See Table 4-1 on page 164 for the
`details of the conversion.)
`
`If the format is GL_LUl\/[INANCE or GL_LUlV[INANCE_ALPHA, the
`luminance element is converted into R, G, and B, by using the
`luminance value for each of the R, G, and B components. In
`GL__LUMlNANCE_ALPHA format, the alpha value becomes the A
`value. If GL_LUMlNANCE is specified, the A value is set_to 1.0.
`
`Each component (R, G, B, A, or depth) is multiplied by the appropriate
`scale, and the appropriate bias is added. For example, the R component
`is multiplied by the value corresponding to GL_RED_SCALE and added
`to the value corresponding to GL_RED_BIAS.
`
`if GL_MAP_COLOR is true, each of the R, G, B, and A components is
`clamped to the range {0.0,1.0], multiplied by an integer one less than
`the table size, truncated, and looked up in the table. (See "Tips for
`Improving Pixel Drawing Rates” on page 314 for more details.)
`
`Next, the R, G, B, and A components are clamped to [0.0,1.0], if they
`weren’t already, and converted to fixed—point with as many hits to the
`left of the binary point as there are in the corresponding framebuffer
`component.
`
`If you're working with index values (stencil or color indices), then
`the values are first converted to fixed-point (if they were initially
`floating-point numbers) with some unspecified bits to the right of the
`binary point. Indices that were initially fixed-point remain so, and
`any bits to the right of the binary point are set to zero.
`
`The resulting index value is then shifted right or left by the absolute
`value of GL_INDEX_SHIF'I‘ hits; the value is shifted left if
`GL_INDEX_SHlFT > 0 and right otherwise. Finally, GL_INDEX__OFFSET
`is added to the index.
`
`The next step with indices depends on whether you’re using RGBA
`mode or color-index mode. In RGBA mode, a color index is
`converted to RGBA using the color components specified by
`GL-_PIXEL_MAP_l_T0_R, GL_PlXEL_MAP_I_'I‘0__G,
`‘
`GL_PlXEL__MAP_l_TO__B, and GL__PIXEL_MAP__I_TO__A. (See “Pixel
`Mapping” on page 304 for details.) Otherwise, if GL_MAP_COLOR
`is GL_TRUE, a color index is looked up through the table
`GL_PIXEL‘_MAP_l_TO_I. (if GL__MAP_COLOR is GL_FALSE, the index
`is unchanged.) If the image is made up of stencil indices rather than
`
`Reading and Drawing Pixel Rectangles
`
`311
`
`0361
`
`
`
`
`
`
`
`color indices, and if GL_MAP_STENCIL is GL_TRUE, the index is
`looked up in the table corresponding to GL_PlXEL_MAP_S__’I‘O_S. If
`GL_MAP_STENCIL is FALSE, the stencil index is unchanged.
`
`8. Finally, if the indices haven't been converted to RGBA, the indices are
`then masked to the number of bits of either the color—index or stencil
`
`buffer, whichever is appropriate.
`
`The Pixel Rectangle Reading Process
`
`Many of the conversions done during the pixel rectangle drawing process
`are also done during the pixel rectangle reading process. The pixel reading
`process is shown in Figure 8-11 and described in the following list.
`
`312
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images
`
`0362
`
`
`
`Pixels from Framebufier
`
`Index
`(stencil. oolor index}
`
`FIGBA
`2
`
`~
`
`.0
`
`'
`
`index-bindex
`lookup
`
`byte short int float
`Data Stream
`(index or component)
`to memory
`
`Figute 8-11
`
`Reading Pixels with glReadPixels()
`
`1.
`
`If the pixels to be read aren’t indices (that is, the format isn’t
`GL_COLOR_INDEX or GL_STENCIL_INDEX), the components are
`mapped to [0.0,1.0]—that is, in exactly the opposite way that they are
`when written.
`
`2. Next, the scales and biases are applied to each component. If
`GL_MAP_COLOR is GL_TRUE, they’re mapped and again clamped to
`{0.0,1.0]. If luminance is desired instead of RGB, the R, G, and B
`components are added (L = R + G + B).
`
`
`
`0363
`
`Reading and Drawing Pixel Reclangles
`
`313
`
`
`
`
`
`.
`
`-_ --—¢-
`
`3.
`
`4.
`
`5.
`
`If the pixels are indices (color or stencil), they’re shifted, offset, and, if
`GL*_MAP_COLOR is GL_TRUE, also mapped.
`
`If the storage format is either GL_COLOR_lNDEX or
`GL__STENClL_lNDEX, the pixel indices are masked to the number of
`bits of the storage type (1, 8, 16, or 32) and packed into memory as
`previously described.
`
`If the storage format is one of the component kind (such as luminance
`or RGB), the pixels are always mapped by the index—to-RGBA_maps.
`Then, they're treated as though they had been RGBA pixels in the first
`place (including potential conversion to luminance).
`
`6. Finally, for both index and component data, the results are packed
`into memory according to the GL_PACI<* modes set with
`glPixelStore*().
`
`The scaling, bias, shift, and offset values are the same as those used when
`drawing pixels, so if you’re both reading and drawing pixels, be sure to reset
`these components to the appropriate values before doing a read or a draw.
`Similarly, the various maps must be properly reset if you intend to use maps
`for both reading and drawing.
`
`Note: It might seem that luminance is handled incorrectly in both the
`reading and drawing operations. For example, luminance is not
`usually equally dependent on the R, G, and B components as it may
`be assumed from both Figure 8-10 and Figure 8-11. If you wanted
`your luminance to be calculated such that the R component
`contributed 30 percent, the G 59 percent, and the B 11 percent, you
`can set GL_RED_SCALE to .30, GL_RED_BIAS to 0.0, and so on. The
`computed L is then .3OR + .59G + .11B.
`
`Tips for Improving Pixel Drawing Rates
`
`As you can see, OpenGI. has a rich set of features for reading, drawing and
`manipulating pixel data. Although these features are often very useful, they
`can also decrease performance. Here are some tips for improving pixel draw
`rates.
`
`0
`
`For best performance, set all .pixel—transfer parameters to their default
`values, and set pixel zoom to (1.0,1.0).
`
`314
`
`Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images
`
`0364
`
`
`
`A series of fragment operations is applied to pixels as they are drawn
`into the frarnebuffer. (See “Testing and Operating on_Fragments” on
`page 382.) For optimum performance disable all fragment operations.
`
`While performing pixel operations, disable other costly states, such as
`texturing and lighting.
`
`If you use an image format and type that matches the framebuffer, you
`can reduce the amount of work that the OpenGL implementation has
`to do. For example, if you are writing images to an RGB frarnebuffer
`with 8 bits per component, cal] glDrawPixels() with format set to RGB
`and type set to UNSIGNED_BYTE.
`
`For some implementations, unsigned image formats are faster to use
`than signed image formats.
`
`It is usually faster to draw a large pixel rectangle than to draw several
`small ones, since the cost of transferring the pixel data can be
`amortized over many pixels.
`
`If possible, reduce the amount of data that needs to be copied by using
`small data types (for example, use GL_UNSlGNED_BYTE) and fewer
`components (for example, use format GLWLUMINANCLALPHA).
`
`Pixel-transfer operations, including pixel mapping and values for scale,
`bias, offset, and shift other than the defaults, may decrease
`performance.
`
`Tips for Improving Pixel Drawing Rates
`
`315
`
`0365
`
`
`
`Chapter 9
`
`Texture Mapping
`
`
`
`Chapter Objectives
`
`After reading this chapter, you’ll be able to do the following:
`
`Understand what texture mapping can add to your scene
`
`Specify a texture image
`
`Control how a texture image is filtered as it's applied to a fragment
`
`Create and manage texture images in texture objects and, if available,
`control a high-performance working set of those texture objects
`
`Specify how the color values in the image combine with those of the
`fragment to which it’s being applied
`
`Supply texture coordinates to indicate how the texture image should
`be aligned to the objects in your scene
`
`Use automatic texture coordinate generation to produce effects like
`contour maps and environment maps
`
`31?
`
`0366
`
`
`
`So far, every geometric primitive has been drawn as either a solid color or
`smoothly shaded between the colors at its vertices—that is,_tl1ey’ve been
`drawn without texture mapping. If you want to draw a large brick wall
`without texture mapping, for example, each brick must be drawn as a
`separate polygon. Without texturing, a large flat wall-—which is really a
`single rectangle—might require thousands of individual bricks, and even
`then the bricks may appear too smooth and regular to be realistic.
`
`Texture mapping allows you to glue an image of a brick wall (obtained,
`perhaps, by scanning in a photograph of a real wall) to a polygon and to
`draw the entire wall as a single polygon. Texture mapping ensures that all
`the right things happen as the polygon is transformed and rendered. For
`example, when the wall is viewed in perspective, the bricks may appear
`smaller as the wall gets farther from the viewpoint. Other uses for texture
`mapping include depicting vegetation on large polygons representing the
`ground in flight simulation; wallpaper patterns; and textures that make
`polygons look like natural substances such as marble, wood, or cloth. The
`possibilities are endless. Although it’s most natural to think of applying
`textures to polygons, textures can be applied to all prirnitives—points, lines,
`polygons, bitmaps, and images. Plates 6, 8, 18-21, 24-27, and 29-31 all
`demonstrate the use of textures.
`
`Because there are so many possibilities, texture mapping is a fairly large,
`complex subject, and you must make several programming choices when
`using it. For instance, you can map textures to surfaces made of a set of
`polygons or to curved surfaces, and you can repeat a texture in one or both
`directions to cover the surface. A texture can even be one—di1nensional. In
`
`addition, you can automatically map a texture onto an object in such a way
`that the texture indicates contours or other properties of the item being
`viewed. Shiny objects can be textured so that they appear to be in the center
`of a room or other environment, reflecting the surroundings off their
`surfaces. Finally, a texture can be applied to a surface in different ways. It
`can be painted on directly (like a decal placed on a surface), used to
`modulate the color the surface would have been painted otherwise, or used
`to blend a texture color with the surface color. If this is your first exposure
`to texture mapping, you might find that the discussion in this chapter
`moves fairly quickly. As an additional reference, you might look at the
`chapter on texture mapping in Fundamentals 0fThree-Dimensional Computer
`Graphics by Alan Watt (Reading, MA: Addison-Wesley Publishing
`Company, 1990).
`
`Textures are simply rectangular arrays of data—for example, color data,
`luminance data, or color and alpha data. The individual values in a texture
`array are often called texels. What makes texture mapping tricky is that a
`
`318
`
`Chapter 9: Texture Mapping
`
`0367
`
`
`
`rectangular texture can be mapped to nonrectangular regions, and this
`must be done in a reasonable way.
`
`Figure 9-1 illustrates the texture-mapping process. The left side of the figure
`represents the entire texture, and the black outline represents a
`quadrilateral shape whose corners are mapped to those spots on the texture.
`When the quadrilateral is displayed on the screen, it might be distorted by
`applying various transforrnations—rotations, translations, scaling, and
`proiections. The right side of the figure shows how the texture-mapped
`quadrilateral might appear on your screen after these transformations.
`(Note that this quadrilateral is concave and might not be rendered correctly
`by OpenGL without prior tessellation. See Chapter 1 1 for more information
`about tessellating polygons.)
`
`
`
`Figure 9-1
`
`Texture-Mapping Process
`
`Notice how the texture is distorted to match the distortion of the
`
`quadrilateral. In this case, it’s stretched in the x direction and compressed
`in the y direction; there’s a bit of rotation and shearing going on as well.
`Depending on the texture size, the quadrilateral’s distortion, and "the size of
`the screen image, some of the texels might be mapped to more than one
`fragment, and some fragments might be covered by multiple texels. Since
`the texture is made up of discrete texels (in this case, 256x256 of them),
`filtering operations must be performed to map texels to fragments. For
`example, if many texels correspond to a fragment, they’re averaged down
`to fit; if texel boundaries fall across fragment boundaries, a weighted
`average of the appiicable texels is performed. Because of these calculations,
`texturing is computationally expensive, which is why many specialized
`graphics systems include hardware support for texture mapping.
`
`An application may establish texture objects, with each texture object
`representing a single texture (and possible associated mipmaps). Some
`
`319
`
`
`
`0368
`
`
`
`___ —_:;1¢‘_t
`
`implementations of OpenGL can support a special working set of texture
`objects that have better performance than texture objects outside the
`working set. These high~performance texture objects are said to be resident
`and may have special hardware and/or software acceleration available. You
`may use OpenGL to create and delete texture objects and to determine
`which textures constitute your working set.
`
`This chapter covers the 0penGL’s texture-mapping facility in the following
`major sections.
`‘
`
`"An Overview and an Example” on page 321 gives a brief, broad look
`at the steps required to perform texture mapping. It also presents a
`relatively simple example of texture mapping.
`
`. "Specifying the Texture” on page 326 explains how to specify one- or
`two-dimensional textures. It also discusses how to use a texture’s
`
`borders, how to supply a series of related textures of different sizes, and
`how to control the filtering methods used to determine how an
`applied texture is mapped to screen coordinates.
`
`“Filtering” on page 344 details how textures are either magnified or
`minjfied as they are applied to the pixels of polygons. Minification
`using special rnipmap textures is also explained.
`
`“Texture Objects” on page 346 describes how to put texture images
`into objects so that you can control several textures at one time. With
`texture objects, you may be able to create a working set of
`hjgh—performance textures, which are said to be resident. You may also
`prioritize texture objects to increase or decrease the likelihood that a
`texture object is resident.
`
`“Texture Functions" on page 354 discusses the methods used for
`painting a texture onto a surface. You can choose to have the texture
`color values replace those that would be used if texturing wasn’t in
`effect, or you can have the final color be a combination of the two.
`
`“Assigning Texture Coordinates” on page 357 describes how to
`compute and assign appropriate texture coordinates to the vertices of
`an object. It also explains how to control the behavior of coordinates
`that lie outside the default range—that is, how to repeat or clamp
`textures across a surface.
`
`“Automatic Texture-Coordinate Generation” on page 364 shows how
`to have OpenGL automatically generate texture coordinates so that
`you can achieve such effects as contour and environment maps.
`
`320
`
`Chapter 9: Texture Mapping
`
`0369
`
`
`
`0
`
`“Advanced Features” on page 371 explains how to manipulate the
`texture matrix stack and how to use the q texture coordinate.
`
`Version 1.1 of Oper1GL introduces several new’ texture-mapping operations:
`
`0 Thirty-eight additional internal texture image formats
`
`0 Texture proxy, to query whether there are enough resources to
`accommodate a given texture image
`
`0 Texture subimage, to replace all or part of an existing texture image
`rather than completely deleting and creating a texture to achieve
`the same effect
`
`0
`
`Specifying texture data from frarnebuffer memory (as well as from
`processor memory)
`
`- Texture objects, including resident textures and prioritizing
`
`If you try to use one of these texture-mapping operations and can't find it,
`check the version number of your-implementation of OpenGL to see if it
`actually supports it. (See "Which Version Am I Using?” on page 503.)
`
`An Overview and an Example
`
`This section gives an overview of the steps necessary to perform texture
`mapping. It also presents a relatively simple texture-mapping program. Of
`course, you know that texture mapping can be a very involved process.
`
`Steps in Texture Mapping
`
`To use texture mapping, you perform these steps.
`
`1. Create a texture object and specify a texture for that object.
`
`2.
`
`Indicate how the texture is to be applied to "each pixel.
`
`3. Enable texture mapping.
`
`4. Draw the scene, supplying both texture and geometric coordinates. _
`
`Keep in mind that texture mapping works only in RGBA mode. Texture
`mapping results in color-index mode are undefined.
`
`An Overview and an Example
`
`321
`
`
`
`0370
`
`
`
`Create a Texture Object and Specify a Texture for That Object
`
`A texture is usually thought of as being two-dimensional, like most images,
`but it can also be one-dimensional. The data describing a texture may
`consist of one, two, three, or four elements per texel, representing anything
`from a modulation constant to an (R, G, B, A) quadruple.
`
`In Example 9-1, which is very simple, a single texture object is created to
`maintain a single two-dimensional texture. This example does not find out
`how much memory is available. Since only one texture is created, there is
`no attempt to prioritize or otherwise manage a working set of texture
`objects. Other advanced techniques, such as texture borders or Iniprnaps,
`are not used in this simple example.
`
`Indicate How the Texture Is to Be Applied to Each Pixel
`
`You can choose any of four possible functions for computing the final
`RGBA value from the fragment color and the texture-image data. One
`possibility is simply to use the texture color as the final color; this is the
`decal mode, in which the texture is painted on top of the fragment, just as
`a decal would be applied. (Example 9-1 uses decal mode.) The replace mode,
`a variant of the decal mode, is a second method. Another method is to use
`the texture to modulate, or scale, the fragment’s color; this technique is
`useful for combining the effects of lighting with texturing. Finally, a
`constant color can be blended with that of the fragment, based on the
`texture value.
`
`Enable Texture Mapping
`
`You need to enable texturing before drawing your scene. Texturing is
`enabled or disabled using glEnable0 or glDisable0 with the symbolic
`constant GL_TEXTURE__1D or GL_TEXTURE_2.D for one- or
`two-dimensional texturing, respectively. (If both are enabled,
`GL_TEXTURE_2D is the one that is used.)
`
`Draw the Scene, Supplying Both Texture and Geometric Coordinates
`
`You need to indicate how the texture-should be aligned relative to the
`fragments to which it’s to be applied before it’s "glued on.” That is, you
`need to specify both texture coordinates and geometric coordinates as you
`specify the objects in your scene. For a two-dimensional texture map, for
`example, the texture coordinates range from 0.0 to 1.0 in both directions,
`but the coordinates of the items being textured can be anything. For the
`brick-wall example, if the wall is square and meant to represent one copy of
`
`32
`
`Chapter 9: Texture Mapping
`
`0371
`
`
`
`the texture, the code would probably assign texture coordinates (0, 0), (1, 0),
`(1, 1), and (O, 1) to the four comers of the wall. If the wall is large, you might
`want to paint several copies of the texture map on it. If you do so, the‘
`texture map must be designed so that the bricks on the left edge match up
`nicely with the bricks on the right edge, and similarly for the bricks on the
`top and those on the bottom.
`
`You must also indicate how texture coordinates outside the range [0.0,1.0]
`should be treated. Do the textures repeat to cover the object, or are they
`clamped to a boundary value?
`
`A Sample Program
`
`One of the problems with showing sample programs to illustrate texture
`mapping is that interesting textures are large. Typically, textures are read
`from an image file, since specifying a texture programmatically could take
`hundreds of lines of code. In Example 9-1, the texture-—which consists of
`a