zoukankan      html  css  js  c++  java
  • 基于OpenGL编写一个简易的2D渲染框架-10 重构渲染器-Pass

      

    Pass,渲染通路,一个渲染通路指的是一次像素处理和一次顶点处理,也就是指的是一次绘制。简单来说就是顶点数据在渲染管线中走一遍最后绘制。

    渲染粒子系统的粒子时,需要开启 OpenGL 的混合模式,并使两个颜色相加。如果同一时间进行多张图片的绘制,并且这些图片的渲染并不需要开启混合模式。这时渲染的最终结果就是图片的渲染出现问题,这并不是我们想要的结果。一个解决方法就是进行两次 draw,第一次开启混合模式渲染粒子系统的粒子,第二次则关闭混合模式渲染图片。

    上面解决方法的实现可以通过两个 Pass 渲染,第一个 Pass 设置开启混模式,第二个 Pass 关闭混合模式,进行两个 Pass 的渲染就可以了。

    Simple2D 的 Pass 设计比较简单,主要实现

      1、裁剪测试、Alpha 测试、模板测试、深度测试和混合模式的设置。

      2、填充模式、面剔除模式、顶点正面方向的设置。

    Pass 的成员属性添加这些测试是否开启的开关量:

    bool bEnableScissor;        /* 裁剪测试 */
    bool bEnableAlphaTest;      /* Alpha 测试 */
    bool bEnableStencilTest;    /* 模板测试 */
    bool bEnableDepthTest;      /* 深度测试 */
    bool bEnableBlend;          /* 混合模式 */
    bool bEnableCullFace;

    接下来就是各种测试的属性变量:

        /* 剔除模式 */
        enum CullMode
        {
            CULL_MODE_BACK,             /* 只剔除背面 */
            CULL_MODE_FRONT,            /* 只剔除正面 */
            CULL_MODE_FRONT_AND_BACK    /* 剔除背面和正面 */
        };
    
        /* 正面的顶点顺序 */
        enum FrontFace
        {
            FRONT_FACE_CLOCK_WISE,            /* 顺时针为正面 */
            FRONT_FACE_COUNTER_CLOCK_WISE,    /* 逆时针为正面 */
        };
    
        /* 填充模式 */
        enum FillMode
        {
            FILL_LINE,        /* 线框 */
            FILL_POINT,       /**/
            FILL_FILL         /* 实体 */
        };
    
        /* 混合方程 */
        enum BlendEquation
        {
            BLEND_ADD,                 /* 彼此元素相加 */
            BLEND_SUNTRACT,            /* 彼此元素相减 */
            BLEND_REVERSE_SUBTRACT     /* 彼此元素相减,但顺序相反 */
        };
    
        /* 混合因子 */
        enum BlendFunc
        {
            BLEND_ZERO,
            BLEND_ONE,
            BLEND_SRC_COLOR,
            BLEND_ONE_MINUS_SRC_COLOR,
            BLEND_DST_COLOR,
            BLEND_ONE_MINUS_DST_COLOR,
            BLEND_SRC_ALPHA,
            BLEND_ONE_MINUS_SRC_ALPHA,
            BLEND_DST_ALPHA,
            BLEND_ONE_MINUS_DST_ALPHA,
            BLEND_CONSTANT_COLOR,
            BLEND_ONE_MINUS_CONSTANT_COLOR,
            BLEND_CONSTANT_ALPHA,
            BLEND_ONE_MINUS_CONSTANT_ALPHA
        };
    
        /* 比较函数 */
        enum CompareFunction
        {
            COMPARE_LESS,          /* 在片段深度值小于缓冲区的深度时通过测试 */
            COMPARE_LEQUAL,        /* 在片段深度值小于等于缓冲区的深度时通过测试 */
    
            COMPARE_GREATER,       /* 在片段深度值大于缓冲区的深度时通过测试 */
            COMPARE_GEQUAL,        /* 在片段深度值大于等于缓冲区的深度时通过测试 */
    
            COMPARE_EQUAL,         /* 在片段深度值等于缓冲区的深度时通过测试 */
            COMPARE_NOT_EQUAL,     /* 在片段深度值不等于缓冲区的深度时通过测试 */
    
            COMPARE_ALWAYS,        /* 永远通过测试 */
            COMPARE_NEVER          /* 永远不通过测试 */
        };
    
        /* 模板操作 */
        enum StencilOp
        {
            STENCIL_OP_KEEP,           /* 不改变,这也是默认值 */
            STENCIL_OP_ZERO,           /* 回零 */
            STENCIL_OP_REPLACE,        /* 使用测试条件中的设定值来代替当前模板值 */
            STENCIL_OP_INCR,           /* 增加1,但如果已经是最大值,则保持不变 */
            STENCIL_OP_INCR_WRAP,      /* 增加1,但如果已经是最大值,则从零重新开始 */
            STENCIL_OP_DECR,           /* 减少1,但如果已经是零,则保持不变 */
            STENCIL_OP_DECR_WRAP,      /* 减少1,但如果已经是零,则重新设置为最大值 */
            STENCIL_OP_INVERT          /* 按位取反 */
        };
            /* 裁剪测试,能够被绘制像素的区域 */
            int nScissorX, nScissorY, nScissorW, nScissorH;
    
            /* Alpha 测试 */
            CompareFunction alphaCompareFunction;
            float fClampRef;
    
            /* 模板测试 */
            CompareFunction stencilCompareFunction;
            unsigned int nStencilMask;
            int nStencilRef;
    
            StencilOp failStencilFailDepth;
            StencilOp passStencilFailDepth;
            StencilOp passStencilPassDepth;
    
            /* 深度测试,比较函数 */
            CompareFunction depthCompareFunction;
    
            /* 混合方程和混合因子 */
            BlendEquation blendEquation;
            BlendFunc blendSrc, blendDst, blendSrcAlpha, blendDstAlpha;

    接下来是设置各个测试的变量值:

    void enableScissor(bool enable) { bEnableScissor = enable; }
    void enableAlphaTest(bool enable) { bEnableAlphaTest = enable; }
    void enableStencilTest(bool enable) { bEnableStencilTest = enable; }
    void enableDepthTest(bool enable) { bEnableDepthTest = enable; }
    void enableBlend(bool enable) { bEnableBlend = enable; }
    void enableCullFace(bool enable) { bEnableCullFace = enable; }
    
    void setFillMode(FillMode fm) { fillMode = fm; }
    void setCullMode(CullMode cm) { cullMode = cm; }
    void setFrontFace(FrontFace ff) { frontFace = ff; }
    
    /* 设置裁剪区域 */
    void setScissorRect(int x, int y, int w, int h) { nScissorX = x; nScissorY = y; nScissorW = w; nScissorH = h; }
    
    void setAlphaCompareFunc(CompareFunction compare) { alphaCompareFunction = compare; }
    void setAlphaClamf(float clamf) { fClampRef = clamf; }
    
    void setStencilCompareFunc(CompareFunction compare) { stencilCompareFunction = compare; }
    void setStencilMask(unsigned int mask) { nStencilMask = mask; }
    void setStencilRef(int ref) { nStencilRef = ref; }
    
    /* 更新模板缓冲操作 */
    void setStencilOp(StencilOp sfail, StencilOp dpfail, StencilOp dppass) {
                failStencilFailDepth = sfail;
                passStencilFailDepth = dpfail;
                passStencilPassDepth = dppass;
    }
    
    /* 设置深度测试比较函数 */
    void setDepthCompareFunc(CompareFunction compare) { depthCompareFunction = compare; }
    
    /* 设置混合操作的混合方程 */
    void setBlendEquation(BlendEquation equation) { blendEquation = equation; }
    
    /* 设置混合模式的混合因子 */
    void setBlendFunc(BlendFunc srcColor, BlendFunc dstColor, BlendFunc srcAlpha, BlendFunc dstAlpha) {
                blendSrc = srcColor; 
                blendDst = dstColor;
                blendSrcAlpha = srcAlpha; 
                blendDstAlpha = dstAlpha;
    }

    上面没有什么好说的,关键的地方在于如何设置 OpenGL 的状态,

        static int toEnum(CullMode cullmode)
        {
            switch ( cullmode ) {
            case Simple2D::CULL_MODE_BACK:              return GL_BACK;
            case Simple2D::CULL_MODE_FRONT:             return GL_FRONT;
            case Simple2D::CULL_MODE_FRONT_AND_BACK:    return GL_FRONT_AND_BACK;
            }
            return GL_BACK;
        }
    
        static int toEnum(FrontFace frontface)
        {
            switch ( frontface ) {
            case Simple2D::FRONT_FACE_CLOCK_WISE:            return GL_CW;
            case Simple2D::FRONT_FACE_COUNTER_CLOCK_WISE:    return GL_CCW;
            }
            return GL_CCW;
        }
    
        static int toEnum(FillMode fillmode)
        {
            switch ( fillmode ) {
            case Simple2D::FILL_LINE:    return GL_LINE;
            case Simple2D::FILL_POINT:   return GL_POINT;
            case Simple2D::FILL_FILL:    return GL_FILL;
            }
            return GL_FILL;
        }
    
        static int toEnum(BlendEquation equation)
        {
            switch ( equation ) {
            case Simple2D::BLEND_ADD:                return GL_FUNC_ADD;
            case Simple2D::BLEND_SUNTRACT:           return GL_FUNC_SUBTRACT;
            case Simple2D::BLEND_REVERSE_SUBTRACT:   return GL_FUNC_REVERSE_SUBTRACT;
            }
            return GL_FUNC_ADD;
        }
    
        static int toEnum(BlendFunc func)
        {
            switch ( func ) {
            case Simple2D::BLEND_ZERO:                       return GL_ZERO;
            case Simple2D::BLEND_ONE:                        return GL_ONE;
            case Simple2D::BLEND_SRC_COLOR:                  return GL_SRC_COLOR;
            case Simple2D::BLEND_ONE_MINUS_SRC_COLOR:        return GL_ONE_MINUS_SRC_COLOR;
            case Simple2D::BLEND_DST_COLOR:                  return GL_DST_COLOR;
            case Simple2D::BLEND_ONE_MINUS_DST_COLOR:        return GL_ONE_MINUS_DST_COLOR;
            case Simple2D::BLEND_SRC_ALPHA:                  return GL_SRC_ALPHA;
            case Simple2D::BLEND_ONE_MINUS_SRC_ALPHA:        return GL_ONE_MINUS_SRC_ALPHA;
            case Simple2D::BLEND_DST_ALPHA:                  return GL_DST_ALPHA;
            case Simple2D::BLEND_ONE_MINUS_DST_ALPHA:        return GL_ONE_MINUS_DST_ALPHA;
            case Simple2D::BLEND_CONSTANT_COLOR:             return GL_CONSTANT_COLOR;
            case Simple2D::BLEND_ONE_MINUS_CONSTANT_COLOR:   return GL_ONE_MINUS_CONSTANT_COLOR;
            case Simple2D::BLEND_CONSTANT_ALPHA:             return GL_CONSTANT_ALPHA;
            case Simple2D::BLEND_ONE_MINUS_CONSTANT_ALPHA:   return GL_ONE_MINUS_CONSTANT_ALPHA;
            }
            return GL_ONE;
        }
    
        static int toEnum(CompareFunction compare)
        {
            switch ( compare ) {
            case Simple2D::COMPARE_LESS:        return GL_LESS;
            case Simple2D::COMPARE_LEQUAL:      return GL_LEQUAL;
            case Simple2D::COMPARE_GREATER:     return GL_GREATER;
            case Simple2D::COMPARE_GEQUAL:      return GL_GEQUAL;
            case Simple2D::COMPARE_EQUAL:       return GL_EQUAL;
            case Simple2D::COMPARE_NOT_EQUAL:   return GL_NOTEQUAL;
            case Simple2D::COMPARE_ALWAYS:      return GL_ALWAYS;
            case Simple2D::COMPARE_NEVER:       return GL_NEVER;
            }
            return GL_LESS;
        }
    
        static int toEnum(StencilOp stencilOp)
        {
            switch ( stencilOp ) {
            case Simple2D::STENCIL_OP_KEEP:         return GL_KEEP;
            case Simple2D::STENCIL_OP_ZERO:         return GL_ZERO;
            case Simple2D::STENCIL_OP_REPLACE:      return GL_REPLACE;
            case Simple2D::STENCIL_OP_INCR:         return GL_INCR;
            case Simple2D::STENCIL_OP_INCR_WRAP:    return GL_INCR_WRAP;
            case Simple2D::STENCIL_OP_DECR:         return GL_DECR;
            case Simple2D::STENCIL_OP_DECR_WRAP:    return GL_DECR_WRAP;
            case Simple2D::STENCIL_OP_INVERT:       return GL_INVERT;
            }
            return GL_KEEP;
        }
        void Pass::setOpenGLState()
        {
            /* 面剔除 */
            if ( bEnableCullFace ) {
                glEnable(GL_CULL_FACE);
                glCullFace(toEnum(cullMode));
                glFrontFace(toEnum(frontFace));
            }
            else {
                glDisable(GL_CULL_FACE);
            }
    
            /* 填充模式 */
            glPolygonMode(GL_FRONT_AND_BACK, toEnum(fillMode));
    
            /* 裁剪测试 */
            if ( bEnableScissor ) {
                glEnable(GL_SCISSOR_TEST);
                /* 左下角为坐标原点 */
                glScissor(nScissorX, nScissorY, nScissorW, nScissorH);
            }
            else {
                glDisable(GL_SCISSOR_TEST);
            }
    
            /* Alpha 测试 */
            if ( bEnableAlphaTest ) {
                glEnable(GL_ALPHA_TEST);
                glAlphaFunc(toEnum(alphaCompareFunction), fClampRef);
            }
            else {
                glDisable(GL_ALPHA_TEST);
            }
    
            /* 模板测试 */
            if ( bEnableStencilTest ) {
                glEnable(GL_STENCIL_TEST);
                glStencilFunc(toEnum(stencilCompareFunction), nStencilRef, nStencilMask);
                glStencilOp(toEnum(failStencilFailDepth), toEnum(passStencilFailDepth), toEnum(passStencilPassDepth));
            }
            else {
                glDisable(GL_STENCIL_TEST);
            }
    
            /* 深度测试 */
            if ( bEnableDepthTest ) {
                glEnable(GL_DEPTH_TEST);
                glDepthFunc(toEnum(depthCompareFunction));
            }
            else {
                glDisable(GL_DEPTH_TEST);
            }
    
            /* 混合模式 */
            if ( bEnableBlend ) {
                glEnable(GL_BLEND);
                glBlendEquation(toEnum(blendEquation));
                glBlendFuncSeparate(toEnum(blendSrc), toEnum(blendDst), toEnum(blendSrcAlpha), toEnum(blendDstAlpha));
            }
            else {
                glDisable(GL_BLEND);
            }
        }

    根据先前设计的类图

    每个 Pass 都有一个 Shader 的成员变量,所以 Pass 类还要添加 Shader 的成员变量,不仅如此,绘制时的图元类型也被设计在 Pass 中:

    PrimType primType;
    Shader* pShader;

    整个 Pass 类的设计比较简单,源码在完成重构渲染器后给出。

  • 相关阅读:
    邀请函|2021 云原生实战峰会,邀请您免费现场参会报名
    Game On Serverless:SAE 助力广州小迈提升微服务研发效能
    说出你和「云原生」的故事,获得年度云原生顶级盛会通行证
    巧用浏览器F12调试器定位系统前后端bug
    测试人员怎样定位bug原因
    mysql删除某个表前100条数据
    设计模式之工厂方法模式
    2021.11.19
    20211117
    JQuery插件集合
  • 原文地址:https://www.cnblogs.com/ForEmail5/p/7106257.html
Copyright © 2011-2022 走看看