给osg::Geometry(自己绘制的几何体)添加纹理(二) 您所在的位置:网站首页 牛模型图片 给osg::Geometry(自己绘制的几何体)添加纹理(二)

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

2023-08-27 17:31| 来源: 网络整理| 查看: 265

目录

1. 前言

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

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

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

 3. 说明

1. 前言

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

osg给osg::Geometry(osg自带的几何体,如:BOX等)添加纹理(一) 2. 自己绘制的几何体贴纹理     2.1. 一张图贴到整个几何体

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

#include #include #include #include #include #include #include #include #include osg::ref_ptr createBox() { osg::ref_ptr spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类 osg::ref_ptr spGeometory = new osg::Geometry; spGeode->addChild(spGeometory); //spGeode->addDrawable(spGeometory); // 可以将addChild替换为这句。 osg::ref_ptr spCoordsArray = new osg::Vec3Array; // 右侧面 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右下顶点 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右下顶点 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右上顶点 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右上顶点 // 前面 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 右下顶点 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 右上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 左上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 左下顶点 // 左侧面 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左下顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左下顶点 // 后面 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后下顶点 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 左上顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 左下顶点 // 上面 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右顶点 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左顶点 // 底面 spCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右顶点 spCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左顶点 spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左顶点 spGeometory->setVertexArray(spCoordsArray); osg::DrawElementsUShort* pDrawElemt{ nullptr }; for (auto nCoordIndex = 0; nCoordIndex < spCoordsArray->size(); ++nCoordIndex) { if (0 == (nCoordIndex % 4)) { pDrawElemt = new osg::DrawElementsUShort(GL_QUADS); pDrawElemt->push_back(nCoordIndex); spGeometory->addPrimitiveSet(pDrawElemt); } else { pDrawElemt->push_back(nCoordIndex); } } // 设置纹理 osg::ref_ptrspTexture2D = new osg::Texture2D; osg::ref_ptr spImage = osgDB::readImageFile("guangzhou_tower.jpg"); if (spImage.valid()) { spTexture2D->setImage(spImage.get()); } spTexture2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP); spTexture2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP); spTexture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR); spTexture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR); // 设置纹理坐标 osg::ref_ptr spTextureCoordsArray = new osg::Vec2Array; auto nPrimitiveSetSize = spGeometory->getPrimitiveSetList().size(); // 面的个数 for (auto i = 0; i < nPrimitiveSetSize; i++) // 设置每个面的纹理坐标 { spTextureCoordsArray->push_back(osg::Vec2(0, 0)); spTextureCoordsArray->push_back(osg::Vec2(0, 1)); spTextureCoordsArray->push_back(osg::Vec2(1, 1)); spTextureCoordsArray->push_back(osg::Vec2(1, 0)); } spGeometory->setTexCoordArray(0, spTextureCoordsArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET); spGeometory->getOrCreateStateSet()->setTextureAttributeAndModes(0, spTexture2D.get(), osg::StateAttribute::ON); // 开启纹理 return spGeode; } int main() { osg::ref_ptr viewer = new osgViewer::Viewer; osg::ref_ptr spMatrixTransform = new osg::MatrixTransform; // 绕y、z轴转动下,这样便于观察效果 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))); spMatrixTransform->addChild(createBox()); viewer->setSceneData(spMatrixTransform); return viewer->run(); }

效果如下:

   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。为几何体每个面贴上不同图片的纹理代码如下:

