OSG(OpenSceneGraph) 是一个用于 3D 图形渲染的开源场景图形库,主要用于高性能 3D 应用程序的开发,被广泛应用于飞行模拟、游戏开发、虚拟现实(VR)、增强现实(AR)和仿真系统等领域,OSG 的设计围绕“场景图”结构,帮助开发者高效管理和渲染复杂的 3D 场景。 |
OSG使用C++、面向对象技术开发,基于OpenGL,封装了OpenGL中的功能,屏蔽细节、便于交互,支持Windows、Linux、macOS。 |
Github: https://github.com/openscenegraph/OpenSceneGraph |
一、OSG环境搭建(Windows)
1、Vcpkg包安装
vcpkg.exe install osg vcpkg.exe install osg-qt |
2、CMakeLists
find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgUtil osgGA osgViewer osgWidget) target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSCENEGRAPH_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSCENEGRAPH_LIBRARIES}) |
二、OSG环境搭建(Linux)
1、克隆源码
注意:配合OSGEARTH需要将cmake版本提升到3.20以上。 |
mkdir osg && cd osg git clone https://github.com/openscenegraph/OpenSceneGraph.git cd OpenSceneGraph |
2、编译/构建
注意使用普通用户进行。 |
在OpenSceneGraph文件夹下打开CMakeLists.txt文件,搜索关键词OPENGL_PROFILE,寻找到 SET(OPENGL_PROFILE “GL3” CACHE STRING “OpenGL Profile to use, choose from GL1, GL2, GL3, GLES1, GLES2, GLES3”) 这一行代码,标记内容原本为GL2或其他的选项,这里一律将标记内容修改为GL3,运行以下命令进行安装。 sudo apt install ocl-icd-opencl-dev |
mkdir build && cd build cmake ../ make -j8 sudo make install sudo vim /etc/ld.so.conf.d/osg.conf // 输入OSG动态库路径 /usr/local/lib64 /usr/local/lib /usr/local/lib/x86_64-linux-gnu // 更新链接配置 sudo ldconfig |
![]() |
3、模型测试
下载模型数据:https://openscenegraph.github.io/OpenSceneGraphDotComBackup/OpenSceneGraph/www.openscenegraph.com/downloads/stable_releases/OpenSceneGraph-3.4.0/data/OpenSceneGraph-Data-3.4.0.zip |
osgviewer cow.osg |
4、CMakeLists
find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgUtil osgGA osgViewer osgWidget) target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSCENEGRAPH_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSCENEGRAPH_LIBRARIES}) |
三、OSG文档
https://podsvirov.github.io/osg/reference/openscenegraph/annotated.html OSG的模化设计思想将其类库按照“命名空间+类名称”命名。 |
四、OSG核心库(osg)
核心osg库提供了基本的场景图类,例如 Nodes、State和 Drawables,以及数学和通用帮助程序类。 |
1、数据结构
- osg::ref_ptr(引用计数)
头文件:#include <osg/ref_ptr> |
osg::ref_ptr 是一个模板类,类似于标准库中的 std::shared_ptr,但是它特别为 OSG 的对象生命周期管理而设计,ref_ptr 会自动跟踪引用计数,当引用计数为 0 时,自动删除对象。 |
声明与使用: |
#include <osg/Node> #include <osg/ref_ptr> int main() { // 创建一个 osg::Node 对象的 ref_ptr osg::ref_ptr<osg::Node> node = new osg::Node; // 使用该对象(例如将其添加到场景图中) node->setName("MyNode"); // 不需要显式删除,OSG 会自动管理内存 return 0; } |
函数返回值使用: |
osg::ref_ptr<osg::Node> createNode() { osg::ref_ptr<osg::Node> node = new osg::Node; node->setName("CreatedNode"); return node; } int main() { osg::ref_ptr<osg::Node> node = createNode(); // node 会在使用完后自动释放内存 return 0; } |
引用计数工作机制: |
osg::ref_ptr<osg::Node> node1 = new osg::Node; osg::ref_ptr<osg::Node> node2 = node1; // 增加引用计数 // 当 node1 和 node2 超出作用域时,对象会自动销毁 |
与原始指针的转换: |
osg::ref_ptr<osg::Node> node = new osg::Node; osg::Node* rawNode = node.get(); // 获取原始指针 |
- osg::Vec2(二维向量)
头文件:#include <osg/Vec2> |
功能:osg::Vec2 是一个用于表示二维向量的类,包含两个 float 类型的分量:x 和 y,它通常用于表示二维坐标、纹理坐标、或其他二维向量的数学运算。 成员函数: · x(), y(),:获取二维向量的 x、y分量; · set(x, y):设置向量的 x、y分量。 |
示例代码: |
#include <osg/Vec2> int main() { // 创建一个 osg::Vec2 对象 osg::Vec2 point(1.0f, 2.0f); // 访问 x 和 y 分量 float x = point.x(); float y = point.y(); // 修改分量 point.set(x + 1.0f, y + 1.0f); // 向量加法 osg::Vec2 other(0.5f, 0.5f); osg::Vec2 sum = point + other; return 0; } |
- osg::Vec2Array(二维向量数组)
#include <osg/Vec2Array> |
功能:osg::Vec2Array 是一个容器类,用于存储多个 osg::Vec2 对象。通常用于表示二维顶点坐标、纹理坐标等。 成员函数: · size():获取数组中元素的数量; · operator[]():按索引访问数组中的元素。 |
示例代码: |
#include <osg/Vec2Array> #include <osg/Geometry> int main() { // 创建一个 Vec2Array 对象 osg::ref_ptr<osg::Vec2Array> texCoords = new osg::Vec2Array; // 添加纹理坐标 texCoords->push_back(osg::Vec2(0.0f, 0.0f)); texCoords->push_back(osg::Vec2(1.0f, 0.0f)); texCoords->push_back(osg::Vec2(0.0f, 1.0f)); // 创建一个 Geometry 对象并设置纹理坐标 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry; geometry->setTexCoordArray(0, texCoords); return 0; } |
- osg::Vec3(三维向量)
头文件:#include <osg/Vec3> |
功能:osg::Vec3 是一个用于表示三维向量的类,它包含三个 float 类型的分量:x、y 和 z,用来表示三维空间中的一个点或方向,支持各种数学运算,如加法、减法、点积、叉积等。 成员函数: · x(), y(), z():获取三维向量的 x、y、z 分量; · set(x, y, z):设置向量的 x、y、z 分量; · length():计算向量的长度(模); · normalize():将向量归一化; · dot():计算点积(Vec3 和另一个 Vec3); · cross():计算叉积(Vec3 和另一个 Vec3)。 |
示例代码: |
#include <osg/Vec3> int main() { // 创建一个 osg::Vec3 对象 osg::Vec3 point(1.0f, 2.0f, 3.0f); // 访问 x, y, z 分量 float x = point.x(); float y = point.y(); float z = point.z(); // 修改分量 point.set(x + 1.0f, y + 1.0f, z + 1.0f); // 向量加法 osg::Vec3 other(0.5f, 0.5f, 0.5f); osg::Vec3 sum = point + other; // 向量点积 float dotProduct = point * other; return 0; } |
- osg::Vec3Array(三维向量数组)
头文件:#include <osg/Vec3Array> |
功能:osg::Vec3Array 是一个容器类,用于存储多个 osg::Vec3 对象,通常用于表示一组三维点(例如多边形的顶点)。 成员函数: · size():获取数组中元素的数量; · operator[]():按索引访问数组中的元素。 |
示例代码: |
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry; geometry->setVertexArray(vertices); |
- osg::Vec4(四维向量)
头文件:#include <osg/Vec4> |
功能:osg::Vec4 是一个用于表示四维向量的类,包含四个 float 类型的分量:x、y、z 和 w,用于表示颜色(RGBA)或四维向量。 成员函数: · r(), g(), b(), a():获取四维向量的 r、g、b、a 分量; · set(r, g, b, a):设置向量的 r、g、b、a 分量。 |
示例代码: |
#include <osg/Vec4> int main() { // 创建一个 osg::Vec4 对象(RGBA 颜色) osg::Vec4 color(1.0f, 0.0f, 0.0f, 1.0f); // Red color // 访问 x, y, z, w 分量 float r = color.r(); float g = color.g(); float b = color.b(); float a = color.a(); // 修改分量 color.set(r * 0.5f, g * 0.5f, b * 0.5f, a * 0.5f); return 0; } |
- osg::Vec4Array(四维向量数组)
头文件:#include <osg/Vec4Array> |
功能:osg::Vec4Array 是一个容器类,用于存储多个 osg::Vec4 对象。通常用于表示一组颜色、四维坐标等。 成员函数: · size():获取数组中元素的数量; · operator[]():按索引访问数组中的元素。 |
示例代码: |
#include <osg/Vec4Array> #include <osg/Geometry> int main() { // 创建一个 Vec4Array 对象 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; // 添加颜色 colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); // Red color colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); // Green color colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); // Blue color // 创建一个 Geometry 对象并设置颜色数组 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry; geometry->setColorArray(colors); geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); // 每个顶点使用不同的颜色 return 0; } |
- osg::StateSet(渲染状态容器)
头文件:#include <osg/StateSet> |
功能:osg::StateSet 是渲染状态的容器,用于管理所有渲染状态,如纹理、着色器、光照、混合模式等。 函数: · void setTextureAttributeAndModes(unsigned int unit, osg::StateAttribute* attribute, osg::StateAttribute::Mode mode); // 设置纹理单位和其对应的状态属性 · void setAttributeAndModes(osg::StateAttribute* attribute, osg::StateAttribute::Mode mode); // 设置一个状态属性,并指定它的启用/禁用模式 · void setMode(GLenum cap, osg::StateAttribute::Mode mode); // 设置 OpenGL 状态(例如启用/禁用某个渲染功能) · osg::StateAttribute* getAttribute(osg::StateAttribute::Type type) const; // 获取指定类型的状态属性 · osg::ref_ptr<osg::StateSet> getOrCreateStateSet(); // 获取或创建一个与节点关联的状态集 · void addAttribute(osg::StateAttribute* attribute); // 将一个状态属性添加到 StateSet · void removeAttribute(osg::StateAttribute* attribute); // 从 StateSet 中移除状态属性 |
- osg::Image(图像数据)
头文件:#include <osg/Image> |
功能:osg::Image 是 OpenSceneGraph (OSG) 中用于存储和处理图像数据的类,通常用于表示纹理图像,封装了图像的像素数据,并提供了访问图像各个像素、宽高等属性的方法。 函数: · unsigned int s() const; // 返回图像的宽度(水平分辨率) · unsigned int t() const; // 返回图像的高度(垂直分辨率) · unsigned int r() const; // 返回图像的深度(适用于 3D 图像) · unsigned int getNumComponents() const; // 返回图像的通道数(如 RGB 为 3,RGBA 为 4) · void setNumComponents(unsigned int numComponents); // 设置图像的通道数 · GLenum getPixelFormat() const; // 返回图像的像素格式(如 GL_RGBA) · GLenum getDataType() const; // 返回图像的像素数据类型(如 GL_UNSIGNED_BYTE) · unsigned char* data() const; // 返回指向图像像素数据的指针 · void setImage(unsigned int width, unsigned int height, unsigned int numComponents, GLenum dataType, unsigned char* data); // 设置图像的宽高、通道数、数据类型和像素数据 · osg::ref_ptr<osg::Image> clone() const; // 克隆当前图像对象 · bool isImageTranslucent() const; // 判断图像是否具有透明通道 · void flipVertical(); // 将图像垂直翻转 |
- osg::Texture2D(纹理数据)
头文件:#include <osg/Texture2D> |
功能:osg::Texture2D 用于表示 2D 纹理图像,通常在 3D 场景中用于贴图,它包含纹理图像、纹理过滤方式、环绕模式等参数,可以通过 setImage 方法将一个 osg::Image 对象应用为纹理,也可以设置各种纹理参数来控制纹理如何在渲染时进行处理(例如,过滤方式、环绕方式等)。 函数: · void setImage(osg::Image* image); // 设置纹理图像 · osg::Image* getImage() const; // 获取纹理图像 · void setFilter(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter); // 设置纹理的过滤方式 · void setWrap(osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT); // 设置纹理的环绕方式 · void setWrap(osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT, osg::Texture::WrapMode wrapR); // 设置 3D 纹理的环绕方式 · void setInternalFormat(GLenum format); // 设置纹理的内部格式 · GLenum getInternalFormat() const; // 获取纹理的内部格式 · void setBorderColor(const osg::Vec4& borderColor); // 设置纹理的边框颜色 · const osg::Vec4& getBorderColor() const; // 获取纹理的边框颜色 · void setTextureWidth(unsigned int width); // 设置纹理的宽度 · unsigned int getTextureWidth() const; // 获取纹理的宽度 · void setTextureHeight(unsigned int height); // 设置纹理的高度 · unsigned int getTextureHeight() const; // 获取纹理的高度 · void setTextureDepth(unsigned int depth); // 设置纹理的深度 · unsigned int getTextureDepth() const; // 获取纹理的深度 · void setTarget(GLenum target); // 设置纹理的目标类型(例如,GL_TEXTURE_2D) · GLenum getTarget() const; // 获取纹理的目标类型 · void setMaxAnisotropy(float maxAnisotropy); // 设置纹理的最大各向异性 · float getMaxAnisotropy() const; // 获取纹理的最大各向异性 · void apply(osg::StateSet& stateSet) const; // 将纹理应用到给定的状态集 |
2、场景图(Scene Graph)
- osg::Geode(几何节点)
头文件:#include <osg/Geode> |
功能:osg::Geode 是 OpenSceneGraph 中一个非常重要的类,通常用于包含几何体(osg::Drawable)集合,它用于构建一个渲染节点,几何体数据(如 osg::Geometry)可以被添加到 Geode 中,形成可渲染的图形。 函数: · void addDrawable(osg::Drawable* drawable); // 将几何体(osg::Drawable)添加到 Geode 中 · unsigned int getNumDrawables() const; // 返回 Geode 中包含的几何体(osg::Drawable)的数量 · osg::Drawable* getDrawable(unsigned int index) const; // 获取 Geode 中指定索引的几何体(osg::Drawable) · void removeDrawable(osg::Drawable* drawable); // 从 Geode 中移除指定的几何体 · void setStateSet(osg::StateSet* stateSet); // 设置 Geode 的状态集(StateSet) · osg::StateSet* getOrCreateStateSet(); // 获取或创建 Geode 的状态集(StateSet) · void traverse(osg::NodeVisitor& nv); // 遍历 Geode 中的所有几何体,通常用于场景图遍历 |
3、几何体和着色器(osg::Geometry)
头文件:#include <osg/Geometry> |
功能:osg::Geometry 类是 OpenSceneGraph (OSG) 中用于表示几何体的核心类之一,负责存储顶点数据、颜色、法线、纹理坐标等信息,供图形渲染引擎渲染使用,通过 osg::Geometry 类,可以定义模型的顶点、面、颜色、纹理映射等,并将其传递给图形管线进行绘制。 |
- 构造函数
· Geometry(): 默认构造函数,创建一个空的几何体; · Geometry(const Geometry& geometry, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY): 复制构造函数。 |
- 设置顶点数据(setVertexArray)
void setVertexArray(osg::ref_ptr<osg::Vec3Array> vertices): 设置顶点坐标数组,vertices 是一个 osg::Vec3Array 类型的对象,存储模型的顶点坐标。 |
示例代码: |
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); geometry->setVertexArray(vertices); |
- 设置颜色数据(setColorArray)
void setColorArray(osg::ref_ptr<osg::Vec4Array> colors): 设置顶点颜色数组,colors 是一个 osg::Vec4Array 类型的对象,存储每个顶点的颜色。 |
示例代码: |
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); // 红色 geometry->setColorArray(colors); |
- 设置纹理坐标(setTexCoordArray)
void setTexCoordArray(int unit, osg::ref_ptr<osg::Vec2Array> texCoords): 设置纹理坐标数组,texCoords 是一个 osg::Vec2Array 类型的对象,unit 是纹理单元(通常为 0)。 |
示例代码: |
osg::ref_ptr<osg::Vec2Array> texCoords = new osg::Vec2Array; texCoords->push_back(osg::Vec2(0.0f, 0.0f)); // 纹理坐标 (0,0) geometry->setTexCoordArray(0, texCoords); |
- 设置法线数据(setNormalArray/setNormalBinding)
法线:垂直与一个平面的向量,根据法线计算该面为朝向光源/背向光源; (计算法线向量和从平面上一个点到光源方向向量的点乘,cos值在角度[-90°, +90°]范围内的时候是正值,并且越接近±90°值越接近0,只要cos值大于0,就证明这个面被光照到) |
void setNormalArray(osg::ref_ptr<osg::Vec3Array> normals): 设置法线数组,normals 是一个 osg::Vec3Array 类型的对象,存储每个顶点的法线向量。 void setNormalBinding(NormalBinding binding): 设置法线的绑定方式; osg::Geometry::BIND_OFF:没有绑定; osg::Geometry::BIND_PER_VERTEX:每个顶点使用不同的法线; osg::Geometry::BIND_PER_PRIMITIVE:每个面使用相同的法线。 |
示例代码: |
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f)); // Z轴法线 geometry->setNormalArray(normals); geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); |
- 设置几何体拓补(addPrimitiveSet)
void addPrimitiveSet(osg::ref_ptr<osg::DrawArrays> primitiveSet): 添加绘制原始数组,这个函数用来指定如何通过顶点来绘制几何体,例如,使用 osg::DrawArrays 来绘制三角形、线段等; · osg::PrimitiveSet::POINTS - 绘制独立的点,每个顶点作为一个点来绘制; · osg::PrimitiveSet::LINES - 绘制一系列线段,每两个顶点定义一条线段; · osg::PrimitiveSet::LINE_STRIP - 绘制一条折线,连接一系列顶点,形成连续的线条; · osg::PrimitiveSet::LINE_LOOP - 绘制一个闭合的折线,连接顶点并形成闭环; · osg::PrimitiveSet::TRIANGLES - 绘制三角形,每三个顶点定义一个三角形; · osg::PrimitiveSet::TRIANGLE_STRIP - 绘制三角形带,每个新顶点与前两个顶点共同形成一个三角形; · osg::PrimitiveSet::TRIANGLE_FAN - 绘制三角形扇形,第一个顶点作为中心,与后续顶点一起形成三角形; · osg::PrimitiveSet::QUADS - 绘制四边形,每四个顶点定义一个四边形; · osg::PrimitiveSet::QUAD_STRIP - 绘制四边形带,每两个新顶点与前两个顶点共同形成一个四边形; · osg::PrimitiveSet::POLYGON - 绘制多边形,顶点按顺序连接形成闭合的多边形; · osg::PrimitiveSet::LINES_ADJACENCY - 绘制带有邻接线段的线段; · osg::PrimitiveSet::LINE_STRIP_ADJACENCY - 绘制带有邻接折线的折线; · osg::PrimitiveSet::TRIANGLES_ADJACENCY - 绘制带有邻接三角形的三角形; · osg::PrimitiveSet::TRIANGLE_STRIP_ADJACENCY - 绘制带有邻接三角形带的三角形带。 |
示例代码: |
osg::ref_ptr<osg::DrawArrays> drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3); geometry->addPrimitiveSet(drawArrays); |
- 绑定纹理(setTextureAttributeAndModes)
getOrCreateStateSet() 方法用于获取与 geom(即几何体)相关联的 osg::StateSet 对象,如果 geom 没有 StateSet,它会自动创建一个。 StateSet 用于管理渲染状态,例如纹理、着色器、混合模式等。 setTextureAttributeAndModes() 方法用于将纹理设置到 StateSet 中。 |
示例代码: |
osg::Texture2D* texture = new osg::Texture2D; texture->setImage(pImage); osg::StateSet* stateset = geom->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); |
五、OSG读写库(osgDB)
负责与文件系统交互,进行模型、纹理和其他数据的加载、保存及管理。 |
- 读取图像数据(readRefImageFile)
头文件:#include <osgDB/ReadFile> |
osgDB::readRefImageFile 是 OpenSceneGraph (OSG) 中的一个函数,用于从文件读取图像数据并返回一个引用计数的图像对象(osg::Image),该函数可以自动根据文件扩展名选择合适的图像格式加载图像,支持常见的图像格式如 BMP、PNG、JPEG、TIFF 等。 |
示例代码: |
osg::ref_ptr<osg::Image>pImage = osgDB::readRefImageFile(filename); if (pImage) { osg::Texture2D* texture = new osg::Texture2D; texture->setImage(pImage); osg::StateSet* stateset = geom->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); } |
六、OSG查看器(osgViewer::Viewer)
头文件:#include <osgViewer/Viewer> |
功能:osgViewer::Viewer 是 OpenSceneGraph 提供的一个视图渲染器,帮助用户启动、设置和控制图形窗口、场景和渲染循环,提供设置视图、相机、渲染模式等功能,用于创建一个简单的 OpenGL 渲染应用。 函数: · int run(); // 启动视图渲染循环 · void setSceneData(osg::Node* scene); // 设置场景图数据 · osg::ref_ptr<osg::View> getView() const; // 获取当前视图 · void setCamera(osg::ref_ptr<osg::Camera> camera); // 设置渲染所用的相机 · osg::ref_ptr<osg::Camera> getCamera() const; // 获取当前使用的相机 · void setLightingMode(osg::View::LightingMode mode); // 设置光照模式 · void setMultiThreaded(bool multiThreaded); // 启用或禁用多线程渲染 · void setDrawFPS(bool drawFPS); // 是否在窗口显示帧率 · bool getDrawFPS() const; // 获取是否显示帧率的设置 · void setUpViewInWindow(int x, int y, int width, int height); // 设置窗口位置和大小 · void setReleaseContextAtEndOfFrameHint(bool hint); // 控制 OpenGL 上下文在帧结束时是否释放 · void setCameraManipulator(osgGA::CameraManipulator* manipulator); // 设置自定义相机操作器 |
七、OSG示例代码
- 立方骰子
#include <osg/Group> #include <osg/Geode> #include <osg/MatrixTransform> #include <osg/Texture2D> #include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osgDB/WriteFile> #include <osg/ref_ptr> // 创建四边形面 // pt1--------pt2 // | | // | | // pt4-------pt3 osg::ref_ptr<osg::Geometry> createFace(osg::Vec3& pt1, osg::Vec3& pt2, osg::Vec3& pt3, osg::Vec3& pt4, std::string& filename) { // 几何对象 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); // 顶点数组 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(6); (*vertices)[0] = pt1; (*vertices)[1] = pt2; (*vertices)[2] = pt3; (*vertices)[3] = pt3; (*vertices)[4] = pt4; (*vertices)[5] = pt1; geom->setVertexArray(vertices); // 纹理坐标数组 osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array(6); (*texcoords)[0].set(0.0f, 1.0f); (*texcoords)[1].set(1.0f, 1.0f); (*texcoords)[2].set(1.0f, 0.0f); (*texcoords)[3].set(1.0f, 0.0f); (*texcoords)[4].set(0.0f, 0.0f); (*texcoords)[5].set(0.0f, 1.0f); geom->setTexCoordArray(0, texcoords); // 法线 osg::Vec3 normal = (pt1 - pt2) ^ (pt3 - pt2); normal.normalize(); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array(1); (*normals)[0] = normal; geom->setNormalArray(normals, osg::Array::BIND_OVERALL); // 颜色数组 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1); (*colors)[0].set(1.0f, 1.0f, 1.0f, 1.0f); geom->setColorArray(colors, osg::Array::BIND_OVERALL); // 绘制指令 geom->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 6)); // 加载纹理 osg::ref_ptr<osg::Image>pImage = osgDB::readRefImageFile(filename); if (pImage) { osg::Texture2D* texture = new osg::Texture2D; texture->setImage(pImage); osg::StateSet* stateset = geom->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); } return geom; } // 创建立方体 osg::ref_ptr<osg::Geode> createCube() { osg::ref_ptr<osg::Geode> pGeode = new osg::Geode(); { osg::Vec3 pt1(-1, -1, -1); osg::Vec3 pt2(1, -1, -1); osg::Vec3 pt3(1, 1, -1); osg::Vec3 pt4(-1, 1, -1); std::string imageFile = "./Images/6.png"; osg::ref_ptr<osg::Geometry>pGeoBottom = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoBottom) { pGeode->addChild(pGeoBottom); } } { osg::Vec3 pt1(-1, 1, 1); osg::Vec3 pt2(1, 1, 1); osg::Vec3 pt3(1, -1, 1); osg::Vec3 pt4(-1, -1, 1); std::string imageFile = "./Images/5.png"; osg::ref_ptr<osg::Geometry>pGeoTop = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoTop) { pGeode->addChild(pGeoTop); } } { osg::Vec3 pt1(-1, -1, 1); osg::Vec3 pt2(1, -1, 1); osg::Vec3 pt3(1, -1, -1); osg::Vec3 pt4(-1, -1, -1); std::string imageFile = "./Images/1.png"; osg::ref_ptr<osg::Geometry>pGeoFront = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoFront) { pGeode->addChild(pGeoFront); } } { osg::Vec3 pt1(1, 1, 1); osg::Vec3 pt2(-1, 1, 1); osg::Vec3 pt3(-1, 1, -1); osg::Vec3 pt4(1, 1, -1); std::string imageFile = "./Images/3.png"; osg::ref_ptr<osg::Geometry>pGeoBack = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoBack) { pGeode->addChild(pGeoBack); } } { osg::Vec3 pt1(-1, 1, 1); osg::Vec3 pt2(-1, -1, 1); osg::Vec3 pt3(-1, -1, -1); osg::Vec3 pt4(-1, 1, -1); std::string imageFile = "./Images/4.png"; osg::ref_ptr<osg::Geometry>pGeoLeft = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoLeft) { pGeode->addChild(pGeoLeft); } } { osg::Vec3 pt1(1, -1, 1); osg::Vec3 pt2(1, 1, 1); osg::Vec3 pt3(1, 1, -1); osg::Vec3 pt4(1, -1, -1); std::string imageFile = "./Images/2.png"; osg::ref_ptr<osg::Geometry>pGeoRight = createFace(pt1, pt2, pt3, pt4, imageFile); if (pGeoRight) { pGeode->addChild(pGeoRight); } } return pGeode; } int main(int argc, char** argv) { osg::ref_ptr<osg::Geode> pGeode = createCube(); osgViewer::Viewer viewer; viewer.setSceneData(pGeode); return viewer.run(); } |