PDA

View Full Version : Stencil buffer questions



Hylke Donker
01-08-2005, 03:19 AM
Hello
I've just read my OpenGL rebbook about the stencil buffer, but i don't understand much of it.So i thought, let's ask it out here.
First question: What does glStencilFunc do?
I know it compares something, but what does the parameter mask and the parameter ref do?
Second question: How can you know you're writing to the stencil buffer and not the color buffer?
Because, if i', right, the following code makes a rectangular thing in the stencil buffer with ones:

glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glBegin(GL_QUADS);
glVertex2f(-1.0, 0.0);
glVertex2f(0.0, 1.0);
glVertex2f(1.0, 0.0);
glVertex2f(0.0, -1.0);
glEnd();Third question: Why does stencil.c does not have a glFlush() command in the display function, is that why i get such a weird drawing when i render it?

I hope you can answere my questions.
Thanx Hylke

147-2
01-08-2005, 08:35 AM
glStencilFunc uses an already established screen buffer, called the stencil buffer, to establish whether drawing should occur in that pixel. The idea is sorta the same as the depth buffer, except the programmer has more control. The parameter mask dictates what bits of the stencil buffer are to be regarded for the operation. This allows you to set different bit ranges in your stencil buffer for different purposes. The refrence is a refrence value which is used for comparison. A simple example should suffice...

Suppose I have the following four pixels, each with stencil values:
A) 0x00
B) 0x01
C) 0x04
D) 0x08

I set the mask to 0x07 and the refrence value to 0x03 for the draw fuction. I want it to draw all pixels that have a number less than my refrence value. It will draw A B and D. Why will D draw? Quite simple, when the mask is applied, D's stencil value equates to 0x00.

Drawing to the stencil, color, depth or any other buffer is done when that buffer is enabled. I suppose you could use a glGet to find out if the buffer is enabled, but this is costly. I suggest you keep tabs on which buffers you have enabled. If you have a function which may or may not be drawing into a specific buffer, and it needs to know whether it is or not, simply retain the buffer state and pass it to the function.

I hope this has been some help. :)

Hylke Donker
01-09-2005, 02:07 AM
Originally posted by 147-2:
glStencilFunc uses an already established screen buffer, called the stencil buffer, to establish whether drawing should occur in that pixel. The idea is sorta the same as the depth buffer, except the programmer has more control. The parameter mask dictates what bits of the stencil buffer are to be regarded for the operation. This allows you to set different bit ranges in your stencil buffer for different purposes. The refrence is a refrence value which is used for comparison. A simple example should suffice...

Suppose I have the following four pixels, each with stencil values:
A) 0x00
B) 0x01
C) 0x04
D) 0x08

I set the mask to 0x07 and the refrence value to 0x03 for the draw fuction. I want it to draw all pixels that have a number less than my refrence value. It will draw A B and D. Why will D draw? Quite simple, when the mask is applied, D's stencil value equates to 0x00.

Drawing to the stencil, color, depth or any other buffer is done when that buffer is enabled. I suppose you could use a glGet to find out if the buffer is enabled, but this is costly. I suggest you keep tabs on which buffers you have enabled. If you have a function which may or may not be drawing into a specific buffer, and it needs to know whether it is or not, simply retain the buffer state and pass it to the function.

I hope this has been some help. :) Thank you for your reply.
But i still don't understand how what the mask parameter does.
Can you explain what you mean with:

The parameter mask dictates what bits of the stencil buffer are to be regarded for the operation. Sorry for my bad English, but i couldn't figure out what you mean with that with a dictionary.
I first thought that the mask parameter is like:
every value that equals to mask will be 0x0, but because 0x07 and 0x08 are two different values that can't be true.
So if anyone can help me in the right way(in example, give the formula to calculate why the result is 0x0 or something like that).
Thanx Hylke

EDIT:
And another small question: You said the stencil buffer works basicly just like the depth buffer, but how does OpenGL know what value a fragment has, when your drawing(in example) a quad?
Thanx Hylke

zeckensack
01-09-2005, 08:26 AM
Calling glStencilFunc or glStencilOp does not restrict subsequent rendering to the stencil buffer. Color, depth and stencil will always be produced for every pixel, and directed to their own separated buffers.

Originally posted by Hylke Donker:
And another small question: You said the stencil buffer works basicly just like the depth buffer, but how does OpenGL know what value a fragment has, when your drawing(in example) a quad?OpenGL draws to all enabled buffers simultaneously. You can allow/disallow writing to the color buffer with glColorMask. It takes four arguments, one for each channel (rgba).
The depth buffer is controlled with glDepthMask (only on/off), the stencil buffer with glStencilMask (full 8 bit mask).

