博客
关于我
Implementation Model Editor of AVEVA in OpenSceneGraph
阅读量:797 次
发布时间:2023-03-25

本文共 6143 字,大约阅读时间需要 20 分钟。

Implementation Model Editor of AVEVA in OpenSceneGraph

本文详细介绍了工厂和海工设计软件AVEVA的交互方式,并阐述了OpenSceneGraph中的人机交互工具拖拽器的实现方法。在该框架中,我们成功实现了模型的直接交互操作。对对三维建模感兴趣的读者可以结合其源代码,对其实现细节进行深入分析。


一、引言

在当代三维辅助设计软件中,交互建模设计已成为主流。友好、高效的对三维模型直接编辑或修改,不仅提高了用户的工作效率,也为用户留下了良好的用户体验。常见的交互建模方法包括拖曳、约束、栅格捕捉、橡皮筋方法和引力场方法等。如何设计高效、友好、方便的用户接口,是当前各开发系统厂家和专家共同关心的问题,其设计好坏直接影响用户是否接受产品。

本文主要介绍了AVEVA的交互建模方式,详细说明了OpenSceneGraph中拖拽器的工作原理,并在其中实现了模型的直接交互操作。通过实践,发现OpenSceneGraph的代码规范和设计非常优秀。对于对交互建模感兴趣的读者,可以结合其源代码,对实现细节进行深入分析。


二、AVEVA模型编辑器

AVEVA(原CADCENTRE)是国际知名的工厂工程信息技术企业,总部位于英国剑桥。AVEVA提供的工厂工程一体化解决方案涵盖多个行业,包括石油天然气、电力、化工等。其交互建模功能以Model Editor为核心,用户可以通过鼠标直接对模型进行操作,如轴向移动、平面移动、旋转和对齐等。

Model Editor的Handle允许用户对模型进行多种方式的编辑。例如,通过Linear and Planar handles进行轴向或平面移动,移动距离可通过设置移动增量来精确控制。旋转操作则通过Rotation handle完成,旋转增量可设置以确保精度。对齐功能则允许用户将模型对齐到点、边或面,提供了高效的交互体验。


三、OpenSceneGraph拖拽器

OpenSceneGraph由Don Burns和Robert Osfield共同开发,是一款广泛应用于三维场景渲染的开源引擎。其核心优势包括快速开发、高品质、高性能以及开源特性。OpenSceneGraph提供了多种拖拽器,满足不同交互需求。

