• osg给osg::Geometry(自己绘制的几何体)添加纹理(二)


    目录

    1. 前言

    2. 自己绘制的几何体贴纹理 

       2.1. 一张图贴到整个几何体

       2.2. 几何体每个面贴不同的图片纹理

     3. 说明


    1. 前言

                 前文讲述了如何给osg自带的几何体,如:BOX等,添加纹理,文章参考链接如下:

    2. 自己绘制的几何体贴纹理 

       2.1. 一张图贴到整个几何体

          下面代码展示将一张图作为纹理,贴到整个几何体上,即几何体由几个面组成,则每个面的纹理都是该图片形成的纹理。代码如下:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. osg::ref_ptr createBox()
    11. {
    12. osg::ref_ptr spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类
    13. osg::ref_ptr spGeometory = new osg::Geometry;
    14. spGeode->addChild(spGeometory);
    15. //spGeode->addDrawable(spGeometory); // 可以将addChild替换为这句。
    16. osg::ref_ptr spCoordsArray = new osg::Vec3Array;
    17. // 右侧面
    18. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右下顶点
    19. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右下顶点
    20. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右上顶点
    21. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右上顶点
    22. // 前面
    23. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 右下顶点
    24. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 右上顶点
    25. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 左上顶点
    26. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 左下顶点
    27. // 左侧面
    28. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左下顶点
    29. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左上顶点
    30. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左上顶点
    31. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左下顶点
    32. // 后面
    33. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后下顶点
    34. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后上顶点
    35. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 左上顶点
    36. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 左下顶点
    37. // 上面
    38. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右顶点
    39. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右顶点
    40. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左顶点
    41. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左顶点
    42. // 底面
    43. spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右顶点
    44. spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右顶点
    45. spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左顶点
    46. spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左顶点
    47. spGeometory->setVertexArray(spCoordsArray);
    48. osg::DrawElementsUShort* pDrawElemt{ nullptr };
    49. for (auto nCoordIndex = 0; nCoordIndex < spCoordsArray->size(); ++nCoordIndex)
    50. {
    51. if (0 == (nCoordIndex % 4))
    52. {
    53. pDrawElemt = new osg::DrawElementsUShort(GL_QUADS);
    54. pDrawElemt->push_back(nCoordIndex);
    55. spGeometory->addPrimitiveSet(pDrawElemt);
    56. }
    57. else
    58. {
    59. pDrawElemt->push_back(nCoordIndex);
    60. }
    61. }
    62. // 设置纹理
    63. osg::ref_ptrspTexture2D = new osg::Texture2D;
    64. osg::ref_ptr spImage = osgDB::readImageFile("guangzhou_tower.jpg");
    65. if (spImage.valid())
    66. {
    67. spTexture2D->setImage(spImage.get());
    68. }
    69. spTexture2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP);
    70. spTexture2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP);
    71. spTexture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
    72. spTexture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
    73. // 设置纹理坐标
    74. osg::ref_ptr spTextureCoordsArray = new osg::Vec2Array;
    75. auto nPrimitiveSetSize = spGeometory->getPrimitiveSetList().size(); // 面的个数
    76. for (auto i = 0; i < nPrimitiveSetSize; i++) // 设置每个面的纹理坐标
    77. {
    78. spTextureCoordsArray->push_back(osg::Vec2(0, 0));
    79. spTextureCoordsArray->push_back(osg::Vec2(0, 1));
    80. spTextureCoordsArray->push_back(osg::Vec2(1, 1));
    81. spTextureCoordsArray->push_back(osg::Vec2(1, 0));
    82. }
    83. spGeometory->setTexCoordArray(0, spTextureCoordsArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET);
    84. spGeometory->getOrCreateStateSet()->setTextureAttributeAndModes(0, spTexture2D.get(), osg::StateAttribute::ON); // 开启纹理
    85. // 开启光照,要不然几何体有些面转到正对相机时是黑色的
    86. spGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    87. osg::ref_ptr spLight = new osg::Light;
    88. spLight->setDiffuse(osg::Vec4d(0.0, 1.0, 0.5, 1.0)); // 漫反射光颜色
    89. spLight->setAmbient(osg::Vec4d(0.6, 0.6, 0.6, 1.0)); // 设置环境光颜色
    90. spLight->setPosition(osg::Vec4d(1, -1, 1, 0)); // 设置光源位置
    91. spGeode->getOrCreateStateSet()->setAttributeAndModes(spLight, osg::StateAttribute::ON); // 开启光照
    92. return spGeode;
    93. }
    94. int main()
    95. {
    96. osg::ref_ptr viewer = new osgViewer::Viewer;
    97. osg::ref_ptr spMatrixTransform = new osg::MatrixTransform;
    98. // 绕y、z轴转动下,这样便于观察效果
    99. spMatrixTransform->setMatrix(osg::Matrix::rotate(osg::PI / 3.0, osg::Vec3(0, 0, 1)) * osg::Matrix::rotate(osg::PI / 5.0, osg::Vec3(1, 0, 0)));
    100. spMatrixTransform->addChild(createBox());
    101. viewer->setSceneData(spMatrixTransform);
    102. return viewer->run();
    103. }

    效果如下:

       2.2. 几何体每个面贴不同的图片纹理

           有时需要对几何体每个面贴上不同图片形成纹理,即每个面纹理不同。解决思路是:每个面形成一个osg::Geometry,而不是所有面形成一个osg::Geometry,且每个osg::Geometry对象new出一个osg::Texture2D进行纹理关联。这是因为如下代码:

    spGeometory->getOrCreateStateSet()->setTextureAttributeAndModes(0, spTexture2D.get(), osg::StateAttribute::ON); // 开启纹理

    其中spGeometory表示 osg::Geometry对象,每个osg::Geometry对象只能设定一个osg::Texture2D对象,所以要想每个面绑定一个不同的osg::Texture2D对象,则必须对每个面单独形成一个osg::Geometry,而不是所有面形成一个osg::Geometry。为几何体每个面贴上不同图片的纹理代码如下:

    1. osg::ref_ptr createGeometry(const std::string& strImagePath, osg::ref_ptr spCoordsArray, osg::ref_ptr spNormalArray)
    2. {
    3. osg::ref_ptr spGeometory = new osg::Geometry;
    4. spGeometory->setVertexArray(spCoordsArray);
    5. spGeometory->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, spCoordsArray->size()));
    6. // 设置纹理
    7. osg::ref_ptrspTexture2D = new osg::Texture2D;
    8. osg::ref_ptr spImage = osgDB::readImageFile(strImagePath);
    9. if (spImage.valid())
    10. {
    11. spTexture2D->setImage(0, spImage.get());
    12. }
    13. spTexture2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP);
    14. spTexture2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP);
    15. spTexture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
    16. spTexture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
    17. // 设置纹理坐标
    18. osg::ref_ptr spTextureCoordsArray = new osg::Vec2Array;
    19. spTextureCoordsArray->push_back(osg::Vec2(0, 0));
    20. spTextureCoordsArray->push_back(osg::Vec2(0, 1));
    21. spTextureCoordsArray->push_back(osg::Vec2(1, 1));
    22. spTextureCoordsArray->push_back(osg::Vec2(1, 0));
    23. spGeometory->getOrCreateStateSet()->setTextureAttributeAndModes(0, spTexture2D.get(), osg::StateAttribute::ON); // 开启纹理
    24. spGeometory->setTexCoordArray(0, spTextureCoordsArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET);
    25. spGeometory->setNormalArray(spNormalArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET);
    26. return spGeometory;
    27. }
    28. osg::ref_ptr createBoxEx()
    29. {
    30. osg::ref_ptr spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类
    31. osg::ref_ptr spRightFaceCoordsArray = new osg::Vec3Array;
    32. // 右侧面
    33. spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右下顶点
    34. spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右下顶点
    35. spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右上顶点
    36. spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右上顶点
    37. osg::ref_ptr spRightFaceNormalArray = new osg::Vec3Array;
    38. spRightFaceNormalArray->push_back(osg::Vec3(1, 0, 0));
    39. osg::ref_ptr spRightFaceGeometory = createGeometry("guangzhou_tower.jpg", spRightFaceCoordsArray, spRightFaceNormalArray);
    40. spGeode->addChild(spRightFaceGeometory);
    41. // 前面
    42. osg::ref_ptr spFrontFaceCoordsArray = new osg::Vec3Array;
    43. spFrontFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 右下顶点
    44. spFrontFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 右上顶点
    45. spFrontFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 左上顶点
    46. spFrontFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 左下顶点
    47. osg::ref_ptr spFrontFaceNormalArray = new osg::Vec3Array;
    48. spFrontFaceNormalArray->push_back(osg::Vec3(0, -1, 0));
    49. osg::ref_ptr spFrontGeometory = createGeometry("csdn.jpg", spFrontFaceCoordsArray, spFrontFaceNormalArray);
    50. spGeode->addChild(spFrontGeometory);
    51. // 左侧面
    52. osg::ref_ptr spLeftFaceCoordsArray = new osg::Vec3Array;
    53. spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左下顶点
    54. spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左上顶点
    55. spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左上顶点
    56. spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左下顶点
    57. osg::ref_ptr spLeftFaceNormalArray = new osg::Vec3Array;
    58. spLeftFaceNormalArray->push_back(osg::Vec3(-1, 0, 0));
    59. osg::ref_ptr spLeftGeometory = createGeometry("desktop.jpg", spLeftFaceCoordsArray, spLeftFaceNormalArray);
    60. spGeode->addChild(spLeftGeometory);
    61. // 后面
    62. osg::ref_ptr spBackFaceCoordsArray = new osg::Vec3Array;
    63. spBackFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后下顶点
    64. spBackFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后上顶点
    65. spBackFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 左上顶点
    66. spBackFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 左下顶点
    67. osg::ref_ptr spBackFaceNormalArray = new osg::Vec3Array;
    68. spBackFaceNormalArray->push_back(osg::Vec3(0, 1, 0));
    69. osg::ref_ptr spBackGeometory = createGeometry("tower.jpg", spBackFaceCoordsArray, spBackFaceNormalArray);
    70. spGeode->addChild(spBackGeometory);
    71. // 上面
    72. osg::ref_ptr spTopFaceCoordsArray = new osg::Vec3Array;
    73. spTopFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右顶点
    74. spTopFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右顶点
    75. spTopFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左顶点
    76. spTopFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左顶点
    77. osg::ref_ptr spTopFaceNormalArray = new osg::Vec3Array;
    78. spTopFaceNormalArray->push_back(osg::Vec3(0, 0, 1));
    79. osg::ref_ptr spTopGeometory = createGeometry("xi_an_tower.jpg", spTopFaceCoordsArray, spTopFaceNormalArray);
    80. spGeode->addChild(spTopGeometory);
    81. // 底面
    82. osg::ref_ptr spBottoomFaceCoordsArray = new osg::Vec3Array;
    83. spBottoomFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右顶点
    84. spBottoomFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右顶点
    85. spBottoomFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左顶点
    86. spBottoomFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左顶点
    87. osg::ref_ptr spBottomFaceNormalArray = new osg::Vec3Array;
    88. spBottomFaceNormalArray->push_back(osg::Vec3(0, 1, 0));
    89. osg::ref_ptr spBottomGeometory = createGeometry("paris_tower.jpg", spBottoomFaceCoordsArray, spBottomFaceNormalArray);
    90. spGeode->addChild(spBottomGeometory);
    91. // 开启光照,要不然几何体有些面转到正对相机时是黑色的
    92. spGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    93. osg::ref_ptr spLight = new osg::Light;
    94. spLight->setDiffuse(osg::Vec4d(0.0, 1.0, 0.5, 1.0)); // 漫反射光颜色
    95. spLight->setAmbient(osg::Vec4d(0.6, 0.6, 0.6, 1.0)); // 设置环境光颜色
    96. spLight->setPosition(osg::Vec4d(1, -1, 1, 0)); // 设置光源位置
    97. spGeode->getOrCreateStateSet()->setAttributeAndModes(spLight, osg::StateAttribute::ON); // 开启光照
    98. return spGeode;
    99. }

    上述代码开启了光照,在2.1节没开启光照时,当几何体有些面转到正对相机时,是黑色的,开启光照,则看得清些。 

    将main函数中的如下代码:

    spMatrixTransform->addChild(createBox());

     改为:

    spMatrixTransform->addChild(createBoxEx());

    效果如下:

     3. 说明

          在绑定每个面的纹理时,绑定方式必须为osg::Array::Binding::BIND_PER_PRIMITIVE_SET,否则2.1节只有第1次绘制的面即右侧面才有纹理。关于 osg::Array::Binding枚举各值含义,请参见:osg图元绑定方式总结

         对于某些图片作为纹理,需要相应的插件才行。如:读取jpg,故请保证jpg插件存在,否则读取jpg会失败。如下为读取png类型图片时,因为没有png的插件弹出的错误:

    Error reading file Qt.png: read error (Could not find plugin to read objects from file "Qt.png".)

    关于怎么编译jpg插件到osg,请参见:osg第三方插件的编译方法(以jpeg插件来讲解)

  • 相关阅读:
    数据监控预警系统,实现不同端信息推送
    LeetCode 6138. 最长理想子序列 动态规划
    数值分析思考题(钟尓杰版)参考解答——第五章
    Vue_watch+Computed+filter
    const用法精讲
    Spring Boot 配置文件
    springboot+jsp教师工作量业务数据统计与分析系统ssm高校教师电子业务档案管理系统
    scrollIntoView多重校验rules滚动到指定位置
    Keras可视化神经网络架构的4种方法
    内核网络协议栈传输层协议框架
  • 原文地址:https://blog.csdn.net/danshiming/article/details/130885527