离屏渲染,OpenGL的三种渲染方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了离屏渲染,OpenGL的三种渲染方式相关的知识,希望对你有一定的参考价值。

参考技术A 一. 离屏渲染触发的原理:APP在对图片进行渲染,合并的时候会触发离屏渲染,离屏渲染流程先把图层保存在帧缓冲区(offscreen Buffer)中,如果这个图层需要进行渲染.合并就会把图层存的数据通过顶点着色器.片元着色器,然后放在离屏缓冲区(offscreenBuffer)中,然后把其他的图层也是按照这种形式进行存储,然后把存放在离屏渲染缓冲区的图片取出来进行合并.渲染。如果不需要做渲染.合并的时候回直接渲染在屏幕上,然后直接从帧缓冲区中移除。而触发离屏渲染的方式有:maks,对图片进行裁剪,对颜色进行透明度的叠加,添加投影,采用光栅画,绘制文字的时候。都会触发离屏渲染。

二.在切圆角的时候。如果你只是设置了 self .type.layer.cornerRadius=2;这个方法不会触发离屏渲染。只有在设置了 self .type.layer.masksToBounds = YES ;这个方法的时候才会触发离屏渲染。因为 如果只设置了第一个方法 只是对layer层做了圆角设置。并没有多图片的内容进行裁剪。所以这个时候不会触发离屏渲染,如下图所示:

三.因为离屏渲染会使用额外的内存空间(离屏渲染缓冲区),所以离屏渲染会有性能问题。会比较容易形成掉帧,offscreenBuffer是有空间限制的(屏幕像素点的2.5),离屏渲染有自己的优势。离屏渲染在对于复杂图层进行渲染的时候很高效。在我们重复使用一个渲染效果的时候我们可以复用。

四,OpenGL三种渲染方式:1.Attributes(属性):通过这个方式我们可以把数据传到顶点着色器里面桥接到片元着色器中(属性只能把数据传输到顶点着色器中,不能传送到片元着色器中) Attributes方式我们只能传一些顶点数据、矩阵、纹理坐标等。2、Uniforms: 通过这个方式我们传一些固定的、不经常变动的一些数据。通过Uniforms方式 我们可以把数据传输到顶点着色器中,也可以把数据传输到片元着色器中。3、Texture Data(纹理数据),通过纹理数据可以传输到顶点着色器和片元着色器中,但是纹理数据传到顶点着色器中是毫无意义的。所以我们再平时开发中都不会把纹理数据传输到顶点着色器中。

离屏渲染opengl 4.5多样本FBO

【中文标题】离屏渲染opengl 4.5多样本FBO【英文标题】:offscreen rendering opengl 4.5 multisample FBO 【发布时间】:2014-11-14 12:05:04 【问题描述】:

我在我的代码中引用了 OpenGL Superbible 6。 首先,我只是想在我的 3d 场景中实现对象拾取。最终我决定使用帧缓冲区对象并且我成功了,然后我理解了需要解决多边形边缘锯齿问题的问题,所以,我再次重写了我的代码以使用 GL_TEXTURE_2D_MULTISAMPLE

这里是framebuffer的初始化代码 void window_glview::init_framebuffer()


    //CREATE FRAMEBUFFER OBJECT
    GLenum gl_error=glGetError();

    glGenTextures(1,&texture_id_framebuffer_color);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,texture_id_framebuffer_color);
    glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,ANTIALIASING_SAMPLES,GL_RGBA8,client_area.right,client_area.bottom,GL_TRUE);

    glGenTextures(1,&texture_id_framebuffer_objectid);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,texture_id_framebuffer_objectid);
    glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,ANTIALIASING_SAMPLES,GL_RGBA8,client_area.right,client_area.bottom,GL_TRUE);

    glGenTextures(1,&texture_id_framebuffer_depth);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,texture_id_framebuffer_depth);
    glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,ANTIALIASING_SAMPLES,GL_DEPTH_COMPONENT32,client_area.right,client_area.bottom,GL_TRUE);
    gl_error=glGetError();

    glGenFramebuffers(1,&buffer_id_framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER,buffer_id_framebuffer);
    gl_error=glGetError();
    glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture_id_framebuffer_color,0);
    glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture_id_framebuffer_objectid,0);
    glFramebufferTexture(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,texture_id_framebuffer_depth,0);

    GLenum draw_buffers[] =
    
        GL_COLOR_ATTACHMENT0,
        GL_COLOR_ATTACHMENT1
    ;
    glDrawBuffers(2,draw_buffers);
    GLenum status=glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if(status!=GL_FRAMEBUFFER_COMPLETE)
        MessageBox(0,L"Failed to create framebuffer object",0,0);
    glBindFramebuffer(GL_FRAMEBUFFER,0);

