OSG开发笔记(十一):OSG渲染状态与2D纹理映射

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/95938112
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)

OSG开发专栏(点击传送门)

上一篇:OSG开发笔记(十):OSG模型的变换之平移、旋转和缩放

下一篇:OSG开发笔记(十二):OSG基本几何图形、内置几何类型

 

前言

       复现OpenGL纹理贴图的效果。

 

OpenGL代码示例

传送门

       《OpenGL学习笔记(十二):纹理的使用》:

          https://blog.csdn.net/qq21497936/article/details/79184344

核心代码

        

OpenGL效果

        

 

OSG渲染树

       OSG中存在两棵树,分别为场景树和渲染树,渲染树是一颗以StateSet和RenderLeaf为节点的树,它可以做到StateSet相同的RenderLeaf同时渲染而不用切换OpenGL状态,并且做到尽量少在多个不同的State间切换。

Osg::StateSet类

       渲染时,需要在osg::StateSet中设置渲染状态,可以将StateSet关联到场景图形中的任意一个节点Node或关联到Drawable类。

       OSG将渲染状态分为2个部分,分别为渲染属性(Attribute)和渲染模式(Mode)。

  • 渲染属性:控制渲染特性的状态变量,如雾的颜色。
  • 渲染模式:设置模式量以允许或禁用某个功能,如纹理映射、灯光等。

OSG渲染

        渲染必须的步骤:

  • 为将要设置状态的Node和Drawable对象提供一个StateSet实例。
  • 在StateSet实例中设置状态的渲染模式和渲染属性。

设置渲染属性

       要设置一项属性,首先需要将修改的属性类实例化,设置该类的数值,然后用osg::StateSet::setAttribute()将其关联到StateSet。

示例代码

// 获取StateSet指针
osg::ptr<osg::StateSet> pStateSet = _pGeometry->getOrCreateStateSet();
// 创建并添加CullFace属性类
osg::ptr<osg::CullFace> pCullFace = new osg::CullFace(osg::CullFace::BACK);
pStateSet->setAttribute(pCullFace.get());

设置渲染模式

       用于可以使用osg::StateSet::setMode设置允许或禁止某种模式,例如,打开雾效果模式的许可。

// 获取StateSet指针
osg::ptr<osg::StateSet> pStateSet = _pGeometry->getOrCreateStateSet();
// 允许这个StateSet的雾效果
pStateSet(GL_FOG, osg::StateAttribute::ON);

同时设置渲染属性和模式

       OSG还提供了一个同时设置属性和渲染模式的单一接口,第一个参数为属性,第二个参数默认为打开功能。

// 获取StateSet指针
osg::ptr<osg::StateSet> pStateSet = _pGeometry->getOrCreateStateSet();
// 设置属性和渲染模式
Osg::ptr<Osg::BlendFunc> pBlendFunc = new osg::BlendFunc;
pStateSet->setAttributeAndModes(pBlendFunc);

 

OSG二维纹理映射

       纹理映射主要包括:一维纹理、二维纹理、三维纹理、凹凸纹理、多重纹理、Mipmap纹理、压缩纹理和立方纹理等。

       OSG全面支持OpenGL的纹理映射机制,为了在程序中实现基本的纹理映射功能,用户的代码需要遵循以下步骤:

  • 指定用户几何体的纹理坐标
  • 创建纹理属性对象并保存纹理图形数据
  • 为StateSet设置合适的纹理属性和模式

纹理坐标

       用一个二维的向量数组来保存纹理坐标,纹理坐标与定点一一对应

    

osg::ref_ptr<osg::Vec2Array> pVec2Array = new osg::Vec2Array;
pVec2Array->push_back(osg::Vec2(0.0, 0.0));
pVec2Array->push_back(osg::Vec2(1.0, 0.0));
pVec2Array->push_back(osg::Vec2(0.5, 1.0));

       注意:纹理坐标总是绑定到每个顶点的。

OSG实现效果

        

 

几何体纹理贴图代码

三角形

osg::ref_ptr<osg::Node> OsgWidget::getWindowDemoNode()
{
    osg::ref_ptr<osg::Group> pGroop = new osg::Group;
#if 1
    {
        // 绘制三角形
        // 创建一个用户保存几何信息的对象
        osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
        // 创建四个顶点的数组
        osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;
        // 添加四个顶点
        pGeometry->setVertexArray(pVec3Array.get());
        //          OPENGL的坐标系:X正方向向右,Y正方向朝上,Z正方向朝里
        //                     OpenGL中  x     y     z
        //          OSG的坐标系:X正方向向右,Y正方向朝里,Z正方向朝上
        //                     Osg中     x     y     z
        pVec3Array->push_back(osg::Vec3(-3.0, 0.0, 0.0));
        pVec3Array->push_back(osg::Vec3(-1.0, 0.0, 0.0));
        pVec3Array->push_back(osg::Vec3(-2.0, 0.0, 10.0));

        // 读取纹理图片
        osg::ref_ptr<osg::Image> image = new osg::Image;
        image = osgDB::readImageFile(QString("D:/qtProject/osgDemo/osgDemo/modules/osgWidget/image/window.bmp").toStdString());
        // 将图片关联到纹理
        if(!image->valid())
        {
            LOG_WARN(QString("Failed to open image file: %1").arg(QString::fromStdString(image->getFileName())));
            return 0;
        }
        osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D;
        texture2D->setImage(image.get());
        // 绑定纹理后,释放内部的ref_ptr<Image>,删除image图像
        texture2D->setUnRefImageDataAfterApply(true);
        // 创建纹理顶点
        osg::ref_ptr<osg::Vec2Array> pVec2Array = new osg::Vec2Array;
        //                      纹理单元号
        pVec2Array->push_back(osg::Vec2(0.0, 0.0));
        pVec2Array->push_back(osg::Vec2(1.0, 0.0));
        pVec2Array->push_back(osg::Vec2(0.5, 1.0));
        // 贴图失败
//        osg::ref_ptr<osg::StateSet> pStateSet = new osg::StateSet;
        // Texture类关联到渲染状态StateSet
        osg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet();
        // 将纹理关联给StateSet纹理单元0
        pStateSet->setTextureAttributeAndModes(0, texture2D.get(), osg::StateAttribute::ON);
        pGeometry->setTexCoordArray(0, pVec2Array.get());


        // 为唯一的法线创建一个数组    法线: normal
        osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
        pGeometry->setNormalArray(pVec3ArrayNormal.get());
        pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
        pVec3ArrayNormal->push_back(osg::Vec3(0.0, -1.0, 0.0));
        // 由保存的数据绘制四个顶点的多边形
        pGeometry->setStateSet(pStateSet);
        pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3));
        // 向Geode类添加几何体(Drawable)
        osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
        pGeode->addDrawable(pGeometry.get());
        pGroop->addChild(pGeode);
    }
