osg写 fbo

看了视频教程https://www.bilibili.com/video/av74285647/

感谢up主,

我试图简易地描述下,如果渲染到场景中,最简单的主摄像机

int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> grp = new osg::Group;
    std::string strFileName = "f:/test/pot.FBX";
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strFileName);
    grp->addChild(node);

viewer->setSceneData(grp);

    viewer->run();
}
 

 

现在不想直接绘制到场景了,绘制到面片上;或者进行后处理后再次投影到全屏中,比如hdr

 

这就用到了FBO,

这里不考虑放缩,直接用屏幕大小的面片,以后即使贴到屏幕上,也是一样的。

1,先考虑面片,


osg::Texture2D *createFloatTextureRectangle(int width, int height)
{
    osg::ref_ptr<osg::Texture2D> tex2D = new osg::Texture2D;
    tex2D->setTextureSize(width, height);
    tex2D->setInternalFormat(GL_RGBA16F_ARB);
    tex2D->setSourceFormat(GL_RGBA);
    tex2D->setSourceType(GL_FLOAT);
    return tex2D.release();
}

先获取系统分辨率,确定帧缓冲区大小
    unsigned int screenWidth, screenHeight;
    {
        osg::GraphicsContext::WindowingSystemInterface *wsInterface = osg::GraphicsContext::getWindowingSystemInterface();
        if (!wsInterface)
        {
            return -1;
        }
        wsInterface->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), screenWidth, screenHeight);

    }
    int texWidth = screenWidth;
    int texHeight = screenHeight;
    // 然后设置离屏表面的纹理,FBO涉及到3种缓冲区:深度模板,颜色和法线

这里只考虑关联颜色缓冲区的纹理
    osg::Texture2D *textureSample = createFloatTextureRectangle(texWidth, texHeight);

设置完后呢,需要关联颜色缓冲区,把颜色缓冲区的内容放在这个纹理上。这用到了采样摄像机,这里仍然采用铺满该纹理。其实,主摄像机和采样摄像机都是一样的。

// 采样像机1设置:
    {

        osg::Camera *cameraSample = new osg::Camera;// 各种采样
        grp->addChild(cameraSample);// 加入场景
        cameraSample->addChild(node);// 加入模型
        cameraSample->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);// 这句使内容不渲染到屏幕上
        cameraSample->attach(osg::Camera::COLOR_BUFFER0, textureSample);// 关联采样贴图
        cameraSample->setViewport(0, 0, screenWidth, screenHeight);//

    }

 

然后这张纹理贴到哪里呢?先贴到面片上,面片直接加载到场景中


        osg::Geode * panel1 = createTexturePanel();
        panel1->getOrCreateStateSet()->setTextureAttributeAndModes(0, textureSample);
        grp->addChild(panel1);

 

目前现在这步算是ok了,颜色缓冲区的东西放到面片上了,

可是后处理不是这么玩的,我还想放在全屏上,咋办呢?

 

那就把颜色缓冲区的纹理,再放到最终的摄像机上。这个摄像机要用到设备规格化

    //最终的摄像机
    
        osg::ref_ptr<osg::Camera> finalCamera = new osg::Camera;
        finalCamera->addChild(panel1);
        grp->addChild(finalCamera);
        finalCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);


osg::Geode* createTexturePanel()
{
    osg::Vec3Array *vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(-1.0, -1.0, 0.0));
    vertices->push_back(osg::Vec3(1.0, -1.0, 0.0));
    vertices->push_back(osg::Vec3(1.0, 1.0, 0.0));
    vertices->push_back(osg::Vec3(-1.0, 1.0, 0.0));

    osg::Vec2Array *texcoord = new osg::Vec2Array;
    texcoord->push_back(osg::Vec2(0.0, 0.0));
    texcoord->push_back(osg::Vec2(1.0, 0.0));
    texcoord->push_back(osg::Vec2(1.0, 1.0));
    texcoord->push_back(osg::Vec2(0.0, 1.0));

    osg::Geometry *geom = new osg::Geometry;
    geom->setVertexArray(vertices);
    geom->setTexCoordArray(0, texcoord);
    geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));

    osg::Geode *geode = new osg::Geode;
    geode->addDrawable(geom);
    osg::StateSet *set1 = geode->getOrCreateStateSet();
    //geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    set1->setMode(GL_LIGHTING, osg::StateAttribute::OFF);// 设置不受光照影响, 不然太暗了就看不清

    return geode;
}

结果如下:

贴上去了,看到这里,估计有人想,这不是在逗我吧。我怎么知道这是主摄像机的,还是采样摄像机的纹理贴上去的?

这个简单,在采样摄像机中,再把背景颜色涂成黑色。
      

cameraSample->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));

我们再把颜色缓冲区放到面片上。

看清楚,黑了啊,和主摄像机不同了。

我们再把它当做全屏摄像机的纹理贴上去。

ok,说明确实是把颜色缓冲区的纹理贴到了全屏摄像机上。

 

类似地,深度模板和法线应该同样,具体以后再试。

 

这里总结下,实际上归为两个问题

