Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Buffers © Jeff Parker, 2011. 2 Objectives Introduce additional OpenGL buffers Buffers in General Alpha Blending Accumulation Buffers Stencil Buffers.

Similar presentations


Presentation on theme: "1 Buffers © Jeff Parker, 2011. 2 Objectives Introduce additional OpenGL buffers Buffers in General Alpha Blending Accumulation Buffers Stencil Buffers."— Presentation transcript:

1 1 Buffers © Jeff Parker, 2011

2 2 Objectives Introduce additional OpenGL buffers Buffers in General Alpha Blending Accumulation Buffers Stencil Buffers Please fill out the on-line evaluations

3 3 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Buffer Define a buffer by Spatial resolution (n x m) and its Depth (or precision) k, the number of bits/pixel Purpose pixel

4 4 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 OpenGL Frame Buffer We have seen the first three buffers We will focus on two more tonight Accumulation Buffer Accumulate – add up Stencil Buffer Single out - mark

5 5 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Writing in Buffers Conceptually, we can consider all of memory as a large two- dimensional array of pixels We read and write rectangular block of pixels Bit block transfer (bitblt) operations The frame buffer is part of this memory frame buffer (destination) writing into frame buffer source memory

6 6 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Writing Model Read destination pixel before writing source

7 7 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Bit Writing Modes Source and destination bits are combined bitwise 16 possible functions (one per column in table) replace OR XOR

8 8 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 XOR mode Recall from Chapter 3 that we can use XOR by enabling logic operations and selecting the XOR write mode XOR is especially useful for swapping blocks of memory such as menus that are stored off screen If S represents screen and M represents a menu the sequence S  S  M M  S  M S  S  M swaps the S and M

9 9 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 The Pixel Pipeline OpenGL has a separate pipeline for pixels Writing pixels involves Moving pixels from processor memory to the frame buffer Format conversions Mapping, Lookups, Tests Reading pixels Format conversion

10 10 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Buffer Selection OpenGL can draw into or read from any of the color buffers (front, back, auxiliary) Default to the back buffer Change with glDrawBuffer and glReadBuffer Note that format of the pixels in the frame buffer is different from that of processor memory and these two types of memory reside in different places Need packing and unpacking Drawing and reading can be slow

11 11 Examples We have seen two examples that write to frame buffer Mandelbrot RayTracer void display() { glClear(GL_COLOR_BUFFER_BIT); glDrawPixels(n,m,GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image); glFlush(); }

12 12 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004 Bitmaps OpenGL treats 1-bit pixels (bitmaps) differently from multi-bit pixels (pixelmaps) Bitmaps are masks that determine if the corresponding pixel in the frame buffer is drawn with the present raster color 0  color unchanged 1  color changed based on writing mode Bitmaps are useful for raster text GLUT font: GLUT_BIT_MAP_8_BY_13 OpenGL maintains a Raster Position, where new character will be placed

13 13 Alpha Blending It is possible to blend colors together The gives the appearance of translucent materials We blend the current destination with the source The results are order dependant glEnable(GL_BLEND) glBlendFunc(source_factor, destination_factor)

14 Alpha Blending Two routines - Both use the alpha channel static void drawLeftTriangle(void) { /* draw yellow triangle on LHS of screen */ glBegin (GL_TRIANGLES); glColor4f(1.0, 1.0, 0.0, 0.75); glVertex3f(0.1, 0.9, 0.0); glVertex3f(0.1, 0.1, 0.0); glVertex3f(0.7, 0.5, 0.0); glEnd(); }

15 Which first? void display(void) { glClear(GL_COLOR_BUFFER_BIT); if (leftFirst) { drawLeftTriangle(); drawRightTriangle(); } else { drawRightTriangle(); drawLeftTriangle(); } glFlush(); }

16 16 Issue: Average in Place We want to average three numbers: 1, 1, and 97. If average 1 and 97, we get 49 If we average 1 and 49, we get 25 However, if we average 1's first, and then average in the 97, we get 49 Right answer is ( )/3 = 33 In the first case, we divide 97 by 4: in the second by 2. Want to divide by 3.

17 Solution: Accumulation Buffer We may want to combine multiple pixels to arrive at a result Wish to avoid blending, as it is order dependant We would rather compute a true average. But if I average the values of 4 pixels, I run the risk of overflow I could divide before addition, but then I loose precision The Accumulation Buffer is designed for such purposes Stores a floating point number for each color value in pixel buffer Protocol Clear the buffer Add to it with a scaling factor Copy results back to frame buffer 17

