在 OpenGL 中正确使用 stencil_texturing
Posted
技术标签:
【中文标题】在 OpenGL 中正确使用 stencil_texturing【英文标题】:Correctly use stencil_texturing in OpenGL 【发布时间】:2013-05-09 16:03:02 【问题描述】:我正在尝试实现 OpenGL 的 stencil_texturing 扩展作为概念证明。我的显卡最高支持 GL 4.3,所以我可以使用 stencil_texturing。如果需要更多说明,请参阅此处提供的规范:http://www.opengl.org/registry/specs/ARB/stencil_texturing.txt。
所以我的测试目标是在第 0 帧中将颜色缓冲区渲染为纹理,然后在第 1 帧中渲染深度缓冲区,最后在第 2 帧中渲染模板缓冲区。简单的部分完成了,我有了我的颜色和深度缓冲纹理渲染得很好。我的问题在于模板缓冲区,我认为问题出在我缺乏对模板缓冲区的理解(很可能就是这种情况)或者是我对 stencil_texturing 的滥用。我试图在网上找到一些信息,但可用的信息很少。
为了让您了解我在此处渲染的内容,是我当前的帧捕获: Color buffer, Depth buffer, Stencil buffer
所以我对模板缓冲区的设想是只模板化中间三角形,所以中间三角形中的所有内容的值都为 1,纹理的每个部分的值都为 0。我不确定这将如何实现渲染时向上,但我想模板值为 1 的区域将与值为 0 的区域不同。
下面是我的代码。它只是一个测试类,我将其放入为他们制作的框架中。我相信唯一没有定义的是 GLERR(),它基本上调用 glGetError() 来确保一切正确。
typedef struct
GLuint program;
GLuint vshader;
GLuint fshader;
StencilTexturingState;
class TestStencilTexturing : public TestInfo
public:
TestStencilTexturing(TestConfig& config, int argc, char** argv)
:width(config.windowWidth), height(config.windowHeight)
state = (StencilTexturingState*) malloc(sizeof(StencilTexturingState));
~TestStencilTexturing()
destroyTestStencilTexturing();
void loadFBOShaders()
const char* vshader = "assets/stencil_texturing/fbo_vert.vs";
const char* fshader = "assets/stencil_texturing/fbo_frag.fs";
state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
GLERR();
state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
GLERR();
state->program = Link(state->vshader, state->fshader, 1, "inPosition");
GLERR();
glUseProgram(state->program);
void loadTextureShaders()
const char* vshader = "assets/stencil_texturing/tex_vert.vs";
const char* fshader = "assets/stencil_texturing/tex_frag.fs";
state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
GLERR();
state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
GLERR();
state->program = Link(state->vshader, state->fshader, 1, "inPosition");
GLERR();
glUseProgram(state->program);
void destroyTestStencilTexturing()
glUseProgram(0);
glDeleteShader(state->vshader);
glDeleteShader(state->fshader);
glDeleteProgram(state->program);
free(state);
void RenderToTexture(GLuint renderedTexture, int frame)
GLint posId, colId;
GLuint fboId, depth_stencil_rb;
const float vertexFBOPositions[] =
-0.7f, -0.7f, 0.5f, 1.0f,
0.7f, -0.7f, 0.5f, 1.0f,
0.6f, 0.7f, 0.5f, 1.0f,
;
const float vertexFBOColors[] =
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
;
// Load shaders for the FBO
loadFBOShaders();
// Setup the FBO
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glViewport(0, 0, width, height);
// Set up renderbuffer for depth_stencil formats.
glGenRenderbuffers(1, &depth_stencil_rb);
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_rb);
// Depending on the frame bind the 2D texture differently.
// Frame 0 - Color, Frame 1 - Depth, Frame 2 - Stencil
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Create our RGBA texture to render our color buffer into.
if (frame == 0)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
// Create our Depth24_Stencil8 texture to render our depth buffer into.
if (frame == 1)
glEnable(GL_DEPTH_TEST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0);
// Create our Depth24_Stencil8 texture and change depth_stencil_texture mode
// to render our stencil buffer into.
if (frame == 2)
glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
GLERR();
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
printf("There is an error with the Framebuffer, fix it!\n");
GLERR();
// Give the values of the position and color of our triangle to the shaders.
posId = glGetAttribLocation(state->program, "position");
colId = glGetAttribLocation(state->program, "color");
GLERR();
glVertexAttribPointer(posId, 4, GL_FLOAT, 0, 0, vertexFBOPositions);
glEnableVertexAttribArray(posId);
glVertexAttribPointer(colId, 4, GL_FLOAT, 0, 0, vertexFBOColors);
glEnableVertexAttribArray(colId);
// Clear the depth buffer back to 1.0f to draw our RGB stripes far back.
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
if (frame == 2)
glStencilFunc(GL_NEVER, 1, 0xFF); // never pass stencil test
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); // replace stencil buffer values to ref=1
glStencilMask(0xFF); // stencil buffer free to write
glClear(GL_STENCIL_BUFFER_BIT); // first clear stencil buffer by writing default stencil value (0) to all of stencil buffer.
glDrawArrays(GL_TRIANGLES, 0, 3); // at stencil shape pixel locations in stencil buffer replace stencil buffer values to ref = 1
// no more modifying of stencil buffer on stencil and depth pass.
glStencilMask(0x00);
// can also be achieved by glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// stencil test: only pass stencil test at stencilValue == 1 (Assuming depth test would pass.) and write actual content to depth and color buffer only at stencil shape locations.
glStencilFunc(GL_EQUAL, 1, 0xFF);
// Use the Scissors to clear the FBO with a RGB stripped pattern.
glEnable(GL_SCISSOR_TEST);
glScissor(width * 0/3, 0, width * 1/3, height);
glClearColor(0.54321f, 0.0f, 0.0f, 0.54321f); // Red
glClear(GL_COLOR_BUFFER_BIT);
glScissor(width * 1/3, 0, width * 2/3, height);
glClearColor(0.0f, 0.65432f, 0.0f, 0.65432f); // Green
glClear(GL_COLOR_BUFFER_BIT);
glScissor(width * 2/3, 0, width * 3/3, height);
glClearColor(0.0f, 0.0f, 0.98765f, 0.98765f); // Blue
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
GLERR();
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisable(GL_DEPTH_TEST);
GLERR();
// Remove FBO and shaders and return to original viewport.
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteShader(state->vshader);
glDeleteShader(state->fshader);
glDeleteProgram(state->program);
glDeleteFramebuffers(1, &fboId);
glViewport(0, 0, width, height);
GLERR();
void drawFrameTestStencilTexturing(int frame)
GLint posLoc, texLoc;
GLuint renderedTexture;
const GLubyte indxBuf[] = 0, 1, 2, 1, 3, 2;
const float positions[] =
-0.8f, -0.8f,
-0.8f, 0.8f,
0.8f, -0.8f,
0.8f, 0.8f,
;
const float texCoords[] =
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
;
// Allocate and initialize the texture that will be rendered to, and then
// textured onto a quad on the default framebuffer.
glGenTextures(1, &renderedTexture);
// Render to the texture using FBO.
RenderToTexture(renderedTexture, frame);
// Create and load shaders to draw the texture.
loadTextureShaders();
// Draw texture to the window.
glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
posLoc = glGetAttribLocation(state->program, "position");
texLoc = glGetAttribLocation(state->program, "a_texCoords");
glVertexAttribPointer(posLoc, 2, GL_FLOAT, 0, 0, positions);
glEnableVertexAttribArray(posLoc);
glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, texCoords);
glEnableVertexAttribArray(texLoc);
// Draw our generated texture onto a quad.
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indxBuf);
glFlush();
glDeleteTextures(1, &renderedTexture);
GLERR();
void renderTest(int frame)
drawFrameTestStencilTexturing(frame);
private:
StencilTexturingState* state;
const int height, width;
;
RUN_TEST(StencilTexturing, "stencil_texturing", 2);
【问题讨论】:
【参考方案1】:线
glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);
不起作用,GL 启用枚举不是位值,而只是枚举,所以你可能会启用其他东西,或者只是得到一些 GL_INVALID_ENUM 错误,但你没有在此处启用模板测试。
【讨论】:
好的,谢谢,我错了。我现在得到的只是我的灰色背景,而我的纹理应该是黑色的四边形。至少这是朝着正确方向迈出的一步!谢谢:)以上是关于在 OpenGL 中正确使用 stencil_texturing的主要内容,如果未能解决你的问题,请参考以下文章