zoukankan      html  css  js  c++  java
  • 基于OpenGL编写一个简易的2D渲染框架-13 使用例子

     

    这是重构渲染器的最后一部分了,将会给出一个 demo,测试模板测试、裁剪测试、半透明排序等等:

    上图是本次 demo 的效果图,中间的绿色图形展现的是模板测试。

    模板测试

    void init(Pass*& p1, Pass*& p2)
    {
        p1 = new Pass;
        p2 = new Pass;
    
        Shader* s1 = new Shader("Shader/defaultGeometryShader.vs", "Shader/defaultGeometryShader.frag", CVA_V3F_C4F);
        Shader* s2 = new Shader("Shader/defaultGeometryShader.vs", "Shader/defaultGeometryShader.frag", CVA_V3F_C4F);
    
        p1->enableBlend(true);
        p2->enableBlend(true);
    
        p1->setBlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, BLEND_ONE, BLEND_ZERO);
        p2->setBlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, BLEND_ONE, BLEND_ZERO);
    
        p1->setShader(s1);
        p2->setShader(s2);
    
        p1->setPrimType(PT_TRIANGLES);
        p2->setPrimType(PT_TRIANGLES);
    
        p1->enableStencilTest(true);
        p1->setStencilMask(0xFF);
        p1->setStencilCompareFunc(COMPARE_ALWAYS);
        p1->setStencilRef(1);
        p1->setStencilOp(STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_REPLACE);
    
        p2->enableStencilTest(true);
        p2->setStencilMask(0xFF);
        p2->setStencilCompareFunc(COMPARE_EQUAL);
        p2->setStencilRef(1);
        p2->setStencilOp(STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_REPLACE);
    }

    使用模板测试需要两个 Pass,第一个 Pass 绘制圆的时候,把圆范围内的模板值设置为 1,。在时候 p1 绘制好圆后,再使用第二个 pass 绘制两个波纹效果的图形,这时的 pass 设置比较函数为等于,即只有模板值等于 1 的像素才不会被抛弃:

    /* 模板测试 */
    void stencilTest(GraphicsContext* gc, Canvas2D* canvas, Pass* p1, Pass* p2)
    {
        static float d = 0;
        static float d1 = 0;
        static float h = 0;
    
        Vec2 vs1[23];
        Vec2 vs2[23];
    
        gc->render();
        canvas->setCustomPass(p1);
        canvas->fillCircle(Vec3(400, 300, 0), 100, 360, Color(1, 1, 1, 0));
        gc->render();
    
        canvas->setCustomPass(p2);
    
        float hz = 20;
        vs1[0].set(500, 200);
        vs1[1].set(300, 200);
        for ( int i = 0; i <= hz; i++ ) {
            float y = sinf(i / hz * PI_2 + d + i / hz * 2);
    
            vs1[i + 2].set(300 + i / hz * 200, y * 15 + 200 + h);
        }
        canvas->fillPath(vs1, 23, Color(0, 1, 0, 0.5));
    
        
        vs2[0].set(500, 200);
        vs2[1].set(300, 200);
        for ( int i = 0; i <= hz; i++ ) {
            float y = sinf(i / hz * PI_2 + d1 + i / hz * 3);
    
            vs2[i + 2].set(300 + i / hz * 200, y * (10 + i / hz * 10) + 200 + h);
        }
        canvas->fillPath(vs2, 23, Color(0, 1, 0, 0.7));
    
        gc->render();
        canvas->setCustomPass(nullptr);
    
        h += 0.08;
        if ( h > 200 ) {
            h = 0;
        }
    
        d += 0.01;
        if ( d >= PI_2 ) d = 0;
        d1 += 0.02;
        if ( d1 >= PI_2 ) d1 = 0;
    }

    最终的效果:

    和迅雷的悬浮球显示下载进度的效果相差不多。

    裁剪测试

    在使用裁剪测试时,使用一种粒子效果作为测试对象。粒子会拖出一条长长的尾巴,碰到窗口边缘时反弹。四条绿线围成的矩形为裁剪区域,粒子在矩形区域外的部分不会被显示出来。代码实现:

        ParticleSystem* ball = new ParticleSystem();
        ball->initWithPlist("Particle/motion.plist");
        ball->setTexture("Particle/fire.png");
        ball->getEmitter()->setEmitPos(Vec2(400, 300));
    
        Pass* pass = ball->getPass();
        pass->enableScissor(true);
        pass->setScissorRect(100, 100, 600, 400);
    
        ParticleSystemManager manager;
        manager.appendParticleSystem(ball);

    先创建一个粒子系统,实现拖尾的粒子效果。然后获取粒子系统的 Pass 对象(每个粒子系统都会有一个 pass 对象),开启裁剪测试,随机给出一个裁剪区域,初始化到此结束。

    /* 裁剪测试 */
    void scissorTest(ParticleSystem* ps, Canvas2D* canvas)
    {
        static float x = 400, y = 300;
        static int xdir = 1, ydir = 1;
        static float clipx1 = 0, clipy1 = 0, clipx2 = 800, clipy2 = 600;
        static int clipdx = 1, clipdy = 1;
    
        ps->getEmitter()->setEmitPos(Vec2(x, y));
        int speed = 2.5;
        x -= xdir * speed;
        y -= ydir * speed;
        if ( x < 0 ) {
            xdir = -1;
        }
        else if ( x > DEFAULT_WIN_W ) {
            xdir = 1;
        }
        if ( y < 0 ) {
            ydir = -1;
        }
        else if ( y > DEFAULT_WIN_H ) {
            ydir = 1;
        }
    
        clipx1 += clipdx * 0.5f;
        clipx2 -= clipdx * 0.5f;
        clipy1 += clipdy * 0.5f;
        clipy2 -= clipdy * 0.5f;
        if ( clipx1 >= 150 ) {
            clipdx = -1;
        }
        else if ( clipx1 <= 0 ) {
            clipdx = 1;
        }
        if ( clipy1 >= 150 ) {
            clipdy = -1;
        }
        else if ( clipy1 <= 0 ) {
            clipdy = 1;
        }
        canvas->drawLine(0, clipy1, DEFAULT_WIN_W, clipy1, Color(0, 1, 0, 1));
        canvas->drawLine(clipx1, 0, clipx1, DEFAULT_WIN_H, Color(0, 1, 0, 1));
    
        canvas->drawLine(0, clipy2, DEFAULT_WIN_W, clipy2, Color(0, 1, 0, 1));
        canvas->drawLine(clipx2, 0, clipx2, DEFAULT_WIN_H, Color(0, 1, 0, 1));
        ps->getPass()->setScissorRect(clipx1, clipy1, clipx2 - clipx1, clipy2 - clipy1);
    }

    每一帧,都移动四条绿线,实现裁剪区域的变化。在改变裁剪区域后,要更新 pass 的裁剪区域。作为对比,还加入了火焰的粒子效果(没有对 pass 做任何的更改),火焰跟随鼠标的位置移动。

    半透明图形排序

    这个主要在绘制图形的时候设置深度值即可:

            for ( int i = 0; i < 10; i++ ) {
                int x = 20 + i * 20;
                int y = 20 + i * 20;
                if ( i < 5 ) {
                    canvas.fillRect(x, y, x + 100, y + 100, Color(0.2 * i, 0, 0, 0.1 + 0.1 * i), i);
                }
                else {
                    canvas.fillRect(x, y, x + 100, y + 100, Color(0, 0, 0.2 * i, 0.1 * i), i);
                }
            }

    fillRect 函数的最后一个参数就是深度值(渲染器中就是根据深度值 depth 进行排序的),数值小的先被绘制。

  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/ForEmail5/p/7112638.html
Copyright © 2011-2022 走看看