基于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();
p1->setStencilOp(STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_REPLACE); p2->enableStencilTest(true);
p2->setStencilMask(0xFF);
p2->setStencilCompareFunc(COMPARE_EQUAL);
p2->setStencilRef();
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 = ;
static float d1 = ;
static float h = ; Vec2 vs1[];
Vec2 vs2[]; gc->render();
canvas->setCustomPass(p1);
canvas->fillCircle(Vec3(, , ), , , Color(, , , ));
gc->render(); canvas->setCustomPass(p2); float hz = ;
vs1[].set(, );
vs1[].set(, );
for ( int i = ; i <= hz; i++ ) {
float y = sinf(i / hz * PI_2 + d + i / hz * ); vs1[i + ].set( + i / hz * , y * + + h);
}
canvas->fillPath(vs1, , Color(, , , 0.5)); vs2[].set(, );
vs2[].set(, );
for ( int i = ; i <= hz; i++ ) {
float y = sinf(i / hz * PI_2 + d1 + i / hz * ); vs2[i + ].set( + i / hz * , y * ( + i / hz * ) + + h);
}
canvas->fillPath(vs2, , Color(, , , 0.7)); gc->render();
canvas->setCustomPass(nullptr); h += 0.08;
if ( h > ) {
h = ;
} d += 0.01;
if ( d >= PI_2 ) d = ;
d1 += 0.02;
if ( d1 >= PI_2 ) d1 = ;
}
最终的效果:

和迅雷的悬浮球显示下载进度的效果相差不多。
裁剪测试
在使用裁剪测试时,使用一种粒子效果作为测试对象。粒子会拖出一条长长的尾巴,碰到窗口边缘时反弹。四条绿线围成的矩形为裁剪区域,粒子在矩形区域外的部分不会被显示出来。代码实现:
ParticleSystem* ball = new ParticleSystem();
ball->initWithPlist("Particle/motion.plist");
ball->setTexture("Particle/fire.png");
ball->getEmitter()->setEmitPos(Vec2(, )); Pass* pass = ball->getPass();
pass->enableScissor(true);
pass->setScissorRect(, , , ); ParticleSystemManager manager;
manager.appendParticleSystem(ball);
先创建一个粒子系统,实现拖尾的粒子效果。然后获取粒子系统的 Pass 对象(每个粒子系统都会有一个 pass 对象),开启裁剪测试,随机给出一个裁剪区域,初始化到此结束。
/* 裁剪测试 */
void scissorTest(ParticleSystem* ps, Canvas2D* canvas)
{
static float x = , y = ;
static int xdir = , ydir = ;
static float clipx1 = , clipy1 = , clipx2 = , clipy2 = ;
static int clipdx = , clipdy = ; ps->getEmitter()->setEmitPos(Vec2(x, y));
int speed = 2.5;
x -= xdir * speed;
y -= ydir * speed;
if ( x < ) {
xdir = -;
}
else if ( x > DEFAULT_WIN_W ) {
xdir = ;
}
if ( y < ) {
ydir = -;
}
else if ( y > DEFAULT_WIN_H ) {
ydir = ;
} clipx1 += clipdx * 0.5f;
clipx2 -= clipdx * 0.5f;
clipy1 += clipdy * 0.5f;
clipy2 -= clipdy * 0.5f;
if ( clipx1 >= ) {
clipdx = -;
}
else if ( clipx1 <= ) {
clipdx = ;
}
if ( clipy1 >= ) {
clipdy = -;
}
else if ( clipy1 <= ) {
clipdy = ;
}
canvas->drawLine(, clipy1, DEFAULT_WIN_W, clipy1, Color(, , , ));
canvas->drawLine(clipx1, , clipx1, DEFAULT_WIN_H, Color(, , , )); canvas->drawLine(, clipy2, DEFAULT_WIN_W, clipy2, Color(, , , ));
canvas->drawLine(clipx2, , clipx2, DEFAULT_WIN_H, Color(, , , ));
ps->getPass()->setScissorRect(clipx1, clipy1, clipx2 - clipx1, clipy2 - clipy1);
}
每一帧,都移动四条绿线,实现裁剪区域的变化。在改变裁剪区域后,要更新 pass 的裁剪区域。作为对比,还加入了火焰的粒子效果(没有对 pass 做任何的更改),火焰跟随鼠标的位置移动。
半透明图形排序
这个主要在绘制图形的时候设置深度值即可:
for ( int i = ; i < ; i++ ) {
int x = + i * ;
int y = + i * ;
if ( i < ) {
canvas.fillRect(x, y, x + , y + , Color(0.2 * i, , , 0.1 + 0.1 * i), i);
}
else {
canvas.fillRect(x, y, x + , y + , Color(, , 0.2 * i, 0.1 * i), i);
}
}
fillRect 函数的最后一个参数就是深度值(渲染器中就是根据深度值 depth 进行排序的),数值小的先被绘制。

