Lingkungan Hidup
Ini adalah lingkungan tempat saya bekerja:
- OpenGL ES 2.0
- iPhone Simulator & iPhone 4
- iMac 27 "menggunakan NVIDIA GeForce GTX 680MX 2048 MB
Semoga itu bisa membantu.
Masalah
Telah mencari tinggi dan rendah dari berbagai sumber dan beberapa situs termasuk Stackoverflow tetapi belum ada efek stensil yang berfungsi.
Apa yang saya miliki adalah ini:
Benda hitam 'S' bukan poligon tetapi tekstur yang digambar di atas segi empat yang memiliki lebar dan tinggi yang sama dengan gambar latar belakang.
Saya mencoba untuk melakukan efek stensil di mana latar belakang dan orang kuning kecil seharusnya hanya terlihat jika itu dalam tekstur 'S' hitam itu.
Dalam shader fragmen saya, saya punya ini:
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;
}
Untuk penyetelan Depth Stencil Buffer setup saya, saya telah mengaturnya seperti ini:
-(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);
}
Menurut dokumentasi Apple (yang menurut saya sudah ketinggalan zaman):
Perhatikan beberapa hal seperti GL_RGBA enum tidak ada ketika saya mencoba mengetiknya di Xcode (saya pikir Apple harus menghapusnya dan membuatnya usang).
Saya juga telah mencoba cara Apple untuk mendefinisikan apa yang disebut "kedalaman / stensil" buffer di tautan di atas tetapi itu memberikan kesalahan yang sama di bawah ini.
Kode yang saya miliki di atas adalah bagaimana Anda akan membuat buffer stensil.
Dalam metode setupFrameBuffer () saya, saya lampirkan seperti ini:
-(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);
}
}
Kesalahan yang saya dapatkan ketika saya lampirkan seperti yang ditunjukkan di atas adalah:
gagal membuat objek framebuffer lengkap 8cd6
Untuk metode render saya, saya punya ini:
-(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];
}
Hasil dari ini jelas merupakan layar merah muda yang berarti pengaturan saya salah:
Adakah yang bisa menjelaskan?
sumber
Jawaban:
Solusinya
Tentu saja!!!
Saya senang sekali sekarang! : D
OK, saya akhirnya berhasil membuat Stencil bekerja dengan tekstur :)
(juga mempelajari sejumlah hal di sepanjang jalan, misalnya kita dapat memeriksa color.alpha dan menggunakan discard sebagai cara untuk menghapus piksel transparan dan glBlend (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) trik menjadi usang)
Jadi hal pertama yang saya perhatikan salah adalah membuat nama untuk buffer stensil saya.
Dalam kode sumber di atas dalam pertanyaan saya, saya telah mengetik:
Ini harus benar-benar:
d'oh!
Kedua, saya berkomentar tentang glStencilFunc () kedua yang penting yang perlu dipanggil:
Hasil akhir:
Harapan yang membantu semua orang yang mencoba stensil keren ini dengan fitur tekstur: D
Saya juga memodifikasi sejumlah kode sumber lain tetapi kedua adalah perubahan utama yang membuatnya berfungsi.
Beberapa perubahan bermanfaat membantu saya men-debug masalah juga:
Metode setupFrameBuffer () baru:
sumber