基于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 类的设计比较简单,源码在完成重构渲染器后给出。

 

转载于:https://www.cnblogs.com/ForEmail5/p/7106257.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值