做好事并帮助某人(我)摆脱他们的痛苦,因为很快就会迎来新年前夜。我正在开发一款iOS应用程序,一本适合孩子的着色书,我之前没有偶然发现OpenGL(更确切地说是OpenGLES 2.0)所以我很有可能在那里找不到的东西#&# 39;实际上我的代码。
其中一项任务是不让画笔溢出用户开始绘画的轮廓。
在阅读并理解了一些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上发表另一篇更合适的标题并在那里解释。
答案 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];