基于OpenGL编写一个简易的2D渲染框架-13 使用例子的更多相关文章
- 基于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渲染框架-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渲染框架-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渲染框架-11 重构渲染器-Renderer
假如要渲染一个纯色矩形在窗口上,应该怎么做? 先确定顶点的格式,一个顶点应该包含位置信息 vec3 以及颜色信息 vec4,所以顶点的结构体定义可以这样: struct Vertex { Vec3 p ...
随机推荐
- C#中Task的使用简单总结
Task在并行计算中的作用很凸显,但是他的使用却有点小复杂,下面是任务的一些基本使用说明(转载与总结于多篇文章) 简单点说说吧! 创建 Task 创建Task有两种方式,一种是使用构造函数创建,另一种 ...
- C#中DateTime的缺陷 ---- 代替品DateTimeOffset
C#中的DateTime在逻辑上有个非常严重的缺陷: > var d = DateTime.Now; > var d2 = d.ToUniversalTime(); > d == d ...
- ActiveMQ默认协议和IO模型优化
在ActiveMQ的官方网站上,列出了目前ActiveMQ中支持的所有消息协议,它们是:AMQP.MQTT.OpenWire.REST.Stomp.XMPP: 不同的协议需要设置不同的网络监听端口,这 ...
- java中<load-on-startup>含义
java中 load-on-startup 含义 java中的 load-on-startup 用于表示该servlet是否在servlet容器启动的时候加载. 示例: <load-on-sta ...
- FQ:从入门到放弃(二)
上次的FQ:从入门到放弃(一)介绍了XXNet的部署和基本使用.本文整理一些部署过程中出现的问题,都是这几天朋友们安装过程中出现的问题.如果覆盖不全,欢迎在博客下方评论,互相交流,互相学习. 不过首先 ...
- 【费马小定理+快速幂取模】ACM-ICPC 2018 焦作赛区网络预赛 G. Give Candies
G. Give Candies There are N children in kindergarten. Miss Li bought them N candies. To make the pro ...
- Ubuntu登录系统失败的解决方案
问题一: 只能用guest用户登录下,如何切换成普通用户登录 解决: 重启,同时按Esc建,直至进入到恢复模式下: 选择第一项,进入: 找到ro...那一行,把ro之后的删除,并把ro修改为rw si ...
- javascript的焦点管理
HTML5也添加了辅助管理DOM焦点的功能. 元素获得焦点的方式有页面加载,用户输入和代码中调用的focus()方法. 而document.activeElement属性保存着当前获得焦点的引用. v ...
- HttpClient上传下载文件
HttpClient上传下载文件 java HttpClient Maven依赖 <dependency> <groupId>org.apache.httpcomponents ...
- Hive基础之Hive环境搭建
Hive默认元数据信息存储在Derby里,Derby内置的关系型数据库.单Session的(只支持单客户端连接,两个客户端连接过去会报错): Hive支持将元数据存储在关系型数据库中,比如:Mysql ...