zoukankan      html  css  js  c++  java
  • 实现自定义场景查询的方法

    转载请注明出处!http://www.cnblogs.com/pulas/

    场景管理器SceneManager还默认提供了创建场景查询的功能,下图为场景查询类继承关系图。

    clip_image002

    其中,射线场景查询RaySceneQuery可以用来拾取场景中的物体、地形碰撞检测和地形选择。下面示范如何在四叉树场景管理器中实现自定义的射线场景查询类。

    1. QuadtreeSceneManager覆盖其基类SceneManager的createRayQuery()方法,在其中创建四叉树射线场景查询QuadtreeRaySceneQuery类的实例。

    RaySceneQuery* QuadtreeSceneManager::createRayQuery(const Ray& ray, unsigned long mask)
    {
        QuadtreeRaySceneQuery* q = OGRE_NEW QuadtreeRaySceneQuery(this);
        q->setRay(ray);
        q->setQueryMask(mask);
        return q;
    }

    2. 从DefaultRaySceneQuery基类派生出QuadtreeRaySceneQuery类,并覆盖其中的两个execute()方法,在其中实现自己的场景查询算法。

    /** Quadtree implementation of RaySceneQuery. */
    class _QuadtreePluginExport QuadtreeRaySceneQuery : public DefaultRaySceneQuery
    {
    public:
        QuadtreeRaySceneQuery(SceneManager* creator);
        ~QuadtreeRaySceneQuery();
    
            /** Executes the query, returning the results back in one list.
            @remarks
                This method executes the scene query as configured, gathers the results
                into one structure and returns a reference to that structure. These
                results will also persist in this query object until the next query is
                executed, or clearResults() is called. An more lightweight version of
                this method that returns results through a listener is also available.
            */
            virtual RaySceneQueryResult& execute(void);
    
            /** Executes the query and returns each match through a listener interface. 
            @remarks
                Note that this method does not store the results of the query internally 
                so does not update the 'last result' value. This means that this version of
                execute is more lightweight and therefore more efficient than the version 
                which returns the results as a collection.
            */
            virtual void execute(RaySceneQueryListener* listener);
    };

    RaySceneQueryResult返回一个RaySceneQueryResultEntry结构体的iterator。这个结构体包含三个变量。distance变量告诉你这个物体沿着射线有多远。另外两个变量的其中一个将是null。movable变量包含一个MovableObject对象,如果与射线相交的话。如果射线接触到一个地形片段,worldFragment将保存这个WorldFragment对象(比如地形)。

    MovableObject基本上可以是任何你能绑在SceneNode上的对象(如实体、光源等)。大多数RaySceneQueries的应用包括选取和操纵MovableObject对象,以及它们所绑定到的SceneNodes。调用getName方法获取MovableObject的名称。调用getParentSceneNode(或getParentNode)获取它们所绑定到的SceneNode。如果RaySceneQueryResultEntry的结果不是一个MovableObject,movable变量则为null。

    WorldFragment是完全另一种怪物。当RaySceneQueryResult中的worldFragment成员被设置时,就意味着返回结果是SceneManager创建的世界几何(world geometry)的一部分。返回的world fragment的类型是基于SceneManager的。它是这样实现的,WorldFragment结构体包含一个fragmentType变量,以指明world fragment的类型。基于这个fragmentType变量,设置其它成员变量(singleIntersection, planes, geometry或者renderOp)。一般来说,RaySceneQueries只返回WFT_SINGLE_INTERSECTION类型的WorldFragments。singleIntersection变量只是一个Vector3,用来报告交点的坐标。

    3. 设置自定义的查询遮罩

    所有的MovableObject允许你为它们设置一个遮罩,然后SceneQueries使你能够根据这个遮罩来过滤你的结果。所有的遮罩都是通过二进制操作来实现的。

    1) 首先创建遮罩值。创建一个新的遮罩值时,它的二进制表示必须只包含一个“1”。能使用位或操作符“|”为多个遮罩进行查询,或使用位取反操作符“~”查询遮罩以外的所有东西。

    enum QueryFlags
    {
        NINJA_MASK = 1<<0,
        ROBOT_MASK = 1<<1
    };

    2) 然后调用Entity::setQueryFlags()设置Entity的遮罩。

    if (mRobotMode)

    {

      ent = mSceneMgr->createEntity(name, "robot.mesh");

      ent->setQueryFlags(ROBOT_MASK);

    }

    else

    {

      ent = mSceneMgr->createEntity(name, "ninja.mesh");

      ent->setQueryFlags(NINJA_MASK);

    }

    3) 最后设置RaySceneQuery的查询标记。

    mRaySceneQuery->setQueryMask(mRobotMode ? ROBOT_MASK : NINJA_MASK);

    4) 查询类型遮罩

    SceneQuery还存在另外一个遮罩,查询类型遮罩(QueryTypeMask),它限制了你只能选择这个标记指定的类型。默认情况是,当你做一个查询时,它只返回实体类型的物体。 在你的代码里,如果想要查询返回公告板或者粒子系统,则你要在执行查询之前这么做:

    mRaySceneQuery->setQueryTypeMask(SceneManager::FX_TYPE_MASK);

    在SceneManager类里面,已经定义了6种类型的QueryTypeMask作为静态成员:

    WORLD_GEOMETRY_TYPE_MASK // 返回世界几何
    ENTITY_TYPE_MASK         // 返回实体
    FX_TYPE_MASK             // 返回公告板/粒子系统
    STATICGEOMETRY_TYPE_MASK // 返回静态几何
    LIGHT_TYPE_MASK          // 返回光源
    USER_TYPE_MASK_LIMIT     // 用户类型遮罩限制

    没有手工设置这个属性时,QueryTypeMask的默认值是ENTITY_TYPE_MASK。

    5) 选取所有物体或者不选取任何物体

    如果你把场景查询的查询遮罩设置成QM,MovableObject的遮罩为OM,如果QM & OM 包含至少一个“1”,则表示能查询到符合条件的MovableObject。因此,若把场景查询的查询遮罩设置成0,则QM & OM 将不包含“1”,场景查询将不返回任何MovableObject。把查询遮罩设置成1,则返回所有查询遮罩不为0的MovableObject。

    使用为0的查询遮罩有时是非常有用的。比如,当只需要返回worldFragment时,TerrainSceneManager可以不必使用QueryMasks。可以这么做:

    mRaySceneQuery->setQueryMask(0);

    在你的场景管理器的RaySceneQueries里,你就只能得到worldFragment。如果你的屏幕里有很多物体,由于你只要地形的交点而不想浪费时间循环遍历所有的东西,这样做是很有用的。

    PS. 创建内置的RaySceneQuery,必须在使用完后手动销毁,不然会有内存泄露!

            /** Creates a RaySceneQuery for this scene manager. 
    @remarks
    This method creates a new instance of a query object for this scene manager,
    looking for objects which fall along a ray. See SceneQuery and RaySceneQuery
    for full details.
    @par
    The instance returned from this method must be destroyed by calling
    SceneManager::destroyQuery when it is no longer required.
    @param ray Details of the ray which describes the region for this query.
    @param mask The query mask to apply to this query; can be used to filter out
    certain objects; see SceneQuery for details.
    */
    virtual RaySceneQuery* createRayQuery(const Ray& ray, unsigned long mask = 0xFFFFFFFF);
  • 相关阅读:
    BZOJ5212 ZJOI2018历史(LCT)
    BZOJ5127 数据校验
    253. Meeting Rooms II
    311. Sparse Matrix Multiplication
    254. Factor Combinations
    250. Count Univalue Subtrees
    259. 3Sum Smaller
    156. Binary Tree Upside Down
    360. Sort Transformed Array
    348. Design Tic-Tac-Toe
  • 原文地址:https://www.cnblogs.com/pulas/p/2357704.html
Copyright © 2011-2022 走看看