OpenGL利用模板測試實現不規則裁剪


本文是原創文章,如需轉載,請注明文章出處

 

在游戲開發中,經常會有這樣的需求:給定一張64x64的卡牌素材,要求只顯示以圖片中心為圓點、直徑為64的圓形區域,這就要用到模板測試來進行不規則裁剪。

實現不規則裁剪的主要思路如下:

1.准備好素材:要顯示的64x64圖片一張,不規則形狀的遮罩圖一張(本例中為圓形圖)。

2.打開alpha測試,將測試通過條件設置成>0.5,使遮罩圖中心的圓形區域可以通過測試,周圍的透明像素無法通過測試。

3.打開模板測試,將測試通過條件設置成GL_NEVER,並將測試失敗的模板值設置成參考值。

4.清除模板緩沖區,設置成0。

5.繪制遮罩圖,首先alpha測試只允許遮罩圖中心的圓形區域通過,隨后進行模板測試,全部失敗后,圓形區域的模板緩沖區的值被替換成參考值。

6.關閉alpha測試,重新設置模板測試通過條件成GL_EQUAL,值為之前替換的參考值。

7.繪制64x64的原圖,此時只有圓形區域的模板緩沖區的值是參考值能通過模板測試,其他的都是0無法通過測試,實現了裁剪。

最終效果:

 

以下代碼使用以上思路實現了矩形裁剪:

#include "stdafx.h"
#include <glut.h>

#define viewWidth 800
#define viewHeight 800
GLubyte quad[viewWidth][viewHeight][4];
GLuint quadTexName;
const GLint stencilRef = 0x01;
const GLint stencilClear = 0x00;

void createQuad(void)
{
    int i, j;
    for (i = 0; i < viewWidth; ++i){
        for (j = 0; j < viewHeight; ++j){
            quad[i][j][0] = (GLubyte)255;
            quad[i][j][1] = (GLubyte)255;
            quad[i][j][2] = (GLubyte)255;
            if (i < (viewWidth / 2 + 100) && i >(viewWidth / 2 - 100) && j < (viewHeight / 2 + 100) && j >(viewHeight / 2 - 100)){
                quad[i][j][3] = (GLubyte)255;
            }
            else{
                quad[i][j][3] = (GLubyte)0;
            }
        }
    }
}

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearStencil(stencilClear);
    glShadeModel(GL_FLAT);

    createQuad();

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glGenTextures(1, &quadTexName);
    glBindTexture(GL_TEXTURE_2D, quadTexName);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)viewWidth, (GLsizei)viewHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, quad);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glStencilFunc(GL_NEVER, stencilRef, 0xFF);
    glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
    glAlphaFunc(GL_GREATER, 0.5);

    glEnable(GL_STENCIL_TEST);
    glEnable(GL_ALPHA_TEST);
    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, quadTexName);

    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(-10.0, -10.0);
    glTexCoord2f(0.0, 1.0); glVertex2f(-10.0, 10.0);
    glTexCoord2f(1.0, 1.0); glVertex2f(10.0, 10.0);
    glTexCoord2f(1.0, 0.0); glVertex2f(10.0, -10.0);
    glEnd();
    
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_ALPHA_TEST);

    glStencilFunc(GL_EQUAL, stencilRef, 0xFF);
    glBegin(GL_QUADS);
    glColor3f(0.5, 0.5, 0.5);
    glVertex2f(-10.0, -10.0);
    glVertex2f(-10.0, 10.0);
    glVertex2f(10.0, 10.0);
    glVertex2f(10.0, -10.0);
    glEnd();
    glFlush();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    gluOrtho2D(-10, 10, -10, 10);
}

int _tmain(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(viewWidth, viewHeight);
    glutCreateWindow("Stencil Test");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}
View Code

最終效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM