基于opengl编写一个简易的2d渲染框架-13使用例子

为了邮箱5 为了邮箱5     2022-09-06     440

关键词:

 

这是重构渲染器的最后一部分了,将会给出一个 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(1);
    p1->setStencilOp(STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_REPLACE);

    p2->enableStencilTest(true);
    p2->setStencilMask(0xFF);
    p2->setStencilCompareFunc(COMPARE_EQUAL);
    p2->setStencilRef(1);
    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 = 0;
    static float d1 = 0;
    static float h = 0;

    Vec2 vs1[23];
    Vec2 vs2[23];

    gc->render();
    canvas->setCustomPass(p1);
    canvas->fillCircle(Vec3(400, 300, 0), 100, 360, Color(1, 1, 1, 0));
    gc->render();

    canvas->setCustomPass(p2);

    float hz = 20;
    vs1[0].set(500, 200);
    vs1[1].set(300, 200);
    for ( int i = 0; i <= hz; i++ ) {
        float y = sinf(i / hz * PI_2 + d + i / hz * 2);

        vs1[i + 2].set(300 + i / hz * 200, y * 15 + 200 + h);
    }
    canvas->fillPath(vs1, 23, Color(0, 1, 0, 0.5));

    
    vs2[0].set(500, 200);
    vs2[1].set(300, 200);
    for ( int i = 0; i <= hz; i++ ) {
        float y = sinf(i / hz * PI_2 + d1 + i / hz * 3);

        vs2[i + 2].set(300 + i / hz * 200, y * (10 + i / hz * 10) + 200 + h);
    }
    canvas->fillPath(vs2, 23, Color(0, 1, 0, 0.7));

    gc->render();
    canvas->setCustomPass(nullptr);

    h += 0.08;
    if ( h > 200 ) {
        h = 0;
    }

    d += 0.01;
    if ( d >= PI_2 ) d = 0;
    d1 += 0.02;
    if ( d1 >= PI_2 ) d1 = 0;
}

最终的效果:

和迅雷的悬浮球显示下载进度的效果相差不多。

 

裁剪测试

在使用裁剪测试时,使用一种粒子效果作为测试对象。粒子会拖出一条长长的尾巴,碰到窗口边缘时反弹。四条绿线围成的矩形为裁剪区域,粒子在矩形区域外的部分不会被显示出来。代码实现:

 

    ParticleSystem* ball = new ParticleSystem();
    ball->initWithPlist("Particle/motion.plist");
    ball->setTexture("Particle/fire.png");
    ball->getEmitter()->setEmitPos(Vec2(400, 300));

    Pass* pass = ball->getPass();
    pass->enableScissor(true);
    pass->setScissorRect(100, 100, 600, 400);

    ParticleSystemManager manager;
    manager.appendParticleSystem(ball);

 

先创建一个粒子系统,实现拖尾的粒子效果。然后获取粒子系统的 Pass 对象(每个粒子系统都会有一个 pass 对象),开启裁剪测试,随机给出一个裁剪区域,初始化到此结束。

/* 裁剪测试 */
void scissorTest(ParticleSystem* ps, Canvas2D* canvas)
{
    static float x = 400, y = 300;
    static int xdir = 1, ydir = 1;
    static float clipx1 = 0, clipy1 = 0, clipx2 = 800, clipy2 = 600;
    static int clipdx = 1, clipdy = 1;

    ps->getEmitter()->setEmitPos(Vec2(x, y));
    int speed = 2.5;
    x -= xdir * speed;
    y -= ydir * speed;
    if ( x < 0 ) {
        xdir = -1;
    }
    else if ( x > DEFAULT_WIN_W ) {
        xdir = 1;
    }
    if ( y < 0 ) {
        ydir = -1;
    }
    else if ( y > DEFAULT_WIN_H ) {
        ydir = 1;
    }

    clipx1 += clipdx * 0.5f;
    clipx2 -= clipdx * 0.5f;
    clipy1 += clipdy * 0.5f;
    clipy2 -= clipdy * 0.5f;
    if ( clipx1 >= 150 ) {
        clipdx = -1;
    }
    else if ( clipx1 <= 0 ) {
        clipdx = 1;
    }
    if ( clipy1 >= 150 ) {
        clipdy = -1;
    }
    else if ( clipy1 <= 0 ) {
        clipdy = 1;
    }
    canvas->drawLine(0, clipy1, DEFAULT_WIN_W, clipy1, Color(0, 1, 0, 1));
    canvas->drawLine(clipx1, 0, clipx1, DEFAULT_WIN_H, Color(0, 1, 0, 1));

    canvas->drawLine(0, clipy2, DEFAULT_WIN_W, clipy2, Color(0, 1, 0, 1));
    canvas->drawLine(clipx2, 0, clipx2, DEFAULT_WIN_H, Color(0, 1, 0, 1));
    ps->getPass()->setScissorRect(clipx1, clipy1, clipx2 - clipx1, clipy2 - clipy1);
}

每一帧,都移动四条绿线,实现裁剪区域的变化。在改变裁剪区域后,要更新 pass 的裁剪区域。作为对比,还加入了火焰的粒子效果(没有对 pass 做任何的更改),火焰跟随鼠标的位置移动。

 

半透明图形排序

这个主要在绘制图形的时候设置深度值即可:

 

        for ( int i = 0; i < 10; i++ ) {
            int x = 20 + i * 20;
            int y = 20 + i * 20;
            if ( i < 5 ) {
                canvas.fillRect(x, y, x + 100, y + 100, Color(0.2 * i, 0, 0, 0.1 + 0.1 * i), i);
            }
            else {
                canvas.fillRect(x, y, x + 100, y + 100, Color(0, 0, 0.2 * i, 0.1 * i), i);
            }
        }

 

fillRect 函数的最后一个参数就是深度值(渲染器中就是根据深度值 depth 进行排序的),数值小的先被绘制。

 

基于opengl编写一个简易的2d渲染框架-04绘制图片

阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/   过程简述:利用FreeImage库加载图像数据,再创建OpenGL纹理,通过Canvas2D画布绘制,最后又Renderer渲染器渲染   本来想用soil库... 查看详情

基于opengl编写一个简易的2d渲染框架-09重构渲染器-shader

  Shader只是进行一些简单的封装,主要功能:    1、编译着色程序    2、绑定Uniform数据    3、根据着色程序的顶点属性传递顶点数据到GPU   着色程序的编译GLuintShader::createShaderProgram(constchar*vsname,constchar*p... 查看详情

基于opengl编写一个简易的2d渲染框架-05渲染文本

阅读文章前需要了解的知识:文本渲染 https://learnopengl-cn.github.io/06%20In%20Practice/02%20Text%20Rendering/ 简要步骤:获取要绘制的字符的Unicode码,使用FreeType库获取对应的位图数据,添加到字符表中(后面同样的字符可以再表中... 查看详情

基于opengl编写一个简易的2d渲染框架02——搭建opengl环境

由于没有使用GLFW库,接下来得费一番功夫。阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20Creating%20a%20window/ 以下,我摘取了一点片段 Windows上的OpenGL库  如果你是Windows平台,opengl32.l... 查看详情

基于opengl编写一个简易的2d渲染框架-12重构渲染器-blockallocator

 BlockAllocator的内存管理情况可以用下图表示   整体思路是,先分配一大块内存Chunk,然后将Chunk分割成小块Block。由于Block是链表的一个结点,所以可以通过链表的形式把未使用的Block连接起来,并保存到pFreeLists中。当... 查看详情

基于opengl编写一个简易的2d渲染框架-08重构渲染器-整体架构

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

基于opengl编写一个简易的2d渲染框架-11重构渲染器-renderer

 假如要渲染一个纯色矩形在窗口上,应该怎么做?先确定顶点的格式,一个顶点应该包含位置信息vec3以及颜色信息vec4,所以顶点的结构体定义可以这样:structVertex{Vec3position;Vec4color;};然后填充矩形四个顶点是数据信息:Verte... 查看详情

基于opengl编写一个简易的2d渲染框架-07鼠标事件和键盘事件

这次为程序添加鼠标事件和键盘事件   当检测到鼠标事件和键盘事件的信息时,捕获其信息并将信息传送到需要信息的对象处理。为此,需要一个可以分派信息的对象,这个对象能够正确的把信息交到正确的对象。 实... 查看详情

OpenGL 2D像素完美渲染

】OpenGL2D像素完美渲染【英文标题】:OpenGL2Dpixelperfectrendering【发布时间】:2013-12-2115:04:10【问题描述】:我正在尝试渲染2D图像,以便它完全覆盖整个窗口。对于我的测试,我设置了一个窗口,使客户区正好是320x240,纹理也是... 查看详情

基于opengles的深度学习框架编写

基于OpenGLES的深度学习框架编写背景与工程定位背景项目组基于深度学习实现了视频风格化和人像抠图的功能,但这是在PC/服务端上跑的,现在需要移植到移动端,因此需要一个移动端的深度学习的计算框架。同类型的库caffe-andr... 查看详情

将位图/位数组渲染到 2d 平面的最佳方法(使用 OpenGL)

】将位图/位数组渲染到2d平面的最佳方法(使用OpenGL)【英文标题】:Bestwaytorenderabitmap/bitarrayto2dplane(withOpenGL)【发布时间】:2011-03-0520:13:22【问题描述】:好的,这就是我所拥有的。我有一个1d位图(或位数组、位集、位串,但... 查看详情

opengl绘制三角形(代码片段)

...对象:ElementBufferObject,EBO或IndexBufferObject,IBO渲染管线在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由Ope... 查看详情

OpenGL 2d矩形没有被渲染

】OpenGL2d矩形没有被渲染【英文标题】:OpenGL2drectanglenotbeingrendered【发布时间】:2016-12-2200:07:43【问题描述】:我正在尝试在屏幕上渲染一个矩形。程序运行时,只显示清晰的颜色,没有矩形显示。代码如下:glClearColor(0.0,0.0,0.0,... 查看详情

OpenGL:如何在 3d 模式下优化多层相互重叠的 2d 渲染?

】OpenGL:如何在3d模式下优化多层相互重叠的2d渲染?【英文标题】:OpenGL:Howtooptimize2drenderingwithmultiplelayersoverlappingeachotherin3dmode?【发布时间】:2011-06-0612:36:31【问题描述】:我知道如何通过简单地首先渲染最近的平面来加速3d渲... 查看详情

opengl工作流程

  在OpenGL中,一切事物都在3D空间中,但我们的屏幕坐标确实2D像素数组,OpenGL大部分工作就是把3D坐标转换成适应屏幕的2D像素。3D坐标转换成2D屏幕坐标的过程是有OpenGL的图形渲染管线管理的。图形渲染管线的工作可以被划分... 查看详情

opengl-渲染流程

参考技术A在OpenGL中,任何事物都处于3D空间中,而屏幕和窗口却都是2D像素数组,这就导致了OpenGL大部分工作都是关于把3D坐标转变为适配你屏幕的2D像素,3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(指的是一堆原始图... 查看详情

使用 opencl 将软件渲染到 opengl 2d 视图 [关闭]

】使用opencl将软件渲染到opengl2d视图[关闭]【英文标题】:softwarerenderingwithopenclontoopengl2dview[closed]【发布时间】:2011-07-0606:59:44【问题描述】:我想构建一个小的软件渲染库,因为我喜欢体素的想法,以及其他可能的替代渲染方... 查看详情

iOS 中基于矢量的实时 OSM 渲染器(使用 OpenGL ES)

】iOS中基于矢量的实时OSM渲染器(使用OpenGLES)【英文标题】:Realtimevector-basedOSMrendereriniOS(usingOpenGLES)【发布时间】:2013-04-2415:30:09【问题描述】:我正在寻找一种解决方案,它允许使用OpenStreetMap数据在iOS中渲染基于矢量的2D俯... 查看详情