OpenGL ES 2.0 iOS - 在模板缓冲区中绘制一个矩形,并仅在其内部限制绘图

时间:2015-12-28 20:05:50

标签: ios opengl-es opengl-es-2.0

做好事并帮助某人(我)摆脱他们的痛苦,因为很快就会迎来新年前夜。我正在开发一款iOS应用程序,一本适合孩子的着色书,我之前没有偶然发现OpenGL(更确切地说是OpenGLES 2.0)所以我很有可能在那里找不到的东西#&# 39;实际上我的代码。

其中一项任务是不让画笔溢出用户开始绘画的轮廓。

enter image description here

在阅读并理解了一些OpenGL基础知识之后,我发现使用模板缓冲区是正确的解决方案。这是我的模板缓冲区设置:

glClearStencil(0);

//clear the stencil
glClear(GL_STENCIL_BUFFER_BIT);

//disable writing to color buffer
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );

//disable depth buffer
glDisable(GL_DEPTH_TEST);

//enable writing to stencil buffer
glEnable(GL_STENCIL_TEST);

glStencilFunc(GL_NEVER, 1, 0xFF);

glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

[self drawStencil];

//re-enable color buffer
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

//only draw where there is a 1
glStencilFunc(GL_EQUAL, 1, 1);

//keep the pixels in the stencil buffer
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );

现在,我只想在模板缓冲区中绘制一个正方形,看看我是否可以将绘图仅限制在该正方形上。这是绘制正方形的方法:

- (void)drawStencil
{
// Create a renderbuffer
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];

// Create a framebuffer
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);

// Clear
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);

// Read vertex shader source
NSString *vertexShaderSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"VertexShader" ofType:@"vsh"] encoding:NSUTF8StringEncoding error:nil];
const char *vertexShaderSourceCString = [vertexShaderSource cStringUsingEncoding:NSUTF8StringEncoding];

// Create and compile vertex shader
GLuint _vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(_vertexShader, 1, &vertexShaderSourceCString, NULL);
glCompileShader(_vertexShader);

// Read fragment shader source
NSString *fragmentShaderSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"FragmentShader" ofType:@"fsh"] encoding:NSUTF8StringEncoding error:nil];
const char *fragmentShaderSourceCString = [fragmentShaderSource cStringUsingEncoding:NSUTF8StringEncoding];

// Create and compile fragment shader
GLuint _fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(_fragmentShader, 1, &fragmentShaderSourceCString, NULL);
glCompileShader(_fragmentShader);

// Create and link program
GLuint program = glCreateProgram();
glAttachShader(program, _vertexShader);
glAttachShader(program, _fragmentShader);
glLinkProgram(program);

// Use program
glUseProgram(program);

// Define geometry
GLfloat square[] = {
    -0.5, -0.5,
    0.5, -0.5,
    -0.5, 0.5,
    0.5, 0.5};

//Send geometry to vertex shader
const char *aPositionCString = [@"a_position" cStringUsingEncoding:NSUTF8StringEncoding];
GLuint aPosition = glGetAttribLocation(program, aPositionCString);
glVertexAttribPointer(aPosition, 2, GL_FLOAT, GL_FALSE, 0, square);
glEnableVertexAttribArray(aPosition);

// Draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Present renderbuffer
[context presentRenderbuffer:GL_RENDERBUFFER];
}

如此多的代码并没有任何反应......无论我想要什么,我都可以无情地画出来,而不需要单一的模板测试来阻止我。

我该怎么办?如何检查模板缓冲区内是否有绘制的东西?如果您有任何人丢失拼图,我将很乐意分享代码的任何其他部分。

非常感谢任何帮助!这一直困扰着我一段时间。我将永远为你负债!

更新

我得到轮廓的东西,但我没有使用模板缓冲区。我为每个绘图区域创建了蒙版,并为每个蒙版创建了纹理,我在片段着色器中加载了画笔纹理。当我点击一个区域时,我遍历掩码数组并查看选择了哪一个并绑定了掩码纹理。我将在SO上发表另一篇更合适的标题并在那里解释。

1 个答案:

答案 0 :(得分:3)

分配renderbuffer存储的方式看起来有问题:

[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];

documentation说明了这种方法:

  

宽度,高度和内部颜色缓冲区格式是从可绘制对象的特征派生的。

我理解它的方式,因为你的" drawable object"通常是一个颜色缓冲区,这将创建一个颜色渲染缓冲区。但是在你的情况下你需要一个带有模板格式的渲染缓冲区。我不确定是否有方法在上下文类中使用实用程序方法(文档说明了"覆盖内部颜色缓冲区格式"),但最简单的方法可能只是直接调用相应的OpenGL函数:

glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

如果要将此FBO用于此渲染,则还需要为其创建颜色缓冲区,并将其附加到FBO。否则,你并没有真正产生任何渲染输出。

可能更容易确保默认帧缓冲区具有模板缓冲区,并直接渲染它,而不是创建新的FBO。为此,您可以在设置期间进行此调用,为GLKView派生视图请求模板缓冲区:

[view setDrawableStencilFormat: GLKViewDrawableStencilFormat8];