OSG自定义拖拽器

#ifndef _OSG_TRACKBALL_AND_TRANSLATEAXIS_DRAGGER_
#define _OSG_TRACKBALL_AND_TRANSLATEAXIS_DRAGGER_

#include <osgManipulator/TrackballDragger>
#include <osgManipulator/TranslateAxisDragger>
#include <osgManipulator/TranslatePlaneDragger>
#include <osgManipulator/RotateCylinderDragger>
#include <osgManipulator/Dragger>

/**	@class TranslatePlaneDraggerXY [TranslatePlaneDraggerXY.h]
 *	@brief 平面拖拽器XY
 *  
*/
class TranslatePlaneDraggerXY : public osgManipulator::TranslatePlaneDragger
{
public:
    // 修改平面操作器的方向
    void setupDefaultGeometryXY();
};


/**	@class RotateCylinderDraggerZ [RotateCylinderDraggerZ.h]
 *	@brief 圆柱z拖拽器
 *  
*/
class RotateCylinderDraggerZ : public osgManipulator::RotateCylinderDragger
{
public:
    // 修改圆柱体操作器的形状,使之壁薄,高度减小,上颜色
    void setupDefaultGeometryZ();
    osg::Geometry* createDiskGeometry(float radius, float offset, float z, unsigned int numSegments);

protected:
    virtual bool handle(const osgManipulator::PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override;

private:
    osg::ShapeDrawable* m_ptrCylinderDrawableOutter;
    osg::ShapeDrawable* m_ptrCylinderDrawableIntter;


};

/**	@class  TrackballAndTranslateAxisDragger[TrackballAndTranslateAxisDragger.h]
*	@brief  圆柱z拖拽和平面拖拽XY的合集
//球形拖拽器和XYZ轴拖拽器的合集
*
*/
class CustomDragger : public osgManipulator::CompositeDragger
{
public:

    CustomDragger();

    void setupDefaultGeometry();

protected:

    virtual ~CustomDragger();

    osg::ref_ptr<TranslatePlaneDraggerXY>  m_translateAxisDraggerXY;    
    osg::ref_ptr<RotateCylinderDraggerZ>  m_rotateCylinderDragger;    
};

#endif // _OSG_TRACKBALL_AND_TRANSLATEAXIS_DRAGGER_

#include "CustomDragger.h"

void TranslatePlaneDraggerXY::setupDefaultGeometryXY()
{
    osg::Quat rotation; rotation.makeRotate(osg::Vec3(0.0f, 0.0f, 1.0f), osg::Vec3(0.0f, 1.0f, 0.0f));
    _translate2DDragger->setMatrix(osg::Matrix(rotation)*osg::Matrix::translate(osg::Vec3(0.0, 0.0, 0.0)));
}

///
osg::Geometry* RotateCylinderDraggerZ::createDiskGeometry(float radius, float offset, float z, unsigned int numSegments)
{
    osg::ref_ptr<osg::Vec4Array> boundaryColors = new osg::Vec4Array;
    //boundaryColors->push_back(osg::Vec4(0, 0, 0, 1.0));

    const float angleDelta = 2.0f*osg::PI / float(numSegments);
    const unsigned int numPoints = (numSegments + 1) * 2;
    float angle = 0.0f;
    osg::Vec3Array* vertexArray = new osg::Vec3Array(numPoints);
    osg::Vec3Array* normalArray = new osg::Vec3Array(numPoints);
    unsigned int p = 0;
    for (unsigned int i = 0; i < numSegments; ++i, angle += angleDelta)
    {
        float c = cosf(angle);
        float s = sinf(angle);
        // Outer point
        (*vertexArray)[p].set(radius*c, radius*s, z);
        (*normalArray)[p].set(0.0, 0.0, -1.0);
        ++p;
        // Inner point
        (*vertexArray)[p].set((radius - offset)*c, (radius - offset)*s, z);
        (*normalArray)[p].set(0.0, 0.0, -1.0);
        ++p;
    }
    // do last points by hand to ensure no round off errors.
    (*vertexArray)[p] = (*vertexArray)[0];
    (*normalArray)[p] = (*normalArray)[0];
    ++p;
    (*vertexArray)[p] = (*vertexArray)[1];
    (*normalArray)[p] = (*normalArray)[1];

    osg::Geometry* geometry = new osg::Geometry;
    geometry->setVertexArray(vertexArray);
    geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
    //geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);   // 填充圆柱的上下表面
    //geometry->setColorArray(boundaryColors.get(), osg::Array::BIND_OVERALL);

    return geometry;
}

void RotateCylinderDraggerZ::setupDefaultGeometryZ()
{
    osg::Geode* geode = new osg::Geode;
    {
        osg::TessellationHints* hints = new osg::TessellationHints;
        hints->setCreateTop(false);
        hints->setCreateBottom(false);
        hints->setCreateBackFace(false);

        float radius = 1.0f;
        float height = 0.05f;
        float thickness = 0.02f;

        // outer cylinder
        osg::Cylinder* cylinder = new osg::Cylinder;
        cylinder->setHeight(height);
        cylinder->setRadius(radius);
        m_ptrCylinderDrawableOutter = new osg::ShapeDrawable(cylinder, hints);
        m_ptrCylinderDrawableOutter->setColor(osg::Vec4(1.0, 0, 0, 1.0));
        geode->addDrawable(m_ptrCylinderDrawableOutter);

        // inner cylinder
        osg::Cylinder* cylinder1 = const_cast<osg::Cylinder*>(_projector->getCylinder());
        cylinder1->setHeight(height);
        cylinder1->setRadius(radius - thickness);
        m_ptrCylinderDrawableIntter = new osg::ShapeDrawable(cylinder1, hints);
        m_ptrCylinderDrawableIntter->setColor(osg::Vec4(1.0, 0, 0, 1.0));
        geode->addDrawable(m_ptrCylinderDrawableIntter);

        // top
        geode->addDrawable(createDiskGeometry(radius, thickness, height / 2, 100));
        // bottom
        geode->addDrawable(createDiskGeometry(radius, thickness, - height / 2, 100));
    }
    addChild(geode);
}

bool RotateCylinderDraggerZ::handle(const osgManipulator::PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    // Check if the dragger node is in the nodepath.
    if (!pointer.contains(this)) return false;

    switch (ea.getEventType())
    {
        // Pick start.
    case (osgGA::GUIEventAdapter::PUSH):
    {
        // Get the LocalToWorld matrix for this node and set it for the projector.
        osg::NodePath nodePathToRoot;
        computeNodePathToRoot(*this, nodePathToRoot);
        osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot);
        _projector->setLocalToWorld(localToWorld);

        _startLocalToWorld = _projector->getLocalToWorld();
        _startWorldToLocal = _projector->getWorldToLocal();

        if (_projector->isPointInFront(pointer, _startLocalToWorld))
            _projector->setFront(true);
        else
            _projector->setFront(false);

        osg::Vec3d projectedPoint;
        if (_projector->project(pointer, projectedPoint))
        {
            // Generate the motion command.
            osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();
            cmd->setStage(osgManipulator::MotionCommand::START);
            cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);

            // Dispatch command.
            dispatch(*cmd);

            // Set color to pick color.
            setMaterialColor(_pickColor, *this);
            m_ptrCylinderDrawableOutter->setColor(osg::Vec4(1.0, 1.0, 0.0, 1.0));
            m_ptrCylinderDrawableIntter->setColor(osg::Vec4(1.0, 1.0, 0.0, 1.0));

            _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld();
            _prevRotation = osg::Quat();

            aa.requestRedraw();
        }
        return true;
    }