#endif
    return pGroop.get();
}

四边形

       

       绑定了颜色的同时贴了纹理。

osg::ref_ptr<osg::Node> OsgWidget::getWindowRectDemoNode()
{
    osg::ref_ptr<osg::Group> pGroop = new osg::Group;
#if 1
    {
        // 绘制四边形
        // 创建一个用户保存几何信息的对象
        osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;

        // 创建四个顶点的数组
        osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;
        // 添加四个顶点
        pGeometry->setVertexArray(pVec3Array.get());
        //
        //                               x     y     z
        pVec3Array->push_back(osg::Vec3( 1.0, 0.0, 0.0));
        pVec3Array->push_back(osg::Vec3( 3.0, 0.0, 0.0));
        pVec3Array->push_back(osg::Vec3( 3.0, 0.0, 3.0));
        pVec3Array->push_back(osg::Vec3( 1.0, 0.0, 3.0));
        // 注意:此处若不绑定画笔,则表示使用之前绑定的画笔

        // 创建四种颜色的数据
        osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;
        // 添加四种颜色
        pGeometry->setColorArray(pVec4Array.get());
        // 绑定颜色
        pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
        pVec4Array->push_back(osg::Vec4(1.0, 0.0, 0.0, 1.0));
        pVec4Array->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0));
        pVec4Array->push_back(osg::Vec4(0.0, 0.0, 1.0, 1.0));
        pVec4Array->push_back(osg::Vec4(1.0, 1.0, 1.0, 1.0));

#if 1

        // 为纹理创建数组
        osg::ref_ptr<osg::Vec2Array> pVec2Array = new osg::Vec2Array;
        //                      纹理单元号
        pVec2Array->push_back(osg::Vec2(0.0, 0.0));
        pVec2Array->push_back(osg::Vec2(1.0, 0.0));
        pVec2Array->push_back(osg::Vec2(1.0, 1.0));
        pVec2Array->push_back(osg::Vec2(0.0, 1.0));
        // Texture类关联到渲染状态StateSet
        pGeometry->setTexCoordArray(0, pVec2Array.get());


        // 读取纹理图片
        osg::ref_ptr<osg::Image> image = new osg::Image;
        image = osgDB::readImageFile(QString("D:/qtProject/osgDemo/osgDemo/modules/osgWidget/image/window.bmp").toStdString());
        // 将图片关联到纹理
        osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D;
        texture2D->setImage(image.get());
        // 绑定纹理后,释放内部的ref_ptr<Image>,删除image图像
        texture2D->setUnRefImageDataAfterApply(true);
        // 将纹理关联给StateSet纹理单元0
        // 贴图失败
//        osg::ref_ptr<osg::StateSet> pStateSet = new osg::StateSet;
        osg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet();
        pStateSet->setTextureAttributeAndModes(0, texture2D.get());
#endif

        // 为唯一的法线创建一个数组    法线: normal
        osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
        pGeometry->setNormalArray(pVec3ArrayNormal.get());
        pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
        pVec3ArrayNormal->push_back(osg::Vec3(0.0, -1.0, 0.0));
//        pVec3ArrayNormal->push_back(osg::Vec3(0.0,  1.0, 0.0));
        // 由保存的数据绘制四个顶点的多边形
        pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
        // 向Geode类添加几何体(Drawable)
        osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
        pGeode->addDrawable(pGeometry.get());
        pGroop->addChild(pGeode);
    }
#endif
    return pGroop.get();
}

 

入坑

入坑一:2D纹理贴图未成功

        原因:编译的时候没有带jpg插件,是编译osg库时可以带第三方库,笔者没有编译。

        解决方法:将图片换bmp,使用osgDB::writeImageFile可以测试。

入坑二:2D纹理贴图未成功

        原因:是设置了StateSet的属性,没有设置mode

        解决方法:补上mode

入坑三:2D纹理贴图未成功

        原因:是自己重新new了StateSet

        解决方法:需要使用Node::getOrCreateStateSet()。

工程模板:对应版本号1.8.0

        对应版本号1.8.0

 

上一篇:OSG开发笔记(十):OSG模型的变换之平移、旋转和缩放

下一篇:OSG开发笔记(十二):OSG基本几何图形、内置几何类型

 

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/95938112

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页