18 Applications We can combine images Or perform image processing on image We can use this for Motion blur Antialiasing Depth of Field Soft Shadows Next week 18

19 Motion Blur SIGGRAPH 1996 motionblur.c Render the ball multiple times, moving the ball between passes

20 Using Accumulation Buffer void redraw(void) {... switch(rendermode) { case NONE: render(0.f, 0.f, 0.f); break; case FIELD:... glClear(GL_ACCUM_BUFFER_BIT); for (i = 0; i < max; i++) { render(dx * i, dy * i, dz * i); glAccum(GL_ACCUM, 1.f/max); } glAccum(GL_RETURN, 1.f); break; Clear buffer Add into accumulation buffer Copy result to frame buffer

21 Render void render(GLfloat dx, GLfloat dy, GLfloat dz) {... glPushMatrix(); glTranslatef(-80.f + dx, -60.f + dy, -420.f + dz); glCallList(SPHERE); glPopMatrix(); glPushMatrix(); glTranslatef(-20.f, -80.f, -600.f); glCallList(CONE); glPopMatrix(); Note that we waste time reimaging everything, when only the sphere moves

22 Convolutions It is common in image processing to use convolutions A common use is to find edges, as with the Sobel filter below 22

23 Convolutions SIGGRAPH 1996 convolve.c This is a version of the cone and sphere picture after applying the Sobel edge detector We are looking for edges as x increases {-.5f, 0.f,.5f, -1.f, 0.f, 1.f, -.5f, 0.f,.5f}; 23 Note that we waste time reimaging everything, when only the sphere moves

24 Convolutions void redraw(void) { glClearAccum(curmat->bias, curmat->bias, curmat- >bias, 1.0); glClear(GL_ACCUM_BUFFER_BIT); convolve(render, curmat); glViewport(0, 0, winWidth, winHeight); /* !?! */ glAccum(GL_RETURN, curmat->scale); glutSwapBuffers(); }

25 Convolutions void convolve(void (*draw)(void), Filter *mat) {... for(j = 0; j < jmax; j++) { for(i = 0; i < imax; i++) { glViewport(-i, -j, winWidth - i, winHeight - j); draw(); glAccum(GL_ACCUM, mat->array[i + j * imax]); } 25

26 Sobel Filter void sobel(Filter *mat) { static GLfloat sobel[] = {-.5f, 0.f,.5f, -1.f, 0.f, 1.f, -.5f, 0.f,.5f}; resize(mat, 3, 3); memcpy(mat->array, sobel, sizeof(sobel)); mat->scale = 2.f; mat->bias = 0.f; } We usually use Sobel filters in pairs This version detects vertical edges

27 Resize /* doesn't re-initialize matrix */ void resize(Filter *mat, int rows, int cols) { if (mat->rows != rows || mat->cols != cols) { free(mat->array); mat->array = (GLfloat *)realloc(mat->array, rows * cols * sizeof(GLfloat)); } mat->rows = rows; mat->cols = cols; }

28 Extra Free! /* doesn't re-initialize matrix */ void resize(Filter *mat, int rows, int cols) { if (mat->rows != rows || mat->cols != cols) { free(mat->array); /* 1) Already done by realloc 2) Free before using? Ouch! */ mat->array = (GLfloat *)realloc(mat->array, rows * cols * sizeof(GLfloat)); } mat->rows = rows; mat->cols = cols; }

29 realloc The realloc() function tries to change the size of the allocation pointed to by ptr to size, and returns ptr. If there is not enough room to enlarge the memory allocation pointed to by ptr, realloc() creates a new allocation, copies as much of the old data pointed to by ptr as will fit to the new allocation, frees the old allocation, and returns a pointer to the allocated memory. 29

30 Depth of Field SIGGRAPH 1996 field.c How can we get the effect of the depth of field? 30

31 Image for(j = min; j < max; j++) { for(i = min; i < max; i++) { dx = scale * i * FRUSTNEAR/focus; dy = scale * j * FRUSTNEAR/focus; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-FRUSTDIM + dx, FRUSTDIM + dx, -FRUSTDIM + dy, FRUSTDIM + dy, FRUSTNEAR, FRUSTFAR); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(scale * i, scale * j, 0.f); render(); glAccum(GL_ACCUM, 1.f/count); } glAccum(GL_RETURN, 1.f);

32 Jitter What is happening? We tweak the eye point and the direction the eye is looking For items at the right distance (focal plane) there is no movement 32

33 Fragment Testing Not every fragment becomes a pixel. Some make it to frame buffer, but are overwritten For a fragment to make it to the frame buffer, it must pass a number of tests The tests that a fragment must pass include: scissor test - an additional clipping test alpha test - a filtering test based on the alpha color component stencil test - a pixel mask test depth test - fragment occlusion test Each controlled by glEnable() capability. If a fragment passes all enabled tests, it is then blended, dithered and/or logically combined with pixels in the framebuffer. 33 Angel: Interactive Computer Graphics 4E © Addison- Wesley 2004

34 Updating Buffers For some of these tests, there is no change to state scissor test - an additional clipping test alpha test - a filtering test based on the alpha color component stencil test - a pixel mask test May update stencil depth test - fragment occlusion test May update the depth buffer The Stencil Test is the much more complex than depth test Tied to the depth test, which follows it 34

35 Bit Tests 35

36 Stencil Buffer

37 37 Stencil Buffer Control drawing based on values in the stencil buffer Fragments that fail the stencil test are not drawn Example: create a mask and only draw objects not in mask area Region can be more complex than for the Scissors test Unlike other buffers, we do not draw into the stencil buffer. We set its values with the stencil functions. However, the rendering can alter the values in the stencil buffer depending on whether a fragment passes or fails the stencil test.

38 Redbook stenciltest.c Unlike other buffers, we do not draw into the stencil buffer. We set its values with the stencil functions. However, rendering can alter the values in the stencil buffer depending on whether a fragment passes or fails the stencil test. Implementations are required to support at least one bit of stencil. Most support 8 today. This example distinguishes four areas: background, red, green, and blue

39 Initialize glClearColor(0.0, 0.0, 0.0, 0.0); glClearStencil(0); glStencilMask(1); // Now we can only write LSBit glEnable(GL_STENCIL_TEST); glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); // ? Didn’t we do this with glClearStencil(0)?

40 Initialize glClearColor(0.0, 0.0, 0.0, 0.0); glClearStencil(0); glStencilMask(1); // Now we can only write LSBit glEnable(GL_STENCIL_TEST); glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); // ? Didn’t we do this The glClear() function sets the bitplane area of the window to values previously set by glClearStencil()...

41 Draw static void Draw(void) { glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColor3ub(200, 0, 0); glBegin(GL_POLYGON); glVertex3i(-4, -4, 0); glVertex3i( 4, -4, 0); glVertex3i( 0, 4, 0); glEnd();

42 First Layer Values in the stencil buffer

43 Translation glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. zfail: Stencil action when the stencil test passes, but the depth test fails. GL_KEEPKeeps the current value. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_REPLACESet stencil buffer value to ref

44 Second Layer static void Draw(void) {... glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_INCR, GL_KEEP, GL_DECR); glColor3ub(0, 200, 0); glBegin(GL_POLYGON); glVertex3i(3, 3, 0); glVertex3i(-3, 3, 0); glVertex3i(-3, -3, 0); glVertex3i(3, -3, 0); glEnd(); Note that depth test has not been enabled

45 Painting in Green 45 What does the stencil hold? glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_INCR, GL_KEEP, GL_DECR); There are two effects: Color (or not) and Set stencil buffer (or not) Note that depth test is not enabled

46 Translation glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_INCR, GL_KEEP, GL_DECR); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_INCRIncrements the current stencil buffer value zfail: Stencil action when the stencil test passes, but the depth test fails. GL_KEEPKeeps the current value. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_DECRDecrements the current stencil buffer value.

47 Painting in Green glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_INCR, GL_KEEP, GL_DECR);

48 Last Layer static void Draw(void) {... glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glColor3ub(0, 0, 200); glBegin(GL_POLYGON); glVertex3i(3, 3, 0); glVertex3i(-3, 3, 0); glVertex3i(-3, -3, 0); glVertex3i(3, -3, 0); glEnd();

49 Painting in Blue glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

50 Translation glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. zfail: Stencil action when the stencil test passes, but the depth test fails. GL_KEEPKeeps the current value. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_KEEPKeeps the current value.

51 Stencil vs Depth Buffers The stencil buffer is the same size as the frame buffer, but is not displayed. Like the depth buffer The stencil buffer holds unsigned numbers (Usually at least 8 bits) The depth buffer holds real numbers in the range 0.0 – 1.0 We use the stencil buffer to tag pixel positions. Based on the tags and a comparison function, we accept or reject a pixel, and update stencil value. The depth buffer compares new value to old, and replaces old when the new value is closer to viewer We can use the stencil buffer like an array of counters, and manipulate the values using different masks, or treat it as one number 51

52 Stencil Test Protocol Summary glutInitDisplayMode (... | GLUT_STENCIL); glClearStencil(0); glEnable(GL_STENCIL_TEST); glClear(...|GL_STENCIL_BUFFER_BIT); glStencilFunc (GL_EQUAL,// Comparison 0x1, // Reference value 0x1);// Mask Mask is applied to stencil pixels and reference value before comparison glStencilOp (GL_KEEP,// stencil fail GL_INCR,// stencil pass, depth fail GL_DECR);// stencil pass, depth pass /* draw things */ 52

53 glStencilFunc glStencilFunc(GL_ALWAYS, 1, 1); glStencilFunc(GLenum func, GLint ref, GLuint mask); func - comparison function, The function can be GL_NEVER, GL_ALWAYS,..GL_EQUAL,… ref - The reference value for the stencil test. The ref parameter is clamped to the range [0, 2^n-1], where n is the number of bitplanes in the stencil buffer. maskA - mask that is ANDed with both the reference value and the stored stencil value when the test is done. By default, func is GL_ALWAYS, ref is 0, mask is all 1s, and stenciling is disabled. 53

54 glStencilOp glStencilOp(GL_INCR, GL_KEEP, GL_DECR); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. GL_ZEROSets the stencil buffer value to zero. GL_REPLACESets the stencil buffer value to ref, as specified by glStencilFunc. GL_INCRIncrements the current stencil buffer value. Clamps to the maximum representable unsigned value. GL_DECRDecrements the current stencil buffer value. Clamps to zero. GL_INVERTBitwise inverts the current stencil buffer value. zfail: Stencil action when the stencil test passes, but the depth test fails. Accepts the same symbolic constants as fail. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. Accepts the same symbolic constants as fail.

55 SIGGRAPH 1997 decal.c Z-Fighting when drawing co-planar objects Using Stencil Buffer There are 4 co-planar objects: the ground (red) the asphalt, the yellow stripes, and the plane's shadow

56 Decal 56 void setupDecalState(int decalNum) { if (useStencil) { glDisable(GL_DEPTH_TEST); glDepthMask(0); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_GREATER, decalNum, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); }

57 Translation glStencilFunc(GL_GREATER, decalNum, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. zfail: Stencil action when the stencil test passes, but the depth test fails. GL_KEEPKeeps the current value. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_REPLACEReplace with decalNum

58 Draw 58 drawAirplane(); … setupBasePolygonState(3);/* 2 decals */ drawGround(); /* decal # 1 = the runway asphalt */ setupDecalState(1); drawAsphalt(); /* decal # 2 = yellow paint on the runway */ setupDecalState(2); drawStripes(); /* decal # 3 = the plane's shadow */ setupDecalState(3);...

59 Decal 59 The following is only used for the Red Base void setupBasePolygonState(int maxDecal) { glEnable(GL_DEPTH_TEST); if (useStencil) { glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, maxDecal + 1, 0xff); glStencilOp(GL_KEEP, GL_REPLACE, GL_ZERO); }

60 Translation glStencilFunc(GL_ALWAYS, maxDecal + 1, 0xff); glStencilOp(GL_KEEP, GL_REPLACE, GL_ZERO); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeep the current value. zfail: Stencil action when the stencil test passes, but the depth test fails. GL_REPLACEReplace with maxDecal + 1 zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_ZEROSet to zero 60

61 Draw Stencil state as colors doneWithFrame:... switch(dataChoice) { case COLOR: break; /* color already in back buffer */ case STENCIL: copyStencilToColor(GL_BACK); break; case DEPTH: copyDepthToColor(GL_BACK); break; } glutSwapBuffers(); } 61

62 Array of colors These colors are used to map stencil values to figure unsigned char colors[][3] = { {255, 0, 0}, /* red */ {255, 218, 0}, /* yellow */ {72, 255, 0}, /* yellowish green */ {0, 255, 145}, /* bluish cyan */ {0, 145, 255}, /* cyanish blue */ {72, 0, 255}, /* purplish blue */ {255, 0, 218}, /* reddish purple */ }; 62

63 SIGGRAPH 1997 dissolve.c 63

64 Eraser void makeEraser(void) {... for(y = 0; y < eraserHeight; y++) for(x = 0; x < eraserWidth; x++) { dx = x - eraserWidth / 2; dy = y - eraserHeight / 2; d = sqrt(dx * dx + dy * dy); if(pow(drand48(),.75) * eraserWidth / 2 > d) { eraserpix[i + 0] = 255; eraserpix[i + 1] = 255; eraserpix[i + 2] = 255; eraserpix[i + 3] = 255; } i += 4; } 64

65 Mouse /* left button, first layer, middle button, second layer */ void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { eraser = GL_TRUE; if (button == GLUT_LEFT_BUTTON) layer = 1; else /* GLUT_MIDDLE: GLUT_RIGHT is for menu */ layer = 0; } else { /* GLUT_UP */ eraser = GL_FALSE; } glutPostRedisplay(); } 65 I don't have a middle button: I removed the menu to restore this functionality to right button

66 DrawEraser void draweraser(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, winWidth, 0, winHeight); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* replace with this layer */ glStencilFunc(GL_ALWAYS, layer, 0); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_NOTEQUAL, 0); glRasterPos2i(eraserpos[X], eraserpos[Y]); glBitmap(0, 0, 0.f, 0.f, -winWidth/8.f, -winHeight/12.f, 0); glDrawPixels(eraserWidth, eraserHeight, GL_RGBA, GL_UNSIGNED_BYTE, eraserpix); glDisable(GL_ALPHA_TEST); } 66 Larger on next page…

67 DrawEraser void draweraser(void) {... /* replace with this layer */ glStencilFunc(GL_ALWAYS, layer, 0); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_NOTEQUAL, 0); glRasterPos2i(eraserpos[X], eraserpos[Y]); glBitmap(0, 0, 0.f, 0.f, -winWidth/8.f, -winHeight/12.f, 0); glDrawPixels(eraserWidth, eraserHeight, GL_RGBA, GL_UNSIGNED_BYTE, eraserpix); glDisable(GL_ALPHA_TEST); } 67

68 Translation glStencilFunc(GL_ALWAYS, layer, 0); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); void glStencilFunc(GLenum func, GLint ref, GLuint mask); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. zfail: Stencil action when the stencil test passes, but the depth test fails. GL_REPLACEReplace with layer zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. GL_REPLACEReplace with layer

69 Draw Routine void redraw(void) { if (glutLayerGet(GLUT_NORMAL_DAMAGED) || clearstencil == GL_TRUE) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); clearstencil = GL_FALSE; } else glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_EQUAL, 2, (unsigned)~0); drawlayer2(); glStencilFunc(GL_EQUAL, 1, (unsigned)~0); drawlayer1(); glStencilFunc(GL_EQUAL, 0, (unsigned)~0); drawlayer0(); if (eraser) draweraser();... } 69 Larger on later page…

70 glStencilFunc glStencilFunc(GL_ALWAYS, 1, 1); glStencilFunc(GLenum func, GLint ref, GLuint mask); func - comparison function, ref The reference value for the stencil test. The ref parameter is clamped to the range [0,2n 1], where n is the number of bitplanes in the stencil buffer. mask mask that is ANDed with both the reference value and the stored stencil value when the test is done. The function can be GL_NEVER, GL_ALWAYS,..GL_EQUAL,… By default, func is GL_ALWAYS, ref is 0, mask is all 1s, and stenciling is disabled. 70

71 glStencilOp glStencilOp(GL_INCR, GL_KEEP, GL_DECR); void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass); fail: The action to take when the stencil test fails. GL_KEEPKeeps the current value. GL_ZEROSets the stencil buffer value to zero. GL_REPLACESets the stencil buffer value to ref, as specified by glStencilFunc. GL_INCRIncrements the current stencil buffer value. Clamps to the maximum representable unsigned value. GL_DECRDecrements the current stencil buffer value. Clamps to zero. GL_INVERTBitwise inverts the current stencil buffer value. zfail: Stencil action when the stencil test passes, but the depth test fails. Accepts the same symbolic constants as fail. zpass: Stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. Accepts the same symbolic constants as fail. 71

72 Draw Routine void redraw(void) {... glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_EQUAL, 2, (unsigned)~0); drawlayer2(); glStencilFunc(GL_EQUAL, 1, (unsigned)~0); drawlayer1(); glStencilFunc(GL_EQUAL, 0, (unsigned)~0); drawlayer0(); if(eraser) draweraser();... } 72

