Exemple #1
0
bool CollisionTools::raycast(const Ogre::Ray &ray, Ogre::Vector3 &result,Ogre::MovableObject* &target,float &closest_distance, const Ogre::uint32 queryMask)
{
	target = NULL;

    // check we are initialised
    if (mRaySceneQuery != NULL)
    {
        // create a query object
        mRaySceneQuery->setRay(ray);
		mRaySceneQuery->setSortByDistance(true);
		mRaySceneQuery->setQueryMask(queryMask);
        // execute the query, returns a vector of hits
        if (mRaySceneQuery->execute().size() <= 0)
        {
            // raycast did not hit an objects bounding box
            return (false);
        }
    }
    else
    {
        //LOG_ERROR << "Cannot raycast without RaySceneQuery instance" << ENDLOG;
        return (false);
    }

    // at this point we have raycast to a series of different objects bounding boxes.
    // we need to test these different objects to see which is the first polygon hit.
    // there are some minor optimizations (distance based) that mean we wont have to
    // check all of the objects most of the time, but the worst case scenario is that
    // we need to test every triangle of every object.
    //Ogre::Ogre::Real closest_distance = -1.0f;
	closest_distance = -1.0f;
    Ogre::Vector3 closest_result;
    Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();
    for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
    {
        // stop checking if we have found a raycast hit that is closer
        // than all remaining entities
        if ((closest_distance >= 0.0f) &&
            (closest_distance < query_result[qr_idx].distance))
        {
            break;
        }

        // Only check this result if its a hit against an Entity or
        // ManualObject.
        if ((query_result[qr_idx].movable != NULL) &&
            (query_result[qr_idx].movable->isVisible()) &&
            ((query_result[qr_idx].movable->getMovableType().compare("Entity") == 0) ||
             (query_result[qr_idx].movable->getMovableType().compare("ManualObject") == 0)))
        {
            // get the entity to check
            Ogre::MovableObject *pmovable =
               static_cast<Ogre::MovableObject*>(query_result[qr_idx].movable);

            Ogre::MeshPtr mesh_ptr;

            if (query_result[qr_idx].movable->getMovableType().compare("Entity") == 0)
            {
                mesh_ptr = ((Ogre::Entity*)pmovable)->getMesh();
            }
            else
            {
                // XXX: Does "Mesh" get replaced so we can get away with not
                // XXX: deleting it for now?
                mesh_ptr = ((Ogre::ManualObject*)pmovable)->convertToMesh("Mesh", "General");
            }

            // mesh data to retrieve
            size_t vertex_count;
            size_t index_count;
            Ogre::Vector3 *vertices;
            Ogre::uint32 *indices;

            // get the mesh information
            GetMeshInformation(mesh_ptr, vertex_count, vertices, index_count, indices, pmovable->getParentNode()->_getDerivedPosition(), pmovable->getParentNode()->_getDerivedOrientation(), pmovable->getParentNode()->_getDerivedScale());

            // test for hitting individual triangles on the mesh
            bool new_closest_found = false;
            for (size_t i = 0; i < index_count; i += 3)
            {
                // check for a hit against this triangle
                std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
                    vertices[indices[i+1]], vertices[indices[i+2]], true, false);

                // if it was a hit check if its the closest
                if (hit.first)
                {
                    if ((closest_distance < 0.0f) ||
                        (hit.second < closest_distance))
                    {
                        // this is the closest so far, save it off
                        closest_distance = hit.second;
                        new_closest_found = true;
                    }
                }
            }

            // free the verticies and indicies memory
            delete[] vertices;
            delete[] indices;

            // if we found a new closest raycast for this object, update the
            // closest_result before moving on to the next object.
            if (new_closest_found)
            {
                target = pmovable;
                closest_result = ray.getPoint(closest_distance);
            }
        }
    }

    // return the result
    if (closest_distance >= 0.0f)
    {
        // raycast success
        result = closest_result;
        return (true);
    }
    else
    {
        // raycast failed
        return (false);
    }
}
Exemple #2
0
void
System::makeObjectTransparent( const Ogre::Vector3 &start, const Ogre::Vector3 &end, float nNewTrans, float nDelay, IObjectFilter *pFilter )
{
    Ogre::Vector3 vDirction = (start-end);
    Ogre::Real fDistance = vDirction.length();
    Ogre::Ray ray = Ogre::Ray(end,vDirction);
    Ogre::RaySceneQuery* raySceneQuery = getSceneManager()->createRayQuery(Ogre::Ray());
    std::set<Fairy::Object*> setCurrentTransparentObjects;

    raySceneQuery->setRay(ray);
    const Ogre::RaySceneQueryResult& queryResult = raySceneQuery->execute();
    for (Ogre::RaySceneQueryResult::const_iterator it = queryResult.begin(); it != queryResult.end(); ++it)
    {
        Ogre::MovableObject* pMovable = it->movable;
        Ogre::Vector3 vObjectPos = pMovable->getParentNode()->getPosition();
        Ogre::Vector3 vObjectDir = (vObjectPos-end);
        Fairy::ObjectPtr pObject = Fairy::getObjectFromMovable(pMovable);

        if(pObject)
        {
            // 当满足以下条件时设置透明: 1.是StaticEntity类型; 2.相交; 3.允许透明
            if(pObject->getType() == "StaticEntity" && vObjectDir.dotProduct(vDirction) > 0 && static_cast<Fairy::StaticEntityObject*>(pObject.get())->getEnableTransparency())
            {
                Fairy::StaticEntityObject* pModel = static_cast<Fairy::StaticEntityObject*>(pObject.get());
                pModel->setTransparency(0.5f);
                // 删除原有的Object,放到临时的Set中
                m_setTransparencyObjects.erase(pObject.get());
                setCurrentTransparentObjects.insert(pObject.get());
            }
        }
    }

    std::set<Fairy::Object*>::iterator iter = m_setTransparencyObjects.begin();
    std::set<Fairy::Object*>::iterator tempIter;

    while (iter != m_setTransparencyObjects.end())
    {
        tempIter = iter;
        ++iter;
        // 恢复没有遮挡的Object的透明度为0
        Fairy::StaticEntityObject* pModel = static_cast<Fairy::StaticEntityObject*>(*tempIter);
        pModel->setTransparency(0);
        // 删除透明度为0的Object
        if (pModel->getTransparency()==0)
        {
            m_setTransparencyObjects.erase(tempIter);
        }
    }

    // 将遮挡的Object放到m_setTransparencyObjects
    for (std::set<Fairy::Object*>::iterator it = setCurrentTransparentObjects.begin(); it != setCurrentTransparentObjects.end(); ++it)
    {
        m_setTransparencyObjects.insert(*it);
    }

    if(raySceneQuery)
    {
        getSceneManager()->destroyQuery(raySceneQuery);
        raySceneQuery = NULL;
    }
}
	bool CollisionTools::raycast(const Ogre::Ray &ray, Ogre::Vector3 &result,Ogre::MovableObject* &target,float &closest_distance, const Ogre::uint32 queryMask)
	{
		target = NULL;

		// check we are initialised
		if (mRaySceneQuery != NULL)
		{
			// create a query object
			mRaySceneQuery->setRay(ray);
			mRaySceneQuery->setSortByDistance(true);
			mRaySceneQuery->setQueryMask(queryMask);
			// execute the query, returns a vector of hits
			if (mRaySceneQuery->execute().size() <= 0)
			{
				// raycast did not hit an objects bounding box
				return (false);
			}
		}
		else
		{
			//LOG_ERROR << "Cannot raycast without RaySceneQuery instance" << ENDLOG;
			return (false);
		}

		// at this point we have raycast to a series of different objects bounding boxes.
		// we need to test these different objects to see which is the first polygon hit.
		// there are some minor optimizations (distance based) that mean we wont have to
		// check all of the objects most of the time, but the worst case scenario is that
		// we need to test every triangle of every object.
		//Ogre::Ogre::Real closest_distance = -1.0f;
		closest_distance = -1.0f;
		Ogre::Vector3 closest_result;
		Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults();

#if 0
		for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
		{
			const Ogre::RaySceneQueryResultEntry& result = query_result[qr_idx];
			Ogre::Real distance = result.distance;
			Ogre::MovableObject* movable = static_cast<Ogre::MovableObject*>(result.movable);
			Ogre::SceneQuery::WorldFragment* worldFragment = result.worldFragment;

			if (movable)
			{
				const Ogre::String& type = movable->getMovableType();
				const Ogre::String& name = movable->getName();
				const Ogre::String& parentName = movable->getParentNode()->getName();
				Ogre::uint32 flag = movable->getQueryFlags();  

				if (type.compare("Entity") == 0)
				{
					Ogre::Entity* ent =  (Ogre::Entity*)movable;
				}

				std::ostrstream oss;
				oss<<"name:"<<name<<" distance:"<< distance <<" type:"<<type<<" flag:"<<flag<<" parent:"<<parentName<<std::endl;
				OutputDebugString(oss.str() );
			}
		}

#endif

		for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
		{
			// stop checking if we have found a raycast hit that is closer
			// than all remaining entities
			if ((closest_distance >= 0.0f) &&
				(closest_distance < query_result[qr_idx].distance))
			{
				break;
			}

			// only check this result if its a hit against an entity
			if ((query_result[qr_idx].movable != NULL)  &&
				(query_result[qr_idx].movable->getMovableType().compare("Entity") == 0))
			{
				// get the entity to check
				Ogre::MovableObject *pentity = static_cast<Ogre::MovableObject*>(query_result[qr_idx].movable);

				// mesh data to retrieve
				size_t vertex_count;
				size_t index_count;
				Ogre::Vector3 *vertices = NULL;
				Ogre::uint32 *indices = NULL;

				// get the mesh information
				GetMeshInformation(((Ogre::Entity*)pentity)->getMesh(), vertex_count, vertices, index_count, indices,
					pentity->getParentNode()->_getDerivedPosition(),
					pentity->getParentNode()->_getDerivedOrientation(),
					pentity->getParentNode()->_getDerivedScale());

				// test for hitting individual triangles on the mesh
				bool new_closest_found = false;
				for (size_t i = 0; i < index_count; i += 3)
				{
					// check for a hit against this triangle
					std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]],
						vertices[indices[i+1]], vertices[indices[i+2]], true, false);

					// if it was a hit check if its the closest
					if (hit.first)
					{
						if ((closest_distance < 0.0f) ||
							(hit.second < closest_distance))
						{
							// this is the closest so far, save it off
							closest_distance = hit.second;
							new_closest_found = true;
						}
					}
				}

				// free the verticies and indicies memory
				delete  vertices;
				delete  indices;

				// if we found a new closest raycast for this object, update the
				// closest_result before moving on to the next object.
				if (new_closest_found)
				{
					target = pentity;
					closest_result = ray.getPoint(closest_distance);
				}
			}
		}

		// return the result
		if (closest_distance >= 0.0f)
		{
			// raycast success
			result = closest_result;
			return (true);
		}
		else
		{
			// raycast failed
			return (false);
		}
	}
