• 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

    最终效果:

  • 相关阅读:
    txt文件按行处理工具类(可以截取小说、分析日志等)【我】
    java正则表达式取出匹配字符串
    svn客户端更改用户名
    Spring集成MyBatis完整示例
    redis的list取出数据方式速度测试
    处理大量数据的性能优化一例【我】
    unity3d结合轮廓显示,实现完整的框选目标(附Demo代码)
    Unity3dPro 和免费版的区别
    unity3d 射线扫描 忽略图层
    Unity3D角色攻击范围判定和攻击判定
  • 原文地址:https://www.cnblogs.com/Pickcle/p/5396186.html
Copyright © 2020-2023  润新知