73 Layer 2 void drawlayer2(void) {... glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(winWidth, 0); glTexCoord2i(1, 1); glVertex2i(winWidth, winHeight); glTexCoord2i(0, 1); glVertex2i(0, winHeight); glEnd(); glDisable(GL_TEXTURE_2D); } 73

74 Layer 0 void drawlayer0(void) { static GLfloat lightpos[] = {50.f, 50.f, 0.f, 1.f}; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-50.f, 50.f, -50.f, 50.f, 0.f, 100.f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.f, 0.f, -50.f); glRotatef(angle, 0.f, 1.f, 0.f); glRotatef(90.f, 0.f, 0.f, 1.f); glTranslatef(0.f, -25.f, 0.f); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, lightpos); glCullFace(GL_BACK); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glCallList(CONE); } 74 Layer 1 is similar, but more complex…

75 Init glClearStencil(2); glEnable(GL_STENCIL_TEST); /* used all the time */ glEnable(GL_CULL_FACE); glCullFace(GL_BACK); 75

76 Halo When your action figure acquires super powers, draw her with a halo However, don't want to obscure her face with yellow schmutz So set reference stencil value and draw her normally Then expand her, and draw the enlarged area that does not touch the old values with the halo color, blending with background color 76

77 Reflections We can use Ray Tracing We have faked reflections with environmental mapping We will"reflect" the model through a plane and draw it again Stencil buffer helps to keep it clean 77

