There is a feeling that I do not fully understand how to work properly with the stencil buffer in OpenGL.
So, what is the point:
In OpenGL, along with the z-buffer there is also a stencil buffer, which allows you to specify which pixels should be dropped and which ones should not. With this piece, you usually make various strokes around objects. I also decided to use this opportunity for this. The algorithm is as follows:
- Draw an object, while writing units to the stencil buffer for each pixel of this object
- Slightly increase the object (so that it is slightly larger than the previous version)
- The stencil function is set up so that only those pixels for which the value in the stencil buffer is not equal to one pass the test
- Draw the object again, in a single color (already enlarged) and as a result we get a frame of this color around the original object.
So it looks like in the code:
In the beginning, when initializing the renderer, I do this. So I set the behavior - what to do with the stencil value if the stencil test is not passed, if the depth test is not passed, if the depth test is passed (I get that the value will be updated only if I pass the depth test and the stencil test)
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); Then, in the very cycle of rendering objects, I do
// о б ъ е к т // Тест будет пройден в любом случае (какое бы значение не было в буфере) // После прохождения теста в буфер будет внесено значение 1 (поведение из glStencilOp) glStencilFunc(GL_ALWAYS, 1, 0xFF); // Матрица модели glm::mat4 mdodelMatrix = light->getModelMatrix(); glUniformMatrix4fv(glGetUniformLocation(solidColorShaderID, "model"), 1, GL_FALSE, glm::value_ptr(mdodelMatrix)); // Передать цвет glUniform3fv(glGetUniformLocation(solidColorShaderID, "lightColor"), 1, glm::value_ptr(light->color)); // Привязать VAO glBindVertexArray(this->defaultGeometry_.cube->getVaoId()); glDrawElements(GL_TRIANGLES, this->defaultGeometry_.cube->getIndexCount(), GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); // о б в о д к а // Тест считается пройденным если в буфере не 1 // После прохождения теста в буфер будет внесено значение 1 (поведение из glStencilOp) glStencilFunc(GL_NOTEQUAL, 1, 0xFF); // Матрица модели (чуть увеличенный вариант) mdodelMatrix = light->getModelMatrix(1.1f); glUniformMatrix4fv(glGetUniformLocation(solidColorShaderID, "model"), 1, GL_FALSE, glm::value_ptr(mdodelMatrix)); // Передать цвет glm::vec3 col = {1.0f,0.68f,0.0f}; glUniform3fv(glGetUniformLocation(solidColorShaderID, "lightColor"), 1, glm::value_ptr(col)); // Привязать VAO glBindVertexArray(this->defaultGeometry_.cube->getVaoId()); glDrawElements(GL_TRIANGLES, this->defaultGeometry_.cube->getIndexCount(), GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); As a result, I get this result: 
That is, object strokes are merged. I would like to achieve a different effect so that the stroke is drawn on top of other objects. As I understand it, this happens because units are always added to the stencil buffer (even if the z-test was not passed), because I do the following before drawing the source object:
glStencilFunc(GL_ALWAYS, 1, 0xFF); But on the other hand, I have already indicated that if the depth test is not passed, then no recording takes place.
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); So why then does he still write to the stencil, ignoring this rule? Is this because of GL_ALWAYS? And how then to adjust so that he wrote to the stencil only if he passed the z-test and not in any case? How much I did not try to make various variations of settings, I still could not get the desired option. Very curious how this can be done. Thank you in advance.