void EntityWorldPickListener::processPickResult(bool& continuePicking, Ogre::RaySceneQueryResultEntry& entry, Ogre::Ray& cameraRay, const MousePickerArgs& mousePickerArgs)
{
	if (!mContinuePickingThisContext) {
		return;
	}

	if (entry.worldFragment) {
		//this is terrain
		//a position of -1, -1, -1 is not valid terrain
		Ogre::SceneQuery::WorldFragment* wf = entry.worldFragment;
		static const Ogre::Vector3 invalidPos(-1, -1, -1);
		if (wf->singleIntersection != invalidPos) {

			if (mFurthestPickingDistance == 0 || mResult.empty()) {
				EntityPickResult result;
				result.entity = findTerrainEntity();
				result.position = wf->singleIntersection;
				result.distance = entry.distance;
				result.isTransparent = false;
				mResult.push_back(result);
				mContinuePickingThisContext = false;
			} else {
				if (entry.distance < mResult[mResult.size() - 1].distance) {
					//If the last result is transparent, add another result, but if it's not replace it.
					if (mResult.size() && !mResult[mResult.size() - 1].isTransparent) {
						mResult.pop_back();
					}
					EntityPickResult result;
					result.entity = findTerrainEntity();
					result.position = wf->singleIntersection;
					result.distance = entry.distance;
					result.isTransparent = false;
					mResult.push_back(result);
					mContinuePickingThisContext = false;
				}
			}
		}
		/*		std::stringstream ss;
		 ss << wf->singleIntersection;
		 S_LOG_VERBOSE("Picked in terrain: " << ss.str() << " distance: " << mResult.distance);*/

	} else if (entry.movable) {
		Ogre::MovableObject* pickedMovable = entry.movable;
		if (pickedMovable->isVisible() && pickedMovable->getUserObjectBindings().getUserAny().getType() == typeid(EmberEntityUserObject::SharedPtr)) {
			EmberEntityUserObject* anUserObject = Ogre::any_cast<EmberEntityUserObject::SharedPtr>(pickedMovable->getUserObjectBindings().getUserAny()).get();
			//refit the opcode mesh to adjust for changes in the mesh (for example animations)
			anUserObject->refit();

			ICollisionDetector* collisionDetector = anUserObject->getCollisionDetector();
			if (collisionDetector) {
				CollisionResult collisionResult;
				collisionResult.collided = false;
				collisionResult.isTransparent = false;
				collisionDetector->testCollision(cameraRay, collisionResult);
				if (collisionResult.collided) {
					if (mFurthestPickingDistance == 0) {
						//If the current collision is transparent, also check for entities which are further away.
						if (!collisionResult.isTransparent) {
							//test all objects that fall into this distance
							mFurthestPickingDistance = (pickedMovable->getParentNode()->_getDerivedPosition() - cameraRay.getOrigin()).length() + pickedMovable->getBoundingRadius();
						}
					} else {
						if (collisionResult.distance > mFurthestPickingDistance) {
							mContinuePickingThisContext = false;
							return;
						} else {
							if (!mResult.empty() && mResult[mResult.size() - 1].distance > collisionResult.distance) {
								//If the last result is transparent, add another result, but if it's not replace it.
								if (!mResult[mResult.size() - 1].isTransparent) {
									mResult.pop_back();
								}
							} else {
								return;
							}
						}
					}
					EmberEntity& pickedEntity = anUserObject->getEmberEntity();

					std::list<EmberEntity*> entities;
					entities.push_front(&pickedEntity);
					EmberEntity* entity = pickedEntity.getEmberLocation();
					while (entity) {
						if (entity->getCompositionMode() == EmberEntity::CM_COMPOSITION) {
							entities.push_front(entity);
						} else if (entity->getCompositionMode() == EmberEntity::CM_COMPOSITION_EXCLUSIVE) {
							entities.clear();
							entities.push_front(entity);
						}
						entity = entity->getEmberLocation();
					}

					for (std::list<EmberEntity*>::const_iterator I = entities.begin(); I != entities.end(); ++I) {
						EntityPickResult result;
						result.entity = *I;
						result.position = collisionResult.position;
						result.distance = collisionResult.distance;
						result.isTransparent = collisionResult.isTransparent;
						mResult.push_back(result);
					}
				}
			}
		}
	}
}