
Texture2D 与 Image
在 OSG(OpenSceneGraph)三维开发中,纹理贴图 是实现模型真实感渲染的核心手段,而 osg::Image 和 osg::Texture2D 是承载纹理数据、实现纹理渲染的两个关键类。
本文结合完整可编译运行的四边形纹理渲染源码 ,从类继承关系、核心功能、源码实战、工作流程四个维度,彻底讲透这两个类的用法与原理,让你一站式掌握 OSG 二维纹理渲染。
核心基础
OSG 所有核心类都继承自基类 osg::Object,遵循树形继承、职责分离 的设计思想,先理清 Image 和 Texture2D 的继承链,才能理解它们的分工:
1. osg::Image 继承关系
osg::Image 是纯数据载体类,只负责存储图片的像素、宽高、格式等原始数据,与渲染无关:
osg::Object(OSG 所有对象基类)
└── osg::Image(图片原始数据容器)
- 职责:读取/存储/管理图片原始像素数据(如 PNG/JPG/GIF 的像素数组、分辨率、通道数)。
- 定位:相当于「图片文件的内存化身」,不参与渲染,只提供数据。
2. osg::Texture2D 继承关系
osg::Texture2D 是渲染状态类,负责将 Image 的数据交给 GPU,实现纹理采样渲染,继承链更长:
osg::Object
└── osg::StateAttribute(渲染状态属性基类:纹理、光照、混合等)
└── osg::Texture(纹理基类,封装通用纹理逻辑)
└── osg::Texture2D(二维纹理子类,最常用)
- 职责:将 Image 数据上传至 GPU,配置纹理渲染参数(过滤、环绕、数据更新方式)。
- 定位:相当于「图片数据与 GPU 之间的桥梁」,是渲染纹理的核心。
3. 两个类的核心分工总结
| 类名 | 继承源头 | 核心作用 | 与渲染的关系 |
|---|---|---|---|
osg::Image |
直接继承 Object |
存储图片原始像素数据 | 无渲染能力 |
osg::Texture2D |
继承 StateAttribute |
管理 GPU 纹理,控制渲染效果 | 直接参与渲染 |
简单说:Image 管「数据」,Texture2D 管「渲染」,二者配合才能完成纹理贴图。
完整可运行源码(四边形纹理渲染)
以下是完整可直接编译、运行 的 OSG 代码,集成了 Image 加载、Texture2D 纹理绑定、四边形渲染全流程,是本文讲解的核心实践案例:
cpp
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/Texture2D>
#include <osg/StateSet>
#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
#include <iostream>
// 创建一个带纹理坐标的四边形节点
osg::ref_ptr<osg::Node> createTextureQuad()
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();
// 1. 设置四边形顶点(XY平面,Z=0)
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(1.0f, 0.0f, 1.0f)); // 右上角
vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f)); // 左上角
geom->setVertexArray(vertices.get());
// 2. 设置纹理坐标(UV映射,对应图片四个角)
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(1.0f, 1.0f)); // 纹理右上角
texCoords->push_back(osg::Vec2(0.0f, 1.0f)); // 纹理左上角
geom->setTexCoordArray(0, texCoords.get()); // 绑定到第0层纹理单元
// 3. 设置法线(保证光照渲染正常)
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array();
normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
geom->setNormalArray(normals.get());
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
// 4. 绘制四边形图元
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
geode->addDrawable(geom.get());
return geode.get();
}
// 创建Texture2D纹理状态(核心:绑定Image,配置纹理参数)
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
// 状态集:管理纹理、光照等渲染状态
osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet();
// 核心:创建二维纹理对象
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
// 设置数据更新模式:动态纹理(可修改)
texture->setDataVariance(osg::Object::DYNAMIC);
// 核心API:将Image数据绑定到Texture2D
texture->setImage(image.get());
// 优化纹理效果:线性过滤
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
// 将纹理添加到状态集并开启
stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
return stateSet;
}
int main()
{
// 1. 创建OSG渲染窗口
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> root = new osg::Group();
// ==================== Image 核心使用:加载图片数据 ====================
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");
if (!image.valid())
{
std::cerr << "错误:图片加载失败,请检查路径!" << std::endl;
return -1;
}
std::cout << "图片加载成功!宽:" << image->s() << " 高:" << image->t() << std::endl;
// 2. 创建四边形节点
osg::ref_ptr<osg::Node> quadNode = createTextureQuad();
// 3. 绑定纹理到节点
osg::ref_ptr<osg::StateSet> textureState = createTexture2DState(image);
quadNode->setStateSet(textureState.get());
// 4. 构建场景树
root->addChild(quadNode.get());
// 5. 优化场景并启动渲染
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
viewer->setSceneData(root.get());
viewer->realize();
std::cout << "渲染启动成功,鼠标操作:左键旋转,滚轮缩放,中键平移" << std::endl;
return viewer->run();
}