    // Pick move.
    case (osgGA::GUIEventAdapter::DRAG):
    {
        // Get the LocalToWorld matrix for this node and set it for the projector.
        osg::Matrix localToWorld = osg::Matrix(_prevRotation) * _startLocalToWorld;
        _projector->setLocalToWorld(localToWorld);

        osg::Vec3d projectedPoint;
        if (_projector->project(pointer, projectedPoint))
        {
            osg::Vec3d prevProjectedPoint = _prevWorldProjPt * _projector->getWorldToLocal();
            osg::Quat  deltaRotation = _projector->getRotation(prevProjectedPoint,
                projectedPoint);
            osg::Quat rotation = deltaRotation * _prevRotation;

            // Generate the motion command.
            osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();
            cmd->setStage(osgManipulator::MotionCommand::MOVE);
            cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);
            cmd->setRotation(rotation);

            // Dispatch command.
            dispatch(*cmd);

            _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld();
            _prevRotation = rotation;
            aa.requestRedraw();
        }
        return true;
    }

    // Pick finish.
    case (osgGA::GUIEventAdapter::RELEASE):
    {
        osg::ref_ptr<osgManipulator::Rotate3DCommand> cmd = new osgManipulator::Rotate3DCommand();

        cmd->setStage(osgManipulator::MotionCommand::FINISH);
        cmd->setLocalToWorldAndWorldToLocal(_startLocalToWorld, _startWorldToLocal);

        // Dispatch command.
        dispatch(*cmd);

        // Reset color.
        setMaterialColor(_color, *this);
        m_ptrCylinderDrawableOutter->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
        m_ptrCylinderDrawableIntter->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
        aa.requestRedraw();

        return true;
    }
    default:
        return false;
    }
}

///

CustomDragger::CustomDragger()
{
    m_translateAxisDraggerXY = new TranslatePlaneDraggerXY();
    m_translateAxisDraggerXY->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
    addChild(m_translateAxisDraggerXY.get());
    addDragger(m_translateAxisDraggerXY.get());

    m_rotateCylinderDragger = new RotateCylinderDraggerZ();
    addChild(m_rotateCylinderDragger.get());
    addDragger(m_rotateCylinderDragger.get());


    setParentDragger(getParentDragger());
}

CustomDragger::~CustomDragger()
{
}

void CustomDragger::setupDefaultGeometry()
{
    m_translateAxisDraggerXY->setupDefaultGeometry();
    m_translateAxisDraggerXY->setupDefaultGeometryXY();
    m_rotateCylinderDragger->setupDefaultGeometryZ();
}

简述:为了实现仅允许在osg的XY平面进行平移和旋转的功能,这里创建了2个自定义拖拽器

1 osgManipulator::CompositeDragger提供给了用户自定义组合想要的拖拽器,你可以将任意简单的Dragger进行组合添加到CompositeDragger中
2 osgManipulator::TranslatePlaneDragger的默认拖拽器是平行于Z轴的,所以需要将_translate2DDragger进行矩阵变换;
  osgManipulator::RotateCylinderDragger的圆柱体拖拽面积和颜色是可以进行自定义的

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页