基于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 类的设计比较简单,源码在完成重构渲染器后给出。
基于OpenGL编写一个简易的2D渲染框架-10 重构渲染器-Pass的更多相关文章
- 基于OpenGL编写一个简易的2D渲染框架-05 渲染文本
阅读文章前需要了解的知识:文本渲染 https://learnopengl-cn.github.io/06%20In%20Practice/02%20Text%20Rendering/ 简要步骤: 获 ...
- 基于OpenGL编写一个简易的2D渲染框架-06 编写一个粒子系统
在这篇文章中,我将详细说明如何编写一个简易的粒子系统. 粒子系统可以模拟许多效果,下图便是这次的粒子系统的显示效果.为了方便演示,就弄成了一个动图. 图中,同时显示了 7 种不同粒子效果,看上去效果挺 ...
- 基于OpenGL编写一个简易的2D渲染框架-01 创建窗口
最近正在学习OpenGL,我认为学习的最快方法就是做一个小项目了. 如果对OpenGL感兴趣的话,这里推荐一个很好的学习网站 https://learnopengl-cn.github.io/ 我用的 ...
- 基于OpenGL编写一个简易的2D渲染框架-08 重构渲染器-整体架构
事实上,前面编写的渲染器 Renderer 非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求. 当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式.所以同时渲染粒 ...
- 基于OpenGL编写一个简易的2D渲染框架-04 绘制图片
阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 过程简述:利用 FreeI ...
- 基于OpenGL编写一个简易的2D渲染框架-09 重构渲染器-Shader
Shader 只是进行一些简单的封装,主要功能: 1.编译着色程序 2.绑定 Uniform 数据 3.根据着色程序的顶点属性传递顶点数据到 GPU 着色程序的编译 GLuint Shader::cr ...
- 基于OpenGL编写一个简易的2D渲染框架-03 渲染基本几何图形
阅读文章前需要了解的知识,你好,三角形:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ 要 ...
- 基于OpenGL编写一个简易的2D渲染框架-02 搭建OpenGL环境
由于没有使用GLFW库,接下来得费一番功夫. 阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20 ...
- 基于OpenGL编写一个简易的2D渲染框架-11 重构渲染器-Renderer
假如要渲染一个纯色矩形在窗口上,应该怎么做? 先确定顶点的格式,一个顶点应该包含位置信息 vec3 以及颜色信息 vec4,所以顶点的结构体定义可以这样: struct Vertex { Vec3 p ...
随机推荐
- FaceBook: Text Tag Recommendation
Text Tag Recommendation --------2013/12/20 一: 背景 Kaggle上 facebook招聘比赛III. 任务要求是给定文本中抽取关键词.这里称作tag吧. ...
- bat计算两个时间差
这个是脚本代码[保存为etime.bat放在当前路径下即可: 免费内容: :etime <begin_time> <end_time> <return>rem 所测 ...
- vs2013下OpenGL环境的配置
1.下载glut库:https://files.cnblogs.com/files/laoxia/glutdlls37beta.zip 2.解压后,将glut.lib和glut32.lib两个文件拷贝 ...
- zz 牛人啊
http://www.newsmth.net/nForum/#!article/CouponsLife/184517019:57:33cutepig 2015/6/9 19:57:33 http:// ...
- npx 知识点
npx 介绍:https://segmentfault.com/a/1190000010149499
- HTML5 localStorage使用教程
在客户端存储数据,HTML5 提供了两种在客户端存储数据的新方法: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 之前, ...
- C#如何使用VS2010与SQL2008建立链接及初步调用(转)
关于VS2010与SQL2008建立链接及初步调用问题,网上参考的资料很多,我写这个博客,并非是做重复工作,也不是做搬运工.本文将以一种初学者的角度,去完成从数据库建立,到VS2010与SQL中的数据 ...
- WebForm Response和Request以及Cookie
Session:每一台电脑访问服务器,都会是独立的一套session,key值都一样,但是内容都是不一样的 以上所有内容,都跟cookies一样, 内置对象:用于页面之间的数据交互 为什么要使用这么内 ...
- Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充
ylbtech-Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充 1.返回顶部 1. Java 实例 - 数组填充 Java 实例 以下实例我们通过 Java Ut ...
- red hat官方的rhel操作系统版本号与内核版本号的对应关系
原文在如下网址:https://access.redhat.com/articles/3078 The tables below list the major and minor Red Hat En ...