Окружающая обстановка
Это среда, в которой я работаю:
- OpenGL ES 2.0
- Симулятор iPhone и iPhone 4
- iMac 27 "с использованием NVIDIA GeForce GTX 680MX 2048 МБ
Надеюсь, это поможет.
Проблема
Был поиск высокого и низкого уровня из нескольких источников и нескольких сайтов, включая Stackoverflow, но у него не было рабочего эффекта трафарета.
Что у меня есть это:
Черная «S» - это не многоугольник, а текстура, нарисованная на прямоугольном квадрате такой же ширины и высоты, как фоновое изображение.
Я пытаюсь создать эффект трафарета, когда фон и маленький желтый парень должны быть видны только в том случае, если они находятся внутри этой черной 'S' текстуры.
В моем фрагменте шейдера у меня есть это:
varying lowp vec4 destinationColor;
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
uniform highp float TexScale;
void main()
{
highp vec4 color = texture2D(Texture, TexCoordOut);
if(color.a == 0.0)
{
discard;
}
gl_FragColor = color;
}
Для моей настройки Depth Stencil Buffer я настроил его так:
-(void)setupDepthStencilBuffer
{
GLint width;
GLint height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
glGenBuffers(1, &depthStencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_COMPONENT24_OES, width, height);
NSLog(@"depthStencilBuffer = %d", depthStencilBuffer);
}
Согласно документации Apple (которая, я думаю, устарела):
Обратите внимание, что некоторых вещей, таких как перечисление GL_RGBA, не существует, когда я пытался напечатать его в Xcode (я думаю, что Apple, должно быть, удалила его и сделала его устаревшим).
Я также попробовал способ определения в Apple так называемого буфера «глубина / трафарет» в приведенной выше ссылке, но он дал ту же ошибку ниже.
Приведенный выше код показывает, как вы создадите трафаретный буфер.
В моем методе setupFrameBuffer () я прикрепляю его так:
-(void)setupFrameBuffer
{
GLuint frameBuffer;
glGenBuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
NSLog(@"failed to make complete framebuffer object %x", status);
}
}
Ошибка, которую я получил, когда прикрепляю ее, как показано выше:
не удалось создать полный объект кадрового буфера 8cd6
Для моего метода рендеринга у меня есть это:
-(void)render:(CADisplayLink *)displayLink
{
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearStencil(0);
glEnable(GL_STENCIL_TEST);
// ----------------------------------------
// Don't write to color or depth buffer
// ----------------------------------------
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// ----------------------------------------
// First set the alpha test so that
// fragments greather than threshold
// will pass thus will set nonzero
// bits masked by 1 in stencil
// ----------------------------------------
glStencilFunc(GL_ALWAYS, 1, 1);
// ----------------------------------------------------------------
// Drawing our stencil
// ----------------------------------------------------------------
glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, stencilTexture);
glUniform1i(textureUniform, 0);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));
glDrawElements(GL_TRIANGLE_FAN, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);
/*
// -----------------------------------------
// Second pass of the fragments less
// or equal than the threshold will pass
// thus will set zero bits masked by 1
// in stencil
// -----------------------------------------
glStencilFunc(GL_ALWAYS, 0, 1);
glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, stencilTexture);
glUniform1i(textureUniform, 0);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));
glDrawElements(GL_TRIANGLE_STRIP, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);
*/
// ---------------------------------------------------
// RE-ENABLING THE COLOR AND DEPTH MASK AGAIN
// TO DRAW REST OF THE SCENE AFTER STENCIL
// ---------------------------------------------------
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
Mat4 frustrumMatrix = [CameraMatrix createOrthographicMatrixUsingLeft:-(self.bounds.size.width / 2.0)
Right:(self.bounds.size.width / 2.0)
Bottom:-(self.bounds.size.height / 2.0)
Top:(self.bounds.size.height / 2.0)
Near:-1.0f
Far:1.0f];
glUniformMatrix4fv(projectionUniform, 1, 0, frustrumMatrix.matrix);
glViewport(0, 0, self.bounds.size.width * self.contentScaleFactor, self.bounds.size.height * self.contentScaleFactor);
// ----------------------------------------------------------------
// Drawing our background first
// ----------------------------------------------------------------
glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bgTexture);
glUniform1i(textureUniform, 0);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));
glDrawElements(GL_TRIANGLE_FAN, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, floorTexture);
glUniform1i(textureUniform, 0);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));
glDrawElements(GL_TRIANGLE_FAN, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
Результатом этого, очевидно, является розовый экран, который означает, что мои настройки неверны:
Кто-нибудь может пролить свет, пожалуйста?
источник
Ответы:
Решение
Черт возьми да !!!
Я один счастливый парень сейчас! : D
Хорошо, мне наконец-то удалось заставить Stencil работать с текстурой :)
(также узнал много вещей по пути, например, мы можем проверить color.alpha и использовать сброс как способ удаления прозрачного пикселя, а трюк glBlend (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) устарел)
Итак, первое, что я заметил, что сделал неправильно, это неправильно сгенерировал имена для моего буфера трафарета.
В приведенном выше исходном коде в моем вопросе я набрал:
Это действительно должно быть:
d'ах!
Во-вторых, я прокомментировал важный второй glStencilFunc (), который нужно было вызвать:
Конечный результат:
Надеюсь, что это поможет всем, кто пробует этот крутой трафарет с функцией текстуры: D
Я также изменил ряд других исходных кодов, но эти два были основными изменениями, которые заставили его работать.
Некоторые полезные изменения также помогли мне отладить проблему:
Новый метод setupFrameBuffer ():
источник