常见拖拽器类型包括:

  • TabPlaneDragger:支持平面缩放,适用于二维平面上的操作。
  • TabPlaneTrackballDragger:结合平面缩放和轨迹球拖拽功能,提供灵活的交互方式。
  • TrackballDragger:专注于旋转操作,适用于需要精确控制的场景。
  • Translate1DDragger:支持沿直线平移,适用于单轴移动。
  • Translate2DDragger:在平面上进行二维平移,适用于复杂场景的操作。
  • TranslateAxisDragger:支持三维平移,提供全方位控制。
  • TabBoxDragger:由六个平面拖拽器组成,支持多面缩放和平移。
  • 通过组合模式(CompositeDragger),开发者可以将拖拽器灵活组合,例如将TranslateAxisDragger组合成三维平称拖拽器。OpenSceneGraph的开源特性使其适合定制化需求,例如与AVEVA的Model Editor类似的操作方式。


    四、示例程序

    为了实现模型的拖拽操作,我们可以通过以下步骤进行:

  • 定义带拖拽器的节点ModelShape,集成TranslateAxisDragger等拖拽器,并设置其矩阵变换。
  • 实现PickHandler类,用于处理选择事件,打开或关闭拖拽器。
  • 在主函数中构建场景,加载模型并设置拖拽器。
  • 以下是示例代码:

    #pragma once
    #include
    #include
    #include
    #include
    class ModelShape : public osg::Group
    {
    public:
    ModelShape(osg::Node* shape);
    ~ModelShape(void);
    void EnableDragger(void);
    void DisableDragger(void);
    void setMatrix(const osg::Matrix& matrix);
    private:
    osg::ref_ptr
    mShape;
    osg::ref_ptr
    mDragger; osg::ref_ptr
    mSelection; };
    #include "ModelShape.h"
    ModelShape::ModelShape(osg::Node* shape) : mShape(shape), mDragger(new TranslateAxisDragger()), mSelection(new Selection())
    {
    float scale = shape->getBound().radius() * 1.6;
    mDragger->setMatrix(osg::Matrix::scale(scale, scale, scale) *
    osg::Matrix::translate(shape->getBound().center()));
    mDragger->setupDefaultGeometry();
    mSelection->addChild(shape);
    addChild(mSelection);
    }
    ModelShape::~ModelShape(void)
    {
    }
    void ModelShape::EnableDragger(void)
    {
    addChild(mDragger);
    mDragger->addTransformUpdating(mSelection);
    mDragger->setHandleEvents(true);
    }
    void ModelShape::DisableDragger(void)
    {
    removeChild(mDragger);
    mDragger->removeTransformUpdating(mSelection);
    mDragger->setHandleEvents(false);
    }
    #pragma once
    #include
    class PickHandler : public GUIEventHandler
    {
    public:
    PickHandler(void);
    ~PickHandler(void);
    virtual bool handle(const GUIEventAdapter& ea, GUIActionAdapter& aa);
    void pick(const GUIEventAdapter& ea, GUIActionAdapter& aa);
    private:
    float mX;
    float mY;
    bool mEnableDragger;
    };
    #include "PickHandler.h"
    #include "ModelShape.h"
    PickHandler::PickHandler(void) : mX(0.0f), mY(0.0f), mEnableDragger(true)
    {
    }
    PickHandler::~PickHandler(void)
    {
    }
    bool PickHandler::handle(const GUIEventAdapter& ea, GUIActionAdapter& aa)
    {
    View* view = dynamic_cast
    (aa);
    if (NULL == view)
    {
    return false;
    }
    switch (ea.getEventType())
    {
    case PUSH:
    {
    mX = ea.getX();
    mY = ea.getY();
    break;
    }
    case RELEASE:
    {
    if (ea.getX() == mX && ea.getY() == mY)
    {
    pick(ea, aa);
    }
    break;
    }
    case KEYDOWN:
    {
    if (ea.getKey() == 'd')
    {
    mEnableDragger = !mEnableDragger;
    }
    break;
    }
    default:
    break;
    }
    return false;
    }
    void PickHandler::pick(const GUIEventAdapter& ea, GUIActionAdapter& aa)
    {
    View* view = dynamic_cast
    (aa);
    LineSegmentIntersector::Intersections hits;
    if (view->computeIntersections(ea.getX(), ea.getY(), hits))
    {
    LineSegmentIntersector::Intersection intersection = *hits.begin();
    NodePath& nodePath = intersection.nodePath;
    int nNodeSize = nodePath.size();
    if (nNodeSize > 0)
    {
    Node* node = nodePath[nNodeSize - 1];
    Node* grandParent = node->getParent(0)->getParent(0);
    ModelShape* shape = dynamic_cast
    (grandParent);
    if (shape)
    {
    mEnableDragger ? shape->EnableDragger() : shape->DisableDragger();
    }
    }
    }
    }
    #include 
    #include
    #include
    using namespace std;
    int main(void)
    {
    Viewer viewer;
    RefPtr
    root = new Group();
    for (int i = 1; i < 10; ++i)
    {
    for (int j = 1; j < 10; ++j)
    {
    RefPtr
    box = new MatrixTransform();
    RefPtr
    glider = new MatrixTransform(); box->setMatrix(osg::Matrix::translate(i * 6.0, j * 6.0, 0.0)); glider->setMatrix(osg::Matrix::translate(i * 2.5, j * 2.5, 6.0)); box->addChild(new ModelShape(osgDB::readNodeFile("box.stl"))); glider->addChild(new ModelShape(osgDB::readNodeFile("glider.osg"))); root->addChild(box); root->addChild(glider); } } viewer.setSceneData(root.get()); viewer.addEventHandler(new StatsHandler()); viewer.addEventHandler(new WindowSizeHandler()); viewer.addEventHandler(new StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); viewer.addEventHandler(new PickHandler()); viewer.run(); }

    五、结论

    通过实践,我们发现OpenSceneGraph的人机交互方式非常友好,提供了灵活的拖拽器来操纵模型。拖拽器采用组合模式设计,便于扩展和定制。OpenSceneGraph的开源特性使其适合调试和定制,同时避免了知识产权问题。

    此外,OpenSceneGraph还提供了丰富的仿真效果,如烟雾、火焰、粒子效果等,这些功能可以提升建模设计的体验。如果在建模过程中适量添加这些效果,相信会让您的作品更加酷炫。


    六、参考资料

  • AVEVA Graphical Model Manipulation Guide
  • Donald Hearn, M. Pauline Baker, Computer Graphics with OpenGL
  • 何援军, 计算机图形学
  • 王锐, 钱学雷, OpenSceneGraph三维渲染引擎设计与实践
  • 肖鹏, 刘更代, 徐明亮, OpenSceneGraph三维渲染引擎编程指南
  • 转载地址:http://nyhfk.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现找出由两个 3 位数字的乘积构成的最大回文数的算法 (附完整源码)
    查看>>
    Objective-C实现找出矩阵的最大最小值(附完整源码)
    查看>>
    Objective-C实现找到一个数字数组的中值算法(附完整源码)
    查看>>
    Objective-C实现找到具有 500 个除数的第一个三角形数算法(附完整源码)
    查看>>
    Objective-C实现找到最近的点对之间的距离算法(附完整源码)
    查看>>
    Objective-C实现抓包实例(附完整源码)
    查看>>
    Objective-C实现抽签抓阄(附完整源码)
    查看>>
    Objective-C实现抽象工厂模式(附完整源码)
    查看>>
    Objective-C实现拉格朗日插值法(附完整源码)
    查看>>
    Objective-C实现拷贝二进制文件(附完整源码)
    查看>>
    Objective-C实现指定内存空间获取时间的函数(附完整源码)
    查看>>
    Objective-C实现按位倒序(附完整源码)
    查看>>
    Objective-C实现按位运算符乘以无符号数multiplyUnsigned算法(附完整源码)
    查看>>
    Objective-C实现排队叫号系统(附完整源码)
    查看>>
    Objective-C实现控制NRP8S功率计读取功率 (附完整源码)
    查看>>
    Objective-C实现控制程控电源2306读取电流 (附完整源码)
    查看>>
    Objective-C实现摄氏温度和华氏温度互转(附完整源码)
    查看>>
    Objective-C实现播放器(附完整源码)
    查看>>
    Objective-C实现操作MySQL(附完整源码)
    查看>>
    Objective-C实现操作注册表 (附完整源码)
    查看>>