OpenSceneGraph中创建一个大小不变的小球

OpenSceneGraph中创建一个大小不变的小球

OpenSceneGraph中创建一个大小不变的小球

核心思想是利用osg::AutoTransform类。具体用法可以看osg自带的例子autotrans

功能验证代码,就不要纠结内存泄露不泄露的问题了,直接裸指针搞起。

核心功能在Build_No_Scaling()函数中。

不过有一个问题就是,为什么小球在缩放过程中会失去光照效果呢?尤其是场景变小(物体放大)的过程中。有知道的留言说一下吧。

直接上代码把


// OpenSceneGraph library.
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/ShapeDrawable>
#include <osg/LineWidth>
#include <osg/MatrixTransform>
#include <osgFX/Scribe>
#include <osgUtil/SmoothingVisitor>
//下面两个头文件设置点和线宽
#include <osg/Point>
#include <osg/AutoTransform>
#include <osg/Light>

#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgFXd.lib")

const osgFX::Scribe * one_scribe = NULL;



// 返回一个不缩放的小球. 但是为什么缩小的时候,才有光照呢?
osg::Node* Build_No_Scaling(float x, float y, float z)
{

    // 7. add a sphere 
    osg::Sphere* cylinder = new osg::Sphere(osg::Vec3f(x, y, z), 6.0f);
    osg::ShapeDrawable * drawable = new osg::ShapeDrawable(cylinder);
    drawable->setColor(osg::Vec4f(1.0, 0.5, 0.5, 0.0));
    osg::Geode*  geode = new osg::Geode;
    geode ->addDrawable(drawable);

    //  这里可以让圆球不缩放. 
    osg::AutoTransform* at = new osg::AutoTransform;
    at->addChild(geode);
    at->setMinimumScale(0.0);
    at->setMaximumScale(FLT_MAX);

    at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
    //at->setAutoRotateMode(osg::AutoTransform::NO_ROTATION);
    at->setAutoScaleToScreen(true);
    at->setScale(osg::Vec3f(1, 1, 1));
    at->setPosition(osg::Vec3f(x,y,z));

    return at;  
}

osg::Node* BuildScene(void)
{
    osg::ref_ptr<osg::Group> root = new osg::Group();

    osg::Cylinder* cylinder = new osg::Cylinder(osg::Vec3f(8.0, 0.0, 0.0), 10.0f, 25.0f);
    osg::ShapeDrawable * drawable = new osg::ShapeDrawable(cylinder);
    drawable->setColor(osg::Vec4f(1.0, 0.5, 0.5, 0.0));
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode ->addDrawable(drawable);
    root->addChild(geode);
    

    // 增加各种小球
    root->addChild(Build_No_Scaling(0, 0, 20));
    root->addChild(Build_No_Scaling(0, 20, 20));
    root->addChild(Build_No_Scaling(20, 0, 20));
    root->addChild(Build_No_Scaling(20, 20, 0));
    return root.release();
}


class RotateGlider : public osgGA::GUIEventHandler 
{
    public: 
        virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) 
        {
            osgViewer::Viewer* vw = dynamic_cast<osgViewer::Viewer*>(&aa); 
            if (vw) {
                //printf("key down : %d !\n", ea.getKey()); 
                osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(vw->getSceneData());
                if (mt) {
                printf("key down -2: %d !\n", ea.getKey()); 
                    static float i = 0.1f;
                    switch (ea.getEventType()) {
                        case osgGA::GUIEventAdapter::KEYDOWN: 
                            { 
                                if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left) {
                                    mt->setMatrix(osg::Matrix::rotate(i, osg::Vec3(0.f, 0.f, 1.f)));
                                    i += 0.0f; 
                                } 
                                else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right) {
                                    mt->setMatrix(osg::Matrix::rotate(i, osg::Vec3(0.f, 0.f, 1.f)));
                                    i -= 0.1f; 
                                } 
                            } 
                            break; 
                        default: break; 
                    } 
                } 
            }
            return false; 
        } 
}; 