1,主摄像机为什么把物体直接绘制到屏幕上,而FBO没有

2,fbo如何绘制到面片上,如何绘制到全屏?

 

先看第一个问题。

FBO除了关联三个缓冲区外(这里只写了颜色缓冲区),还设置了下
        cameraSample->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);// 这句使内容不渲染到屏幕上
        cameraSample->attach(osg::Camera::COLOR_BUFFER0, textureSample);// 关联采样贴图

这两句起到了作用,当然,还有第三句容易误导

cameraSample->setViewport(0, 0, screenWidth, screenHeight);//

这是把离屏表面填满,与主摄像机的视口没任何关系。

或许,应该直接写为
 cameraSample->setViewport(0, 0, texWidth, texHeight);

 

第二个问题,如何绘制到面片和全屏,

这里规整后代码对比下

osg::Geode * panel1 = createTexturePanel();
 panel1->getOrCreateStateSet()->setTextureAttributeAndModes(0, textureSample);

.//面片直接添加到场景中
{
        grp->addChild(panel1);

}

//全屏

{
        osg::ref_ptr<osg::Camera> finalCamera = new osg::Camera;
        finalCamera->addChild(panel1);
        grp->addChild(finalCamera);
        finalCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

}

由此可见,似乎是


        finalCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

在起作用。

把全屏的注释掉这句代码。

果然成面片了。

看看API,

默认状态是RELATIVE_RF

 

 

即:

1,FBO需要
        cameraSample->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);// 这句使内容不渲染到屏幕上
        cameraSample->attach(osg::Camera::COLOR_BUFFER0, textureSample);// 关联采样贴图

2,如果想将FBO放到全屏,则需要新建一个摄像机,摄像机添加该面片,并设置该摄像机为

 finalCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

最后上代码

#include "common.h"
#include <iostream>

osg::Geode* createTexturePanel()
{
    osg::Vec3Array *vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(-1.0, -1.0, 0.0));
    vertices->push_back(osg::Vec3(1.0, -1.0, 0.0));
    vertices->push_back(osg::Vec3(1.0, 1.0, 0.0));
    vertices->push_back(osg::Vec3(-1.0, 1.0, 0.0));

    osg::Vec2Array *texcoord = new osg::Vec2Array;
    texcoord->push_back(osg::Vec2(0.0, 0.0));
    texcoord->push_back(osg::Vec2(1.0, 0.0));
    texcoord->push_back(osg::Vec2(1.0, 1.0));
    texcoord->push_back(osg::Vec2(0.0, 1.0));

    osg::Geometry *geom = new osg::Geometry;
    geom->setVertexArray(vertices);
    geom->setTexCoordArray(0, texcoord);
    geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));

    osg::Geode *geode = new osg::Geode;
    geode->addDrawable(geom);
    osg::StateSet *set1 = geode->getOrCreateStateSet();
    //geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    set1->setMode(GL_LIGHTING, osg::StateAttribute::OFF);// 设置不受光照影响, 不然太暗了就看不清

    return geode;
}

osg::Texture2D *createFloatTextureRectangle(int width, int height)
{
    osg::ref_ptr<osg::Texture2D> tex2D = new osg::Texture2D;
    tex2D->setTextureSize(width, height);
    tex2D->setInternalFormat(GL_RGBA16F_ARB);
    tex2D->setSourceFormat(GL_RGBA);
    tex2D->setSourceType(GL_FLOAT);
    return tex2D.release();
}

int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> grp = new osg::Group;
    std::string strFileName = "f:/test/pot.FBX";
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strFileName);

    //获取系统分辨率
    unsigned int screenWidth, screenHeight;
    {
        osg::GraphicsContext::WindowingSystemInterface *wsInterface = osg::GraphicsContext::getWindowingSystemInterface();
        if (!wsInterface)
        {
            return -1;
        }
        wsInterface->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), screenWidth, screenHeight);

    }
    int texWidth = screenWidth;
    int texHeight = screenHeight;
    // 采样贴图设置:
    osg::Texture2D *textureSample = createFloatTextureRectangle(texWidth, texHeight);
    
    // 采样像机1设置:
    {

        osg::Camera *cameraSample = new osg::Camera;// 各种采样
        grp->addChild(cameraSample);// 加入场景
        cameraSample->addChild(node);// 加入模型

        cameraSample->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
        cameraSample->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);// 这句使内容不渲染到屏幕上
        cameraSample->attach(osg::Camera::COLOR_BUFFER0, textureSample);// 关联采样贴图
        cameraSample->setViewport(0, 0, texWidth, texHeight);//

    }
    osg::Geode * panel1 = createTexturePanel();
    panel1->getOrCreateStateSet()->setTextureAttributeAndModes(0, textureSample);
#if 0
    {
        grp->addChild(panel1);

    
    }
#endif
#if 1
    //最终的摄像机
    
    {
        osg::ref_ptr<osg::Camera> finalCamera = new osg::Camera;
        finalCamera->addChild(panel1);
        grp->addChild(finalCamera);
        finalCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
    }
    
#endif
    viewer->setSceneData(grp);

    viewer->run();
}
 

 

    

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值