ios - OpenGL ES 2.0 iOS - 将矩形绘制到模板缓冲区中并限制仅在其中绘制

标签 ios opengl-es opengl-es-2.0

做一件好事,帮助某人(我)摆脱痛苦,因为马上就是除夕了。我正在开发一个 iOS 应用程序,这是一本 child 图画书,我以前没有偶然发现 OpenGL(更准确地说是 OpenGLES 2.0),所以很有可能我的代码中没有真正得到一些东西。

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

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];
}

这么多的代码,什么也没有发生……我可以在任何我想画的地方不懈地画画,而没有一个模板测试会阻止我。

我能做什么?我如何检查模板缓冲区中是否绘制了某些内容?如果你们中的任何人有任何遗漏的难题,我很乐意分享代码的任何其他部分。

非常感谢任何帮助!这已经折磨了我一段时间了。我将永远欠你的债!

更新

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

最佳答案

您分配渲染缓冲区存储的方式看起来有问题:

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

documentation说到这个方法:

The width, height, and internal color buffer format are derived from the characteristics of the drawable object.

按照我的理解,由于您的“可绘制对象”通常是一个颜色缓冲区,因此这将创建一个颜色渲染缓冲区。但是在您的情况下,您需要一个带有模板格式的渲染缓冲区。我不确定是否有办法在上下文类中使用实用方法来做到这一点(文档中有关于“覆盖内部颜色缓冲区格式”的内容),但最简单的方法可能是直接调用相应的 OpenGL 函数:

glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

如果你想为这个渲染使用你自己的 FBO,你还需要为它创建一个颜色缓冲区,并将它附加到 FBO。否则你不会真正产生任何渲染输出。

与其创建一个新的 FBO,不如确保默认的帧缓冲区有一个模板缓冲区,并直接渲染到它可能更容易。为此,您可以通过在设置期间进行以下调用,为您的 GLKView 派生 View 请求模板缓冲区:

[view setDrawableStencilFormat: GLKViewDrawableStencilFormat8];

关于ios - OpenGL ES 2.0 iOS - 将矩形绘制到模板缓冲区中并限制仅在其中绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34499981/

相关文章:

ios - 生成烛条 View 但不显示

ios - Swift OpenGL ES 应用程序模板?

android - 参数对 GLES20.glViewport(0, 0, width, height) 意味着什么?

opengl-es-2.0 - 用于 Nvidia Tegra 的 OpenGL ES 2.0 离线着色器编译器

ios - 内存警告释放 View Controller ?

iphone - 将变量从一个 View 转移到另一个 View

ios - 将 NSMutable 数组从一个 View 传递到另一个 View

opengl - GLSL 变量默认初始化为什么值?

opengl-es - 多边形的分割和三角剖分

c++ - 恢复 OpenGL 状态