Blending & stencil
Blending Combining
the pixel values that are currently being computed (source pixel) with the pixel values previously written (destination pixel)
OutputPixel = SourcePixel ⊗ SourceBlendFactor + DestPixel ⊗ DestBlendFactor
Blending Enable blending (disabled by default) SetRenderState(D3DRS_ALPHABLENDENABLE, true); Setting source/destination blend factor SetRenderState(D3DRS_SRCBLEND, Source); SetRenderState(D3DRS_DESTBLEND, Destination);
Blending
D3DBLEND_ZERO: (0, 0, 0, 0) D3DBLEND_ONE: (1, 1, 1, 1) D3DBLEND_SRCCOLOR: (rs, gs, bs, as)
D3DBLEND_INVSRCCOLOR : (1 – rs, 1 – gs, 1 – bs, 1 – as)
D3DBLEND_SRCALPHA: (as, as, as, as)
D3DBLEND_INVSRCALPHA: (1 – as, 1 – as, 1 – as,1 – as)
D3DBLEND_DESTALPHA: (ad, ad, ad, ad)
D3DBLEND_INVDESTALPHA : (1 – ad, 1 – ad, 1 – ad, 1 – ad)
D3DBLEND_DESTCOLOR: (rd, gd, bd, ad)
D3DBLEND_INVDESTCOLOR : (1 – rd, 1 – gd, 1 – bd, 1 – ad)
D3DBLEND_SRCALPHASAT: (f, f, f, 1)
Alpha source
Where the alpha component of the source pixels come from?
Alpha channel of the (current) texture
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
Diffuse component of current pixel
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
Transparency
Draw “background” object Set blending factors and alpha source Enable blending Draw transparent object Disable blending
blending is an “expensive” operation!
Issues with z-buffer
Many transparent objects
Depth sorting! Yes,
but base on what?
Center of polygon? Closet vertex? Furthest vertex? Distance to the face?
What
about overlapping polygons?
Binary Space Partitioning (BSP) 1
1 3
3
2
Front
2
4,5,62 4
4 5
5
6 61
62
3
Back 1,2,61
Binary Space Partitioning (BSP) 1 3
3
2
4,5,62
2 1, 61
61
62
Binary Space Partitioning (BSP) 1 3
3
2
4,5,62
2 1 61
61
62
Binary Space Partitioning (BSP) 1 3
3
2
2
5 4
4 5
1 62 61
61
62
Binary Space Partitioning (BSP) void traverse(Tree *t, Point vp) { if (t = NULL) return; if (vp in-front of plane at root of t ) { traverse(t->back, vp); draw polygons on node of t; traverse(t->front, vp); } else { traverse(t->front, vp); draw polygons on node of t; traverse(t->back, vp); } }
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4
61
5 Back 3 61
62
1
3 Front 3
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4
1 62
4
61
5 Front of 2 61
62
2 Back of 2 3 Front 3
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4
1 62
4 5
NULL 2
61
62
Front of 1 1 Back of 1 3 Front 3
61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4 5
NULL 2
61
62
1
NULL 1 61 3 Front 3
61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4 5
2 > 1 > 61 > 3 Front 3
61
62
1 61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4 5
2 > 1 > 61 > 3 Back 5
61
62
1
5 Front 5
61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4 5
2 > 1 > 61 > 3 Front 4
61
62
1
4 Back 4 5 NULL
61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4 62
4 5
2 > 1 > 61 > 3 NULL
61
62
1
4 62 5 NULL
61
Binary Space Partitioning (BSP) 1
3 3
2
5
2
4
1 62
4
61
5 61
62
2 > 1 > 61 > 3 > 4 > 62 > 5
SELECT THE PARTITION PLANE Planes
Select one that divides most equally the current polygon set
Planes
from polygons
constructed from vertex set
Very expensive!
Axis
aligned planes
EXERCISE DRAW A STATIC SCENE WITH SEVERAL TRANSPARENT (50%) CUBES CAMERA IS MOVING IN A CIRCLE, LOOKING AT THE CENTER OF THE CIRLE MUST PROPERLY SEE THE BEHIND CUBES
Next week
NON-STATIC TRANSPARENT OBJECTS? Don’t
use BSP Use simpler depth sort method!
STENCIL
STENCIL Like
blending, only enable it when really necessary
SetRenderState(D3DRS_STENCILENABLE, true); ... // do stencil work SetRenderState(D3DRS_STENCILENABLE, false);
STENCIL Initialize
the stencil buffer
Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xff000000, 1.0f, 0 );
STENCIL TEST (ref & mask) Op (value & mask) ref: pre-defined value mask: pre-defined value value: stencil value of the “current” pixel Op: a comparison operation (greater, smaller, …)
STENCIL TEST (ref & mask) Op (value & mask) ref: pre-defined value mask: pre-defined value value: stencil value of the “current” pixel Op: a comparison operation (greater, smaller, …)
STENCIL TEST Set reference value SetRenderState(D3DRS_STENCILREF, 0x1);
Set stencil mask SetRenderState(D3DRS_STENCILMASK, 0x0000FFFF); * Mask: used to “ignore/hide” certain bits in the stencil test. Default is 0xFFFFFFFF (use all stencil bits)
STENCIL TEST Comparision operations typedef enum _D3DCMPFUNC { D3DCMP_NEVER = 1, // always FALSE D3DCMP_LESS = 2, // ref & mask < value & mask D3DCMP_EQUAL = 3, // ref & mask = value & mask D3DCMP_LESSEQUAL = 4, // ref & mask <= value & mask D3DCMP_GREATER = 5, // ref & mask > value & mask D3DCMP_NOTEQUAL = 6, // ref & mask != value & mask D3DCMP_GREATEREQUAL = 7, // ref & mask >= value & mask D3DCMP_ALWAYS = 8, // always TRUE D3DCMP_FORCE_DWORD = 0x7fffffff } D3DCMPFUNC;
STENCIL TEST How (when) to update stencil buffer When stencil test failed SetRenderState(D3DRS_STENCILFAIL, Op); When depth test failed SetRenderState(D3DRS_STENCILZFAIL, Op); When stencil test passed SetRenderState(D3DRS_STENCILPASS,, Op);
STENCIL TEST Op values D3DSTENCILOP_KEEP: don’t change D3DSTENCILOP_ZERO: set to zero D3DSTENCILOP_REPLACE: replace by the ref D3DSTENCILOP_INCRSAT: increase, if > max, set = max D3DSTENCILOP_DECRSAT: decrease, if < 0, set = 0 D3DSTENCILOP_INVERT: invert bit (NOT) D3DSTENCILOP_INCR: increase, if > max, set = 0 D3DSTENCILOP_DECR: decrease, if < 0, set = max
STENCIL TEST Write mask (to protect some bits from being written to) SetRenderState(D3DRS_STENCILWRITEMASK, 0x0000FFFF);
MIRROR - Reflection (see reference book page 138) - Render only within to the mirror surface 1. Render normal objects including the mirror but NOT the reflected copy 2. Clear the stencil buffer to 0 3. Render the mirror to stencil buffer only (not backbuffer), set stencil test to always true, operation to replace, ref = 1 4. Now render the reflected copy with ref = 1, op = equal.
MIRROR Render the mirror // prepare stencil SetRenderState(D3DRS_STENCILENABLE, true); SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); SetRenderState(D3DRS_STENCILREF, 0x1); SetRenderState(D3DRS_STENCILMASK, 0xffffffff); SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff); SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
MIRROR Render ONLY to stencil buffer // disable writes to the depth buffer SetRenderState(D3DRS_ZWRITEENABLE, false); // use a blending trick to disable writes to the back buffer SetRenderState(D3DRS_ALPHABLENDENABLE, true); SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); // … draw mirror // source ⊗ (0,0,0,0) + dest ⊗ (1,1,1,1) = dest // (source = new pixel dest = existing pixel) SetRenderState(D3DRS_ZWRITEENABLE, true);
MIRROR Prepare stencel test to render the reflected mirror // only render when stencil value = 0x1 SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); // do not change the stencil value (we might draw many objects in the // mirror) SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
MIRROR Depth issue The reflected copy is BEHIND the mirror => do not see anything Clear the depth buffer? So, reflected objects MUST be draw last ⇒ Reflected mirror IN FRONT of the mirror … ⇒ Blend Source factor = DESTCOLOR Dest factor = ZERO Final = src ⊗ dest + dst ⊗ (0,0,0,0) = src ⊗ dest ⇒
Clear(0, 0, D3DCLEAR_ZBUFFER, 0, 1.0f, 0); SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
MIRROR Winding issue Object is flipped but the winding order is not => reverse winding SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);