78 78 multimirror SIGGRAPH 1997 Advanced OpenGL tutorial Can add or remove rooms: > < Can change viewpoint: h

79 79 multimirror typedef struct { GLfloat verts[4][3]; GLfloat scale[3];/* Scale */ GLfloat trans[3];/* Translation */ } Mirror; Mirror mirrors[] = { /* mirror on the left wall */ {{{-1., -.75, -.75}, {-1.,.75, -.75}, {-1.,.75,.75}, {-1, -.75,.75}}, {-1, 1, 1}, /* x = -x */ {2, 0, 0}},/* x = x + 2 */ int nMirrors = 2; Room is 2x2x2 cube centered at origin

80 80 draw_mirror void draw_mirror(Mirror *m) { glBegin(GL_QUADS); glVertex3fv(m->verts[0]); glVertex3fv(m->verts[1]); glVertex3fv(m->verts[2]); glVertex3fv(m->verts[3]); glEnd(); } does not draw what you see in mirror

81 81 reflect /* It would be easier to use push and pop to * save and restore the matrices, but stack * is very shallow */ GLenum reflect_through_mirror(Mirror *m, GLenum cullFace) { GLenum newCullFace = ((cullFace == GL_FRONT) ? GL_BACK : GL_FRONT); glMatrixMode(GL_PROJECTION); glScalef(m->scale[0], m->scale[1], m->scale[2]); glTranslatef(m->trans[0], m->trans[1], m->trans[2]); glMatrixMode(GL_MODELVIEW); /* must flip the cull face */ glCullFace(newCullFace); return newCullFace; }

82 82 undo_reflect void undo_reflect_through_mirror(Mirror *m, GLenum cullFace) { glMatrixMode(GL_PROJECTION); glTranslatef(-m->trans[0], -m->trans[1], -m->trans[2]); glScalef(1./m->scale[0], 1./m->scale[1], 1./m->scale[2]); glMatrixMode(GL_MODELVIEW); glCullFace(cullFace); }

83 83 drawroom void draw_room(void) { /* material for the walls, floor, ceiling */ static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat); glBegin(GL_QUADS); /* floor */ glNormal3f(0, 1, 0); glVertex3f(-1, -1, 1); glVertex3f(1, -1, 1); glVertex3f(1, -1, -1); glVertex3f(-1, -1, -1);

84 84 make viewpoint void make_viewpoint(void) { if (headsUp) {... } else { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, 1,.01, 4 + 2*(draw_passes / nMirrors)); /* far */ gluLookAt(-2, 0,.75, 0, 0, 0, 0, 1, 0); }

85 85 draw callback void draw(void) { GLenum err; GLfloat secs = get_secs(); glDisable(GL_STENCIL_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if (!headsUp) glEnable(GL_STENCIL_TEST); draw_scene(secs, draw_passes, GL_BACK, 0, (unsigned)-1); glDisable(GL_STENCIL_TEST);... }

86 draw_scene void draw_scene(GLdouble secs, int passes, GLenum cullFace, GLuint stencilVal, GLuint mirror) { GLenum newCullFace; int passesPerMirror, passesPerMirrorRem; unsigned int curMirror, drawMirrors; int i; /* one pass to draw the real scene */ passes--; /* only draw in my designated locations */ glStencilFunc(GL_EQUAL, stencilVal, 0xffffffff); /* draw things which may obscure the mirrors first */ draw_sphere(secs); draw_cone();

87 87 draw_scene /* now draw the appropriate number of mirror reflections. for * best results, we perform a depth-first traversal by allocating * a number of passes for each of the mirrors. */ if (mirror != 0xffffffff) { passesPerMirror = passes / (nMirrors - 1); passesPerMirrorRem = passes % (nMirrors - 1); if (passes > nMirrors - 1) drawMirrors = nMirrors - 1; else drawMirrors = passes; } else { /* mirror == -1 means that this is the initial scene */ passesPerMirror = passes / nMirrors; passesPerMirrorRem = passes % nMirrors; if (passes > nMirrors) drawMirrors = nMirrors; else drawMirrors = passes; }

88 draw_scene for (i = 0; drawMirrors > 0; i++) { curMirror = i % nMirrors; if (curMirror == mirror) continue; drawMirrors--; /* draw mirror into stencil buffer but not color or depth buffers */ glColorMask(0, 0, 0, 0); glDepthMask(0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); draw_mirror(&mirrors[curMirror]); glColorMask(1, 1, 1, 1); glDepthMask(1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

89 draw_scene for (i = 0; drawMirrors > 0; i++) { curMirror = i % nMirrors; if (curMirror == mirror) continue; drawMirrors--; /* draw mirror into stencil buffer... */... /* draw reflected scene */ newCullFace = reflect_through_mirror(&mirrors[curMirror], cullFace); if (passesPerMirrorRem) { draw_scene(secs, passesPerMirror + 1, newCullFace, stencilVal + 1, curMirror); passesPerMirrorRem--; } else { draw_scene(secs, passesPerMirror, newCullFace, stencilVal + 1, curMirror); } undo_reflect_through_mirror(&mirrors[curMirror], cullFace);

90 90 Prepare view 1. Load the modelview matrix with the view transform. For example, given the eye location, the center of viewing, and up direction vector, the view transform can be set as follows: glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eye[0], eye[1], eye[2], center[0], center[1], center[2], up[0], up[1], up[2]); 2. Push the modelview matrix: glPushMatrix();

91 91 Reflection Transform 3. Multiply the current modelview matrix by a reflection matrix that reflects the scene through the plane of the mirror. Consider the special case where the mirror happens to lie in the z=0 plane. This special case reflection is a simple scaling matrix that negates the Z coordinate: glScalef(1.0, 1.0, -1.0); For an arbitrary plane, a 4 by 4 matrix can be constructed to reflect through the plane 4. If using back face culling, cull front faces instead. The reflective transformation flips the front/back orientation of transformed polygons. glCullFace(GL_FRONT);

92 92 Reflected Scene 5. Draw the scene, but be careful to render only objects on the reflective side of the mirror plane. Otherwise, objects behind the mirror that should properly be obscured by the mirror will be rendered as if they are actually in front of the mirror plane. 6. Resume normal back face culling and undo the reflection matrix. glCullFace(GL_BACK); glPopMatrix();

93 93 Mirror Surface 7. Optionally, to give the appearance of a semi-reflective surface such as polished marble, or simply a dull or dirty mirror, a textured planar surface coincident with the mirror plane can be blended on top of the reflection rendered in Step 5. For example: glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); // additive blending renderMarbleTexturedMirrorSurfacePolygons(); glDisable(GL_BLEND); Even if mirror surface is not blended with a semi-reflective surface, it is important to render the mirror surface polygons into the depth buffer to ensure that when the scene is rendered again in the next step that objects properly are occluded by the mirrors. glColorMask(0,0,0,0); // disable color buffer updates renderMirrorSurfacePolygons(); // update depth buffer with the mirror surface glColorMask(1,1,1,1); // re-enable color buffer updates

94 94 Unreflected Scene 8. Finally, now render the unreflected scene. This type of rendering algorithm is often referred to as multi-pass because the sequence of operations involves rendering the scene or portions of the scene multiple times. Notice that steps 5 and 8 each render the scene but with different model view transformations. Assumes that you cannot look behind the plane of the mirror. Reflective stairs…

95 95 Mirrors with Stencil Buffer When clearing the frame buffer at start, also clear the stencil buffer to zero. For each mirror in the scene, the application must maintain a data structure that contains the non-overlapping and co-planar polygons that compose the mirror surface. For a standard rectangular mirror, the coordinates of four vertices are sufficient. Clear the color, depth, and stencil buffers. Then render the scene, excluding the mirror surfaces, with depth buffering but without stencil testing. glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFER_BIT); glEnable(GL_DEPTH_BUFFER_BIT); glDisable(GL_STENCIL_TEST); drawScene(); // draw everything except mirrors

96 96 Set the bits in Stencil Buffer Then for each mirror, perform the following sequence: 1. Set up stenciling to write the value 1 into the stencil buffer when the depth test passes. Also disable writes to the color buffer. Then draw the mirror’s polygons. glEnable(GL_STENCIL_TEST); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, ~0); glColorMask(0,0,0,0); renderMirrorSurfacePolygons(thisMirror); This step “tags” all the mirror’s visible pixels with a stencil value 1. Depth testing prevents occluded mirror pixels from being tagged.

97 97 Mirrors with Stencil Buffer 2. With the color buffer writes still disabled, set the depth range to write the farthest value possible for all updated pixels and set the depth test to always pass. Also, set the stencil test to only update pixels tagged with the stencil value 1. Then draw the mirror’s polygons. glDepthRange(1,1); // always glDepthFunc(GL_ALWAYS); // write the farthest depth value glStencilFunc(GL_EQUAL, 1, ~0); // match mirror’s visible pixels glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // do not change stencil values renderMirrorSurfacePolygons(thisMirror); This step resets the depth buffer to its cleared maximum value for all the mirror’s visible pixels.

98 98 Prepare the mirror space 3. Restore the depth test, color mask, and depth range to their standard settings: glDepthFunc(GL_LESS); glColorMask(1,1,1,1); glDepthRange(0,1);

99 99 Draw the Reflection We are now ready to render the reflection itself. The pixels belonging to the reflection with the stencil value 1, and these same pixels also have their depth values cleared to the farthest depth value. The stencil test remains enabled and only updating pixels with the stencil value 1, i.e. those pixels on the visible mirror. And the less than depth test will ensure subsequent rendering to the mirror pixels will determine visible surfaces appropriately. 4. Rendering the reflection requires reflecting the scene through the mirror plane, but we must also be careful to only render objects on the reflective side of the mirror Therefore, we establish a user-defined clip plane to render only objects on the reflective side of the mirror plane. The reflection itself is accomplished by concatenating the appropriate reflection matrix to the modelview matrix so that everything is reflected through the mirror plane. Because the reflection flips the sense of back and front facing polygons, the cull face state is reversed. Then the scene is rendered.

100 100 Draw the Reflection GLfloat matrix[4][4]; GLdouble clipPlane[4]; glPushMatrix(); // returns world-space plane equation for mirror plane to use as clip plane computeMirrorClipPlane(thisMirror, &clipPlane[0]); // set clip plane equation glClipPlane(GL_CLIP_PLANE0, &clipPlane); // returns mirrorMatrix (see Appendix A) for given mirror computeReflectionMatrixForMirror(thisMirror, &matrix[0][0]); // concatenate reflection transform into modelview matrix glMultMatrixf(&matrix[0][0]); glCullFace(GL_FRONT); drawScene(); // draw everything except mirrors drawOtherMirrorsAsGraySurfaces(thisMirror); // draw other mirrors as // neutral “gray” surfaces glCullFace(GL_BACK); glDisable(GL_CLIP_PLANE0); glPopMatrix();

101 101 Draw the Reflection Now the mirror’s reflection is rendered correctly. Other mirrors visible in the reflection of this mirror are rendered gray so at least they properly occlude objects behind them even if they do not reflect objects correctly. Immediately following, we sketch a recursive algorithm that handles reflections of reflections. 5. Finally, we reset to zero the stencil value of all the mirror’s pixels so the pixels are not confused with another mirror’s pixels while rendering the reflections of subsequent mirrors. Also update the depth buffer to reflect the mirror’s proper depth so this mirror may properly occlude any subsequent mirrors. Do not update the color buffer during this step. glColorMask(0,0,0,0); glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); glDepthFunc(GL_ALWAYS); renderMirrorSurfacePolygons(thisMirror); glDepthFunc(GL_LESS); glColorMask(1,1,1,1);

102 Summary We can use buffers to do some powerful image processing One more way to harness the power in your graphics card Don't forget to fill out the evaluations. 102

103 Resources Excellent paper "Improving Shadows and Reflections via the Stencil Buffer" by Mark Kilgard. The alpha blending and stencil test examples are from the Red Book halomagic - The rest are from 1996 and 1997 SIGCSE Advanced OpenGL talks ograms/programs.html Several of them require multiple source files and data files motionblur.c, convolve.c, field.c – depth of field 1997 – decal.c, dissolve.c

104 Video Lady from Shanghai Mirror sequence Manhattan Murder Mystery Mirror sequence

105 Sample Programs alphablend motionblur convolve field stencil decal.c dissolve.c multimirror.c halogmagic


Download ppt "1 Buffers © Jeff Parker, 2011. 2 Objectives Introduce additional OpenGL buffers Buffers in General Alpha Blending Accumulation Buffers Stencil Buffers."

Similar presentations


Ads by Google