在 OpenSceneGraph (OSG)
中,操作器(Manipulator
)是用于控制视图和场景交互的核心组件。
常见的操作器包括 TrackballManipulator
(轨迹球模式)、FlightManipulator
(飞行模式)等。
通过使用这些操作器,用户可以以不同的方式与场景进行交互。
今天我们将深入探讨如何切换轨迹球模式和飞行模式,并实现一个自定义的操作器。
切换轨迹球模式和飞行模式
- 轨迹球模式 (
TrackballManipulator
):模拟一个虚拟的球体,允许用户通过鼠标拖动来旋转、平移和缩放场景。 - 飞行模式 (
FlightManipulator
):模拟飞行器的行为,可以通过键盘和鼠标控制视角的移动,适合大范围场景的浏览。
实战:切换操作器
在 OSG 中,可以通过 osgViewer::Viewer
的 setCameraManipulator()
方法来动态切换操作器。
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgDB/ReadFile>
#include <iostream>
int main()
{
// 创建 Viewer
osgViewer::Viewer viewer;
// 加载模型
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cessna.osg");
if (!model)
{
std::cerr << "无法加载模型!" << std::endl;
return -1;
}
viewer.setSceneData(model);
// 默认使用轨迹球操作器
viewer.setCameraManipulator(new osgGA::TrackballManipulator);
// 主循环中监听按键切换操作器
while (!viewer.done())
{
viewer.frame();
// 检测按键
if (viewer.getEventQueue()->keyDown('t'))
{
std::cout << "切换到轨迹球模式..." << std::endl;
viewer.setCameraManipulator(new osgGA::TrackballManipulator);
}
else if (viewer.getEventQueue()->keyDown('f'))
{
std::cout << "切换到飞行模式..." << std::endl;
viewer.setCameraManipulator(new osgGA::FlightManipulator);
}
}
return 0;
}
运行效果
- 按下
t
键切换到轨迹球模式。 - 按下
f
键切换到飞行模式。
实战:实现自定义操作器
如果内置的操作器无法满足需求,我们可以继承 osgGA::CameraManipulator
类来实现自定义操作器。
自定义操作器的基本结构
自定义操作器需要重写以下方法:
home()
:重置操作器到初始状态。handle()
:处理事件(如鼠标、键盘输入)。getMatrix()
和getInverseMatrix()
:返回摄像机的变换矩阵和逆矩阵。
代码实例
以下是一个简单的自定义操作器示例,它会根据鼠标拖动改变摄像机的位置。
#include <osgGA/CameraManipulator>
#include <osg/Matrixd>
#include <osg/Quat>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <iostream>
class CustomManipulator : public osgGA::CameraManipulator
{
public:
CustomManipulator() : _center(0, 0, 0), _distance(10.0) {}
// 重置到初始状态
void home(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override
{
_center = osg::Vec3(0, 0, 0);
_distance = 10.0;
}
// 处理事件
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::DRAG:
// 根据鼠标移动改变中心点
_center.x() += ea.getDX() * 0.1;
_center.y() -= ea.getDY() * 0.1;
return true;
default:
return false;
}
}
// 获取摄像机矩阵
osg::Matrixd getMatrix() const override
{
return osg::Matrixd::translate(osg::Vec3(0, 0, _distance)) *
osg::Matrixd::translate(_center);
}
// 获取逆矩阵
osg::Matrixd getInverseMatrix() const override
{
return osg::Matrixd::inverse(getMatrix());
}
private:
osg::Vec3 _center; // 相机注视的中心点
double _distance; // 相机到中心点的距离
};
int main()
{
// 创建 Viewer
osgViewer::Viewer viewer;
// 加载模型
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cessna.osg");
if (!model)
{
std::cerr << "无法加载模型!" << std::endl;
return -1;
}
viewer.setSceneData(model);
// 使用自定义操作器
viewer.setCameraManipulator(new CustomManipulator);
// 开始渲染循环
return viewer.run();
}