osg::ref_ptr createGeometry(const std::string& strImagePath, osg::ref_ptr spCoordsArray, osg::ref_ptr spNormalArray) { osg::ref_ptr spGeometory = new osg::Geometry; spGeometory->setVertexArray(spCoordsArray); spGeometory->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, spCoordsArray->size())); // 设置纹理 osg::ref_ptrspTexture2D = new osg::Texture2D; osg::ref_ptr spImage = osgDB::readImageFile(strImagePath); if (spImage.valid()) { spTexture2D->setImage(0, spImage.get()); } spTexture2D->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP); spTexture2D->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP); spTexture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR); spTexture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR); // 设置纹理坐标 osg::ref_ptr spTextureCoordsArray = new osg::Vec2Array; spTextureCoordsArray->push_back(osg::Vec2(0, 0)); spTextureCoordsArray->push_back(osg::Vec2(0, 1)); spTextureCoordsArray->push_back(osg::Vec2(1, 1)); spTextureCoordsArray->push_back(osg::Vec2(1, 0)); spGeometory->getOrCreateStateSet()->setTextureAttributeAndModes(0, spTexture2D.get(), osg::StateAttribute::ON); // 开启纹理 spGeometory->setTexCoordArray(0, spTextureCoordsArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET); spGeometory->setNormalArray(spNormalArray, osg::Array::Binding::BIND_PER_PRIMITIVE_SET); return spGeometory; } osg::ref_ptr createBoxEx() { osg::ref_ptr spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类 osg::ref_ptr spRightFaceCoordsArray = new osg::Vec3Array; // 右侧面 spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右下顶点 spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右下顶点 spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右上顶点 spRightFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右上顶点 osg::ref_ptr spRightFaceNormalArray = new osg::Vec3Array; spRightFaceNormalArray->push_back(osg::Vec3(1, 0, 0)); osg::ref_ptr spRightFaceGeometory = createGeometry("guangzhou_tower.jpg", spRightFaceCoordsArray, spRightFaceNormalArray); spGeode->addChild(spRightFaceGeometory); // 前面 osg::ref_ptr spFrontFaceCoordsArray = new osg::Vec3Array; spFrontFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 右下顶点 spFrontFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 右上顶点 spFrontFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 左上顶点 spFrontFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 左下顶点 osg::ref_ptr spFrontFaceNormalArray = new osg::Vec3Array; spFrontFaceNormalArray->push_back(osg::Vec3(0, -1, 0)); osg::ref_ptr spFrontGeometory = createGeometry("csdn.jpg", spFrontFaceCoordsArray, spFrontFaceNormalArray); spGeode->addChild(spFrontGeometory); // 左侧面 osg::ref_ptr spLeftFaceCoordsArray = new osg::Vec3Array; spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左下顶点 spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左上顶点 spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左上顶点 spLeftFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左下顶点 osg::ref_ptr spLeftFaceNormalArray = new osg::Vec3Array; spLeftFaceNormalArray->push_back(osg::Vec3(-1, 0, 0)); osg::ref_ptr spLeftGeometory = createGeometry("desktop.jpg", spLeftFaceCoordsArray, spLeftFaceNormalArray); spGeode->addChild(spLeftGeometory); // 后面 osg::ref_ptr spBackFaceCoordsArray = new osg::Vec3Array; spBackFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后下顶点 spBackFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后上顶点 spBackFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 左上顶点 spBackFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 左下顶点 osg::ref_ptr spBackFaceNormalArray = new osg::Vec3Array; spBackFaceNormalArray->push_back(osg::Vec3(0, 1, 0)); osg::ref_ptr spBackGeometory = createGeometry("tower.jpg", spBackFaceCoordsArray, spBackFaceNormalArray); spGeode->addChild(spBackGeometory); // 上面 osg::ref_ptr spTopFaceCoordsArray = new osg::Vec3Array; spTopFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, 1.0)); // 前右顶点 spTopFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, 1.0)); // 后右顶点 spTopFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, 1.0)); // 后左顶点 spTopFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, 1.0)); // 前左顶点 osg::ref_ptr spTopFaceNormalArray = new osg::Vec3Array; spTopFaceNormalArray->push_back(osg::Vec3(0, 0, 1)); osg::ref_ptr spTopGeometory = createGeometry("xi_an_tower.jpg", spTopFaceCoordsArray, spTopFaceNormalArray); spGeode->addChild(spTopGeometory); // 底面 osg::ref_ptr spBottoomFaceCoordsArray = new osg::Vec3Array; spBottoomFaceCoordsArray->push_back(osg::Vec3d(1.0, -1.0, -1.0)); // 前右顶点 spBottoomFaceCoordsArray->push_back(osg::Vec3d(1.0, 1.0, -1.0)); // 后右顶点 spBottoomFaceCoordsArray->push_back(osg::Vec3d(-1.0, 1.0, -1.0)); // 后左顶点 spBottoomFaceCoordsArray->push_back(osg::Vec3d(-1.0, -1.0, -1.0)); // 前左顶点 osg::ref_ptr spBottomFaceNormalArray = new osg::Vec3Array; spBottomFaceNormalArray->push_back(osg::Vec3(0, 1, 0)); osg::ref_ptr spBottomGeometory = createGeometry("paris_tower.jpg", spBottoomFaceCoordsArray, spBottomFaceNormalArray); spGeode->addChild(spBottomGeometory); // 开启光照,要不然几何体有些面转到正对相机时是黑色的 spGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); osg::ref_ptr spLight = new osg::Light; spLight->setDiffuse(osg::Vec4d(0.0, 1.0, 0.5, 1.0)); // 漫反射光颜色 spLight->setAmbient(osg::Vec4d(0.6, 0.6, 0.6, 1.0)); // 设置环境光颜色 spLight->setPosition(osg::Vec4d(1, -1, 1, 0)); // 设置光源位置 spGeode->getOrCreateStateSet()->setAttributeAndModes(spLight, osg::StateAttribute::ON); // 开启纹理 return spGeode; }

上述代码开启了光照,在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插件来讲解)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有