osg::Image 类:图片数据的「内存容器」
osg::Image 是 OSG 中处理图片原始数据的唯一入口,完整源码中通过 osgDB::readImageFile 加载图片 ,本质就是将磁盘文件转为 Image 对象。
1. 核心功能
- 加载图片 :通过
osgDB::readImageFile读取磁盘图片(支持 PNG/JPG/BMP/GIF 等所有常见格式); - 存储数据 :保存图片的宽、高、像素格式(RGB/RGBA)、原始像素数组;
- 内存管理 :基于 OSG 智能指针(
ref_ptr)自动释放内存,避免泄漏。
2. 源码中的核心用法
cpp
// 加载磁盘图片,创建Image对象(纯数据载体)
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");
// 判空校验
if (!image.valid()) {
std::cerr << "图片加载失败!" << std::endl;
return -1;
}
// 获取图片属性
int width = image->s(); // 图片宽度
int height = image->t(); // 图片高度
osg::Texture2D 类:GPU 渲染的「纹理桥梁」
osg::Texture2D 是二维纹理渲染的核心,本身不存储图片数据 ,而是通过 setImage() 绑定 Image 对象,将数据上传到 GPU 并配置渲染规则。
1. 核心功能
- 绑定 Image 数据 :关联
osg::Image,将像素数据传递给 GPU; - 配置纹理参数:设置过滤模式(抗锯齿)、环绕模式、数据更新频率;
- GPU 资源管理:自动管理纹理显存,程序退出时自动释放。
2. 源码中的核心用法
cpp
// 创建Texture2D对象
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
// 设置数据更新模式:动态纹理
texture->setDataVariance(osg::Object::DYNAMIC);
// 核心API:绑定Image数据(数据→渲染的关键衔接)
texture->setImage(image.get());
// 配置纹理过滤(抗锯齿,提升显示效果)
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
Texture2D 与 Image 协同工作流程
在本文的完整源码中,Image 和 Texture2D 的配合流程是纹理渲染的核心,拆解如下:
完整工作流
- 加载图片 → 创建 Image
调用osgDB::readImageFile读取磁盘图片,生成osg::Image对象,存储原始像素数据; - 创建 Texture2D → 绑定 Image
实例化osg::Texture2D,通过setImage关联 Image,将图片数据交给纹理类; - 纹理绑定到状态集 → 交给节点
Texture2D作为渲染状态,添加到StateSet(状态集),再挂载到四边形节点; - GPU 渲染 → 显示纹理
OSG 渲染时,Texture2D将数据上传至 GPU,结合顶点纹理坐标,完成四边形贴图。
源码对应核心代码
cpp
// 步骤1:Image 加载图片原始数据
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");
// 步骤2:Texture2D 绑定 Image 数据(核心衔接)
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
texture->setImage(image.get());
// 步骤3:纹理加入状态集,绑定到渲染节点
stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
quadNode->setStateSet(stateSet.get());
总结
- 继承关系 :
Image直接继承Object(纯数据层),Texture2D继承StateAttribute(渲染状态层); - 核心分工 :
osg::Image负责存储图片原始数据 ,osg::Texture2D负责将数据传递给 GPU 渲染; - 使用关键 :先通过
osgDB加载Image,再用setImage绑定到Texture2D,最后挂载到节点完成渲染。
