1 buffers © jeff parker, 2011. 2 objectives introduce additional opengl buffers buffers in general...

105
1 Buffers © Jeff Parker, 2011

Upload: oliver-strickland

Post on 15-Jan-2016

253 views

Category:

Documents


0 download

TRANSCRIPT

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

1

Buffers

© Jeff Parker, 2011

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

2

Objectives

Introduce additional OpenGL buffers

Buffers in General

Alpha Blending

Accumulation Buffers

Stencil Buffers

Please fill out the on-line evaluations

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

3 Angel: Interactive Computer Graphics 4E © Addison-Wesley 2004

BufferDefine a buffer by

Spatial resolution (n x m) and its

Depth (or precision) k, the number of bits/pixel

Purpose

pixel

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

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

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

5 Angel: Interactive Computer Graphics 4E © Addison-Wesley 2004

Writing in BuffersConceptually, 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

sourcememory

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

6 Angel: Interactive Computer Graphics 4E © Addison-Wesley 2004

Writing Model

Read destination pixel before writing source

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

7 Angel: Interactive Computer Graphics 4E © Addison-Wesley 2004

Bit Writing ModesSource and destination bits are combined bitwise

16 possible functions (one per column in table)

replaceOR

XOR

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

8 Angel: Interactive Computer Graphics 4E © Addison-Wesley 2004

XOR modeRecall 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

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

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

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

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

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

11

ExamplesWe 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();

}

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

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

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

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)

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

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();

}

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

Which first?

void display(void)

{

glClear(GL_COLOR_BUFFER_BIT);

if (leftFirst) {

drawLeftTriangle();

drawRightTriangle();

}

else {

drawRightTriangle();

drawLeftTriangle();

}

glFlush();

}

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

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 (1 + 1 + 97)/3 = 33

In the first case, we divide 97 by 4: in the second by 2. Want to divide by 3.

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

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

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

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

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

Motion Blur

SIGGRAPH 1996

motionblur.c

Render the ball multiple times, moving the ball between passes

http://www.sgi.com/products/software/opengl/examples/glut/advanced/

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

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 bufferAdd into accumulation bufferCopy result to frame buffer

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

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

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

ConvolutionsIt is common in image processing to use convolutions

A common use is to find edges, as with the Sobel filter below

22

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

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

http://www.sgi.com/products/software/opengl/examples/glut/advanced/

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

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();

}

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

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

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

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 pairsThis version detects vertical edges

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

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;

}

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

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;

}

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

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

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

Depth of FieldSIGGRAPH 1996

field.c

How can we get the effect of the depth of field?

30

http://www.sgi.com/products/software/opengl/examples/glut/advanced/

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

Imagefor(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);

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

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

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

Fragment TestingNot 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

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

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

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

Bit Tests

35

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

Stencil Buffer

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

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.

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

Redbook stenciltest.cUnlike 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

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

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)?

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

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() ...

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

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();

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

First Layer

42

00000100000

00001110000

00011111000

00111111100

01111111110

Values in the stencil buffer

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

TranslationglStencilFunc(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_KEEP Keeps the current value.

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_KEEP Keeps 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_REPLACE Set stencil buffer value to ref

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

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

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

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) andSet stencil buffer (or not)

Note that depth test is not enabled

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

TranslationglStencilFunc(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_INCR Increments the current stencil buffer value

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_KEEP Keeps 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_DECR Decrements the current stencil buffer value.

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

Painting in Green

47

00000100000

00110001100

00100000100

00000000000

01111111110

glStencilFunc(GL_EQUAL, 1, 1);glStencilOp(GL_INCR, GL_KEEP, GL_DECR);

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

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();

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

Painting in Blue

49

00000100000

00110001100

00100000100

00000000000

01111111110

glStencilFunc(GL_EQUAL, 1, 1);glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

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

TranslationglStencilFunc(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_KEEP Keeps the current value.

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_KEEP Keeps 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_KEEP Keeps the current value.

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

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

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

Stencil Test Protocol Summary

52

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

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

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

glStencilOpglStencilOp(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_KEEP Keeps the current value.

GL_ZERO Sets the stencil buffer value to zero.

GL_REPLACE Sets the stencil buffer value to ref, as specified by glStencilFunc.

GL_INCR Increments the current stencil buffer value. Clamps to the maximum representable unsigned value.

GL_DECR Decrements the current stencil buffer value. Clamps to zero.

GL_INVERT Bitwise 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.

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

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

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

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);

}}

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

TranslationglStencilFunc(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_KEEP Keeps the current value.

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_KEEP Keeps 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_REPLACE Replace with decalNum

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

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);...

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

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);

}

}

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