In your example code, the stencil for every fragment inside the quad is 1. Depth is 0 (Vertex2f implies z=0), but may change during matrix transformations. Buffer contents for depth and stencil that are outside of the quad will not be modified.

Overmind
01-09-2005, 08:27 AM
The stencil mask does basically a bitwise AND operation:
masked_value := buffer_value & mask

That means, every bit that is zero in the mask will be zero, every bit that is one in the mask will taken from the buffer. When writing it is almost the same. Bits that are one in the mask are written to the buffer, bits that are zero are left alone.

For example, if I have a value of 0x09 in the buffer and a mask of 0x07, the effective value in the comparison will be 0x01.

0x09 = 00010001 (in binary)
0x07 = 00001111
---------------
gives: 00000001 == 0x01

When I now write e.g. 0x02 (=00000010 in binary) to the buffer, the final value will be 0x0A (=00010010), because the lower 4 bit are written and the others are left alone.

Regarding the other question:
The value written to the buffer depends on the stencil op. For example, with GL_REPLACE, the reference value is written...

Hylke Donker
01-09-2005, 10:57 AM
In your example code, the stencil for every fragment inside the quad is 1.But how did you know that?Why isn't it (in example) 0x05?


The stencil mask does basically a bitwise AND operation:
masked_value := buffer_value & mask

That means, every bit that is zero in the mask will be zero, every bit that is one in the mask will taken from the buffer. When writing it is almost the same. Bits that are one in the mask are written to the buffer, bits that are zero are left alone.I don't think i understand, because i get a different result:

0x09 = 00010001 replace with zero's
0x07 = 00001111
----------------
0xe = 00001111
0x09 = 00001111 remove ones
0x07 = 00001111
----------------
0x0 = 00000000 So my output is 0x00
what am i doing wrong?

Regarding the other question:
The value written to the buffer depends on the stencil op. For example, with GL_REPLACE, the reference value is written... I understand that, but what i mean is, before all the testing operations.

Overmind
01-10-2005, 12:36 AM
Originally posted by Hylke Donker:

I don't think i understand, because i get a different result:

0x09 = 00010001 replace with zero's
0x07 = 00001111
----------------
0xe = 00001111
0x09 = 00001111 remove ones
0x07 = 00001111
----------------
0x0 = 00000000 So my output is 0x00
what am i doing wrong?Your calculations are not right. You have to do a bitwise AND operation with the mask. 0 & 0 = 0, 1 & 0 = 0, 0 & 1 = 0, 1 & 1 = 1. In your first example, only the last bit is set in both the mask and the value, so it is the only one set in the result, giving 00000001 = 0x01.

I am not sure what you did in the second example. To start with, you have a mistake converting the hex value 0x09 to binary...


I understand that, but what i mean is, before all the testing operations.The value that will be written is determined by the testing operations, there is no value before that. If you mean the value that was in the buffer before writing, it is just the value that was written to the buffer by the last operation (or by the glClear command if it is the first operation).

Hylke Donker
01-16-2005, 10:16 AM
Originally posted by Overmind:
Your calculations are not right. You have to do a bitwise AND operation with the mask. 0 & 0 = 0, 1 & 0 = 0, 0 & 1 = 0, 1 & 1 = 1. In your first example, only the last bit is set in both the mask and the value, so it is the only one set in the result, giving 00000001 = 0x01.

I am not sure what you did in the second example. To start with, you have a mistake converting the hex value 0x09 to binary...
So the result of a bitwise & can only be one, if both starting values are 1?


The value that will be written is determined by the testing operations, there is no value before that. If you mean the value that was in the buffer before writing, it is just the value that was written to the buffer by the last operation (or by the glClear command if it is the first operation).But what are the calculations that detirmine that?

Sorry for being offline such a long time, but i had some things to do for school.
Hylke

Overmind
01-16-2005, 02:36 PM
Originally posted by Hylke Donker:
So the result of a bitwise & can only be one, if both starting values are 1?Exactly.


But what are the calculations that detirmine that?The initial value of the stencil buffer after a glClear(GL_STENCIL_BUFFER_BIT) is by default 0, or whatever value you set using the glClearStencil function.

When you draw something with activated stencil test, the value at every drawn pixel is modified according to the stencil operation set with glStencilOp. You can set 3 operations, the first is executed when the stencil test fails, the second when it passes and the z test fails, the third when both pass...

The possible operations are: GL_KEEP (don't modify the buffer content), GL_ZERO (set it to zero), GL_REPLACE (replace it with the "ref" value of glStencilFunc), GL_INCR (increase it by one), GL_DECR (decrease it by one) and GL_INVERT (invert every bit).

Hylke Donker
01-17-2005, 10:53 AM
Thank you all <u>very much</u>.
I finally understand it now.
Hylke