×
Menu

NiStencilProperty lesson zero

Также см. здесь.
Небольшой Урок от уважаемого Greatness7.
в целом повторяет теорию, но применительно МВ.
draw mode there is backface culling basically
CCW = normal, CW = draw backface, Both = both
 
its pretty simple, just each plane sets a specific value for its pixels stencil buffer, and then each object inside the cube is associated to the plane that matches its color and will only render if its pixels stencil buffer matches the specified value
e.g. the blue plane sets all its pixels to 777 and the blue cone simply does TEST_EQUAL 777 (здесь используется в качестве рандомно взятого триггера)
i shouldve made that dwemer mod with the magic door using this technique
but i was too newbie back then

i can explain further if some part is confusing
 
Stencil Test Function
    This is the comparison function used to compare the current stencil value against the 'Stencil Ref' value
    TEST_NEVER: Always False
    TEST_LESS: ref < current
    TEST_EQUAL: ref == current
    TEST_LESSEQUAL: ref <= current
    TEST_GREATER: ref > current
    TEST_GREATEREQUAL: ref >= current
    TEST_ALWAYS: ref == current
 
Stencil Action:
    This is the actions that can be performed after the test function has taken place.
    ACTION_KEEP: Keep the current stencil value
    ACTION_ZERO: Overwrite current stencil value with 0
    ACTION_REPLACE: Replace current stencil value with Stencil Ref
    ACTION_INCREMENT: Increase current stencil value by 1
    ACTION_DECREMENT: Decrease current stencil value by 1
    ACTION_INVERT: Bit-wise invert the current stencil value
 
Stencil Ref
    -- This the ref value used by the test function
Stencil Mask
    -- A mask that can be used to narrow the testing to onlys pecific bits (dont worry about it for now, leave at default)
Pass Action
    -- The action to be taken if the test result was True.
Pass Z Fail Action
    -- The action to be taken if the test result was True, but the Z (depth) test was False.
Fail Action
    -- The action to be taken if the test result was False.
 
so the way it works is
there is a stencil buffer that holds a unique value for every pixel on screen
when your object with a NiStencilProperty gets drawn in game, every pixel it occupies in screen space will perform a stencil test
so for every pixel that your object is occupying, it goes one by and and does the Stencil Function test on the pixels current value against the Stencil Ref value supplied in your nif
And if that function returns False then the object will be hidden, and afterwards it will perform Stencil Action on the current stencil buffer value for that pixel
so lets pretend you had this setting
First it sees: Stencil Enabled is true (e..g it is not 0)
so it knows it needs to perform stencil testing
so next it will go over every pixel that your object is occupying on the screen
and it will do TEST_NOT_EQUAL on that pixels stencil buffer value
so it does: result = (currentValue != StencilRef)
and our StencilRef is 0
and if result was True (e.g. the current value was not 0)
then the object will be rendered as usual
but if result was False, then the object will be hidden
making any sense so far?
 
ok so lets pretend you have a mesh like this
a cube here with a stencil property
and Stencil Enabled is 1, so it will perform stencil testing
Stencil Function is ALWAYS
this means that test always returns True
so our object should show up in game as normal
and it does
so now we try setting it to TEST_NEVER
and that would meant the test alwasy returns False, so the object gets hidden
and indeed it goes away
making sense so far? :smile:
next we can do more advanced test
alright so so far we only did
TEST_ALWAYS and TEST_NEVER
ALWAYS == always True (so the test never fails and the object never gets hidden)
NEVER == always False (so the test always fails and the object is always hidden)
but these tests arent very useful, so instead lets do some tests with TEST_EQUAL
so with TEST_EQUAL it will test against the specific value supplied as Stencil Ref
we can put what ever value we want there
so lets put value 777
yea i just picked 777 randomly
it can be anything
so now we have this value 777 and TEST_EQUAL
assuming all our stencil buffer starts at 0
whent his object gets rendered
it will go over every pixel and and check if the pixels value is == 777
so since all our buffer is just 0 atm
0 == 777 will be False
and so object will get hidden just like TEST_NEVER
make sense?
dont worry about Stencil Mask for now
that is more advanced programmer stuff
leave it at its default value
for now doing simple form
the current stencil buffer always starts at all 0
and since we are testing each pixel vs 777
0 == 777 is False! so object gets hidden
so now the cool part comes in
we can use a second stencil property on a different object
to change 0 to 777
so then we compare 777 == 777 and get True instead of False
so lets make a clip and showcase
stencil buffer is a  buffer holding the current values for every pixel
it starts at 0 by default
it will only be not zero if we change it using a Stencil Action which i will explain
well they a rent the same
stencil ref is a specific value supplied in the NIF
stencil buffer is unique values for every pixel, that is supplied by game engine
ok so the Cube ATM has this values
and our stencil buffer is starting at 0 and 0 EQUAL 777 is always resulting in False
so what we want to do is make some pixels stencil buffer value be 777
so that then our cube will test 777 == 777 and it will draw on those pixels
to do this we can use another object
ok
so we wanted to make some of our pixels stencil values equal to 777
the way we did it is by using the sphere mesh
so it does
TEST_NEVER so its own test is always False and so the sphere will be hidden
and then it uses a Fail Action
Fail Action happen when the stencil test failed (when it was False)
since ours is set to TEST_NEVER it always fails every test, and so it always does ACTION_REPLACE
and what ACTION_REPLACE does is explained bove
 
Stencil Action:
    This is the actions that can be performed after the test function has taken place.
    ACTION_KEEP: Keep the current stencil value
    ACTION_ZERO: Overwrite current stencil value with 0
    ACTION_REPLACE: Replace current stencil value with Stencil Ref
    ACTION_INCREMENT: Increase current stencil value by 1
    ACTION_DECREMENT: Decrease current stencil value by 1
    ACTION_INVERT: Bit-wise invert the current stencil value
 
Replace current stencil value with Stencil Ref
so every pixel that this sphere occupies, it sets those pixels stencil buffer values to 777
make sense?
so pretend this was our stencil buffer
 
000 000 000 000 000 000
000 000 000 000 000 000
000 000 000 000 000 000
000 000 000 000 000 000
000 000 000 000 000 000
000 000 000 000 000 000
 
when the game started
all values were zero
 
each 000 here represents a pixel on the screen
next, the sphere gets drawn
and it is set to ACTION_REPLACE and 777
 
000 000 000 000 000 000
000 000 777 777 000 000
000 777 777 777 777 000
000 777 777 777 777 000
000 000 777 777 000 000
000 000 000 000 000 000
 
so now our buffer looks like this
 
every pixel that the sphere occupied has been replaced with 777
and now next the Cube gets created
and it has its own stencil function
TEST_EQUAL and 777
so it tests each pixel for X == 777
and if that test was True it draws its pixel
so now the Cube is only drawn when looking through the sphere's pixels!
 
my crappy drawing :smile:
the cube will only be shown on the pixels that the sphere set to 777
make sense?
so now you understand the core of stencil buffer :smile:
it can be used for lots of neat tricks!