TranslationglStencilFunc(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_KEEP Keep the current value.

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_REPLACE Replace 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_ZERO Set to zero

60

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

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

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

Array of colorsThese 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

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

SIGGRAPH 1997 dissolve.c

63

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

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

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

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

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

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…

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

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

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

TranslationglStencilFunc(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_KEEP Keeps the current value.

zfail: Stencil action when the stencil test passes, but the depth test fails.

GL_REPLACE Replace 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_REPLACE Replace with layer

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

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…

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

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

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

glStencilOpglStencilOp(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_KEEP Keeps the current value.

GL_ZERO Sets the stencil buffer value to zero.

GL_REPLACE Sets the stencil buffer value to ref, as specified by glStencilFunc.

GL_INCR Increments the current stencil buffer value. Clamps to the maximum representable unsigned value.

GL_DECR Decrements the current stencil buffer value. Clamps to zero.

GL_INVERT Bitwise 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

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

Draw Routinevoid 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

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

Layer 2void 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

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

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…

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

Init

glClearStencil(2);

glEnable(GL_STENCIL_TEST); /* used all the time */

glEnable(GL_CULL_FACE);

glCullFace(GL_BACK);

75

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

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

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

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

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

78

multimirror

SIGGRAPH 1997 Advanced OpenGL tutorial

Can add or remove rooms: > <

Can change viewpoint: h

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

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

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

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

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

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;

}

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

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);

}

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

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);

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

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);

}

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

85

draw callbackvoid 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);

...

}

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

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();

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

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;

}

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

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);

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

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);

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

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();

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

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);

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

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();

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

93

Mirror Surface

7. Optionally, to give the appearance of a semi-reflective surface such as polished marble, orsimply a dull or dirty mirror, a textured planar surface coincident with the mirror plane canbe blended on top of the reflection rendered in Step 5. For example:

glEnable(GL_BLEND);glBlendFunc(GL_ONE, GL_ONE); // additive blendingrenderMarbleTexturedMirrorSurfacePolygons();glDisable(GL_BLEND);

Even if mirror surface is not blended with a semi-reflective surface, it is important torender the mirror surface polygons into the depth buffer to ensure that when the scene isrendered again in the next step that objects properly are occluded by the mirrors.

glColorMask(0,0,0,0); // disable color buffer updatesrenderMirrorSurfacePolygons(); // update depth buffer with the mirror surface

glColorMask(1,1,1,1); // re-enable color buffer updates

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

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…

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

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 thatcontains 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 mirrorsurfaces, 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

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

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.

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

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); // alwaysglDepthFunc(GL_ALWAYS);

// write the farthest depth valueglStencilFunc(GL_EQUAL, 1, ~0);

// match mirror’s visible pixelsglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

// do not change stencil valuesrenderMirrorSurfacePolygons(thisMirror);

This step resets the depth buffer to its cleared maximum value for all the mirror’s visible pixels.

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

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);

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

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.

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

100

Draw the Reflection

GLfloat matrix[4][4];GLdouble clipPlane[4];glPushMatrix();// returns world-space plane equation for mirror plane to use as clip

planecomputeMirrorClipPlane(thisMirror, &clipPlane[0]);// set clip plane equationglClipPlane(GL_CLIP_PLANE0, &clipPlane);// returns mirrorMatrix (see Appendix A) for given mirrorcomputeReflectionMatrixForMirror(thisMirror, &matrix[0][0]);// concatenate reflection transform into modelview matrixglMultMatrixf(&matrix[0][0]);glCullFace(GL_FRONT);drawScene(); // draw everything except mirrorsdrawOtherMirrorsAsGraySurfaces(thisMirror); // draw other mirrors as// neutral “gray” surfacesglCullFace(GL_BACK);glDisable(GL_CLIP_PLANE0);glPopMatrix();

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

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);

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

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

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

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

http://www.opengl.org/resources/code/samples/redbook/

halomagic - http://www.sgi.com/products/software/opengl/examples/glut/examples/

The rest are from 1996 and 1997 SIGCSE Advanced OpenGL talks

http://www.sgi.com/products/software/opengl/examples/glut/advanced/

http://www.opengl.org/resources/code/samples/advanced/advanced97/programs/programs.html

Several of them require multiple source files and data files.

1996 - motionblur.c, convolve.c, field.c – depth of field

1997 – decal.c, dissolve.c

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

Video

Lady from Shanghai Mirror sequence

http://www.youtube.com/watch?v=G05H0QacqQM

Manhattan Murder Mystery Mirror sequence

http://www.youtube.com/watch?v=yUmd9w84Q2Q

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

Sample Programs

alphablend

motionblur

convolve

field

stencil

decal.c

dissolve.c

multimirror.c

halogmagic

http://www.opengl.org/resources/code/samples/redbook/

http://www.sgi.com/products/software/opengl/examples/glut/advanced/