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

基于OpenGL编写一个简易的2D渲染框架-10 重构渲染器-Pass的更多相关文章

  1. 基于OpenGL编写一个简易的2D渲染框架-05 渲染文本

    阅读文章前需要了解的知识:文本渲染 https://learnopengl-cn.github.io/06%20In%20Practice/02%20Text%20Rendering/ 简要步骤: 获 ...

  2. 基于OpenGL编写一个简易的2D渲染框架-06 编写一个粒子系统

    在这篇文章中,我将详细说明如何编写一个简易的粒子系统. 粒子系统可以模拟许多效果,下图便是这次的粒子系统的显示效果.为了方便演示,就弄成了一个动图. 图中,同时显示了 7 种不同粒子效果,看上去效果挺 ...

  3. 基于OpenGL编写一个简易的2D渲染框架-01 创建窗口

    最近正在学习OpenGL,我认为学习的最快方法就是做一个小项目了. 如果对OpenGL感兴趣的话,这里推荐一个很好的学习网站 https://learnopengl-cn.github.io/ 我用的 ...

  4. 基于OpenGL编写一个简易的2D渲染框架-08 重构渲染器-整体架构

    事实上,前面编写的渲染器 Renderer 非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求. 当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式.所以同时渲染粒 ...

  5. 基于OpenGL编写一个简易的2D渲染框架-04 绘制图片

    阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 过程简述:利用 FreeI ...

  6. 基于OpenGL编写一个简易的2D渲染框架-09 重构渲染器-Shader

    Shader 只是进行一些简单的封装,主要功能: 1.编译着色程序 2.绑定 Uniform 数据 3.根据着色程序的顶点属性传递顶点数据到 GPU 着色程序的编译 GLuint Shader::cr ...

  7. 基于OpenGL编写一个简易的2D渲染框架-03 渲染基本几何图形

    阅读文章前需要了解的知识,你好,三角形:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ 要 ...

  8. 基于OpenGL编写一个简易的2D渲染框架-02 搭建OpenGL环境

    由于没有使用GLFW库,接下来得费一番功夫. 阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20 ...

  9. 基于OpenGL编写一个简易的2D渲染框架-11 重构渲染器-Renderer

    假如要渲染一个纯色矩形在窗口上,应该怎么做? 先确定顶点的格式,一个顶点应该包含位置信息 vec3 以及颜色信息 vec4,所以顶点的结构体定义可以这样: struct Vertex { Vec3 p ...

随机推荐

  1. Python——面向对象、绑定对象、组合

    1. 面向过程VS面向对象 (1)面向过程 核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的复杂 ...

  2. codevs 1131 统计单词数

    #include<iostream> #include<string> using namespace std; int main() { string s, s0; getl ...

  3. 实验 1 Java 运行环境的安装、配置与运行

    一.实验目的     1. 掌握下载 Java SDK 软件包.     2. 掌握设置 Java 程序运行环境的方法.     3. 掌握编写与运行 Java 程序的方法.     4. 了解 Ja ...

  4. 关于lidroid xUtils 开源项目

    最近搜了一些框架供初学者学习,比较了一下XUtils是目前git上比较活跃 功能比较完善的一个框架,是基于afinal开发的,比afinal稳定性提高了不少,下面是介绍: xUtils简介 xUtil ...

  5. 【VS】使用vs2017自带的诊断工具(Diagnostic Tools)诊断程序的内存问题

    前言 一般来说.NET程序员是不用担心内存分配释放问题的,因为有垃圾收集器(GC)会自动帮你处理.但是GC只能收集那些不再使用的内存(根据对象是否被其它活动的对象所引用)来确定.所以如果代码编写不当的 ...

  6. R语言学习——欧拉计划(1)Multiples of 3 and 5

    [题目一]If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. ...

  7. LBS(基于位置服务)

    ylbtech-杂项:LBS(基于位置服务) 基于位置的服务,它是通过电信移动运营商的无线电通讯网络(如GSM网.CDMA网)或外部定位方式(如GPS)获取移动终端用户的位置信息(地理坐标,或大地坐标 ...

  8. 最近比赛中遇到的几道dp题

    1.2015 icpc 长春-H-Partial Tree(据说是完全背包,但我觉得不像) 一.题意 给定$n$个点,每一个点$i$的权值为关于度数$d_i$的函数$f(d_i),$让你构建一棵树,使 ...

  9. unity3d动态加载dll的API以及限制

    Unity3D的坑系列:动态加载dll 一.使用限制 现在参与的项目是做MMO手游,目标平台是Android和iOS,iOS平台不能动态加载dll(什么原因找乔布斯去),可以直接忽略,而在Androi ...

  10. centos 7 mount usb hard disk(ntfs format)

    1. yum install -y epel-release* 2. yum install -y ntfs-3g 3. 命令:fdisk -l (查看磁盘分区信息) [root@devserverg ...