class CPickHandler :public osgGA::GUIEventHandler
{
public:
	CPickHandler(osgViewer::Viewer* viewer) :mViewer(viewer){}
	virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		switch (ea.getEventType())
		{
		case(osgGA::GUIEventAdapter::PUSH):
			if (ea.getButton() == 1)
			{
				Pick(ea.getX(), ea.getY());
			}
		        return true;
		}
		return false;
	}
protected:
	void Pick(float x, float y)
	{
        
        // 1、创建一个线段的碰撞检测结果集. 

		osgUtil::LineSegmentIntersector::Intersections intersections;

        //
        // 2、使用computeIntersections计算点击到了哪些模型,结果存放在上面定义的碰撞检测结果集里。 
        //
        if (mViewer->computeIntersections(x, y, intersections))
		{
            printf("number-of-intersections:%d\n", intersections.size()); 
            int i = 0; 
            // 3、使用迭代器取出这些模型。取出的结果是一个NodePath类对象,遍历该NodePath对象可以找到是否单击到了目标节点。 
            //
			for (osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin(); hitr != intersections.end(); ++hitr)
            {

                printf("\tthe-%d-st intersection\n", ++i); 
                //4、将单击到的节点全部取出,进行判断 . 
                // 行为1. 
                // 行为2 选中的物体高亮.  高亮的策略就是删掉原来的对象node,而用一个新的node替代
                // 当然要求nodepath中至少有2个点. 
                //
                // 上面是网上的做法,奇怪的是,为什么不直接替代选中drawable对象的渲染模式呢?
                //
                const size_t np = hitr->nodePath.size(); 
                if ( np >= 2) {
                    osg::Node* const node = hitr->nodePath[np-1]; 
                    osg::Group* parent =  dynamic_cast<osg::Group*>(hitr->nodePath[np-2]); 
                    printf("nodepath len:%d nodename:%s  parent name:%s\n",  np, 
                            node->getName().c_str(), parent->getName().c_str()); 

                    //
                    // Scribe 是个 特效对象,将一个node构建好之后,放到scribe中去,然后渲染的时候
                    // 把scribe 加入到 root树(以前是直接加入node)就可以提供特效了.
                    //
                    osgFX::Scribe* parentAsScribe = NULL; 
                    parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent);
                    /*if (parent->isSameKindAs(one_scribe) ) {
                        printf("you clicked a node WITH wire frame!\n");
                        
                    }*/

                    if (!parentAsScribe)
                    {
                        //如果对象选择到,高亮显示, 就是新建一个Scribe对象替换原来的node对象. 
                        printf("you clicked a node WITHOUT wire frame!\n");
                        osg::ref_ptr<osgFX::Scribe> scribe = new osgFX::Scribe();
                        if (one_scribe == NULL) one_scribe = scribe.get();
                        scribe->setName("newly created scribe object"); 
                        scribe->addChild(node);
                        parent->replaceChild(node,scribe);
                    } else {
                        //如果没有选择到,则移除高亮显示的对象. 
                        
                        osg::Node::ParentList parentList = parentAsScribe->getParents();
                        printf("you clicked a node WITH wire frame num.parents:%d!\n", parentList.size());
                        for(osg::Node::ParentList::iterator itr=parentList.begin();
                                itr!=parentList.end();
                                ++itr)
                        {
                            (*itr)->replaceChild(parentAsScribe, node);
                            //break;
                        }
                    }

                }	
                break; // 一个选择会有多个命中,只处理一个.
            }
		}
	}
	osgViewer::Viewer* mViewer;
};

int main(void)
{
    osgViewer::Viewer myViewer;

    myViewer.getCamera()->setCullingMode(

        myViewer.getCamera()->getCullingMode() &

        ~osg::CullSettings::SMALL_FEATURE_CULLING); 
    /*
     这里还是有点奇怪.难道每棵树的根上都是mt对象?那么内置的handler是怎么处理的? 
     */
    osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
    mt->addChild(BuildScene());
    
    myViewer.setSceneData(mt);

	myViewer.addEventHandler(new CPickHandler(&myViewer));

    return myViewer.run();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值