对于同一主题的大多数 Internet 列表来说,这很常见。 现在这是我的绘图代码

void window_glview::paint()

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


        //DRAW TO CUSTOM FRAMEBUFFER
        glBindFramebuffer(GL_FRAMEBUFFER,buffer_id_framebuffer);
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

        glLineWidth(1.0);
        draw_viewport();
        viewport_object_count=0;

        draw_lights();
        glLineWidth(1.5);
        for (unsigned short i=0;i<mesh_count;i++)
        
            draw_mesh(mesh_table[i],GL_TRIANGLES,false);
        

    //DRAW TO DEFAULT
    glBindFramebuffer(GL_FRAMEBUFFER,0);

    //USE TEXTURE FROM FRAMEBUFFER COLOR_ATTACHMENT0
    glUseProgram(program_id_screen_render);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,texture_id_framebuffer_color);

    //HERE IS A QUAD DRAWING PROCESS
    glBindBuffer(GL_ARRAY_BUFFER,buffer_id_screen_quad);
    glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,24,0);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_QUADS,0,4);
    SwapBuffers(hDC);

顶点着色器很简单

#version 450

layout(location=0) in vec4 _pos;
void main(void)

    gl_Position=_pos;

片段着色器是为了解释多样本而编写的

#version 450
uniform sampler2DMS screen_texture;
layout(location=0) out vec4 out_color;

void main(void) 

    ivec2 coord=ivec2(gl_FragCoord.xy);
    vec4 result=vec4(0.0);
    int i;
    for (i=0;i<4;i++)
    
        result=max(result,texelFetch(screen_texture,coord,i));
    
    out_color=result;

我最终会出现黑屏。如果我将 out_color 更改为 lice out_color=vec4(1.0,0.0,0.0,1.0) 我会得到红屏。

    可能出了什么问题? 在我的帧缓冲区初始化函数中,当我将 GL_DEPTH_COMPONENT 传递给 glTexStorage2DMultisample 时,出现错误。我决定通过 GL_DEPTH_COMPONENT16 并且它有效。这是为什么呢? 我是否应该更好地使用 RENDERBUFFER 来实现某些目的,如果是,我如何将其读取到纹理?

【问题讨论】:

【参考方案1】:

id 为 texture_id_framebuffer_color 的纹理,即您用于最终渲染的纹理,在您渲染到 FBO 时不会附加到 FBO:

glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture_id_framebuffer_color,0);
glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture_id_framebuffer_objectid,0);

一次只能将一个纹理附加到给定的附加点。因此,当您指定要附加到 COLOR_ATTACHMENT0 的第二个纹理时,第一个纹理会自动取消附加。

如果您想拥有两个附件,它们将需要使用不同的连接点:

glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,texture_id_framebuffer_color,0);
glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT1,texture_id_framebuffer_objectid,0);

【讨论】:

非常感谢。我自己永远不会发现这个错字。

以上是关于离屏渲染,OpenGL的三种渲染方式的主要内容,如果未能解决你的问题,请参考以下文章

开始我的GL离屏渲染绑定[转]

离屏渲染学习笔记

iOS离屏渲染

使用 OpenGL ES 1.0 在 Android 上进行离屏渲染的选项?

离屏帧缓冲区opengl上的glGetPixels

远程离屏渲染(Linux / 无 GUI)