The stencil buffer doesn't draw a part of the tiles

Well, I’m trying to draw tiles into a stencil buffer, but while drawing obviously happens something what I don’t understand and during the drawing disappearing (not drawn) part of the tiles.
So, how I draw:

// Enable blending.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Enable testing.
glEnable(GL_STENCIL_TEST);

// Disable depth test.
glDisable(GL_DEPTH_TEST);

// Set stencil buff to 0.
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);

// Here I getting all visible tiles by a camera.
auto const visible_tiles = camera.visible_tiles();

// Draw tiles into stencil.
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);

// Don't output the color.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

// ...

// Here I had loop where I go through each tile from all wich was visible for the camera.
auto tile_id = 1;
visible_tiles.for_each_tile([this, &tile_id](auto const& tile_position) {

    // Output tile ID into stencil buffer. I assume there will never be more than
    // 255 tiles.
    glStencilFunc(GL_ALWAYS, tile_id, 0xFF);

    mesh_->draw(); // << Here I draw.

    ++tile_id;
});

// Disable testing.
glDisable(GL_STENCIL_TEST);

If I disable stencil testing at all, everything is OK.
And we draw it correctly.
https://imgur.com/qbqhKtA

glClear() honors:

  1. The pixel ownership test,
  2. the scissor test,
  3. dithering, and
  4. the buffer writemasks

(Update:)

#4 is a cause of confusion. This means if you want to ensure that a glClear() clears the full contents of whatever buffer(s) you’ve requested to clear, you must first open up the buffer writemask(s) for those buffer(s) (see glColorMask(), glDepthMask(), and glStencilMask()). That doesn’t appear to be a problem in your case, as the default state for the writemasks is “write to all bits enabled”, and you’re explicitly setting the stencil mask to 0xFF (and typically there’s only 8 bits of stencil).

Hi, thx for an answer.
My method “draw()” starts from my above simple code,

Layer::draw(...) {
    // Enable blending.
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Enable testing.
    glEnable(GL_STENCIL_TEST);

    // Disable depth test.
    glDisable(GL_DEPTH_TEST);

    // Set stencil buff to 0.
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT); // So if i add glDisable(GL_STENCIL_TEST) what will be? 

    // Here I getting all visible tiles by a camera.
    auto const visible_tiles = camera.visible_tiles();

    // Draw tiles into stencil.
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glStencilMask(0xFF);

    // Don't output the color.
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

    // ...

    // Here I had loop where I go through each tile from all wich was visible for the camera.
    auto tile_id = 1;
    visible_tiles.for_each_tile([this, &tile_id](auto const& tile_position) {

        // Output tile ID into stencil buffer. I assume there will never be more than
        // 255 tiles.
        glStencilFunc(GL_ALWAYS, tile_id, 0xFF);

        mesh_->draw(); // << Here I draw.

        ++tile_id;
    });

    // Disable testing.
    glDisable(GL_STENCIL_TEST);
}

So if i add glDisable(GL_STENCIL_TEST) before glClear() what will be?
Does this make sense?

Sorry, please ignore that part of my response. glClear() honors scissor test, not stencil test (and I need more caffeine this morning :slight_smile: ).

If you want to be sure scissor test isn’t coming into play, you can call glDisable( GL_SCISSOR_TEST ). However, if you’re not using scissor in your program, it’s probably already disabled.

Yeah, I’m not using scissor at all.
So, before glCearStencil and glClear I need to call glStencilMask(0xFF) to open buffer for write?

Yes, but it only needs to be before glClear(). It doesn’t make any difference whether it’s before or after glStencilMask() IIRC.

So, I did the following:

...
// Set stencil buff to 0.
glStencilMask(0xFF);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
...

And nothing has changed ((

Are you doing any other fragment testing? For instance alpha test, depth test, etc. during your frame? If so, try disabling them to ensure that the reason you’re not seeing something is because of them.

Also, I’d disable blending just for good measure. And possibly just draw a quad with a constant color+depth for your tiles. The goal being to cook an example so you can clearly see why it is those regions aren’t being filled.

So, I disabled blending and depth too.
There are no changes.

Ok, LUL.
With the help of the debug, I managed to narrow the circle of suspects )))
And I realized that the problem was somewhere in glEnable(GL_STENCIL_TEST), namely when I repeatedly call my method “draw(…)”.
So, I just did the following:

static bool flag = false;
if (!flag) {
    glEnable(GL_STENCIL_TEST);
    flag = true;
}

So, now I call glEnable(GL_STENCIL_TEST) only once, at first call of draw, and didn’t call glDisable(GL_STENCIL_TEST);
And it looks as if everything works correctly, at least now I didn’t see any defects.
But why this works?

Update, problem solving is still relevant

Only you have all the relevant code, so only you can know for sure.

Does this leave the state of GL_STENCIL_TEST disabled during the 2nd and subsequent calls to your draw() function? After that code you added, add a call to glIsEnabled( GL_STENCIL_TEST ) and see.

If so, then it’s possible that your algorithm assumes that stencil test (and stencil writes) are disabled during your draw() routine, and you just don’t realize it. Or, it’s possible that this is just a fluke and you’ve still got a bug in your code.

Tell us, high level, what you’re trying to accomplish, and how the stencil buffer fits into it. Then describe your render passes, how they use stencil, and what you assume will be happening with your usage of it. Also, show us all the “stencil state tweaking” you’re doing between your render passes.