Example #1
0
/***************************************************************************//*!
 * @brief Raycast from a point in to the scene.
 * @param[in] point		Point to analyse
 * @param[in] normal		Direction
 * @param[out] result	Result ( ONLY if return TRUE )
 * @return TRUE if somethings found => {result} NOT EMPTY
 */
bool OgreMeshRay::raycastFromPoint(const Ogre::Vector3& point,
		const Ogre::Vector3& normal, Ogre::Vector3& result,
		std::string entityName) {
	// create the ray to test
	Ogre::Ray ray(point, normal);

	if (!m_raySceneQuery)
		return false;

	// create a query object
	m_raySceneQuery->setRay(ray);

	// execute the query, returns a vector of hits
	if (m_raySceneQuery->execute().size() <= 0) {
		// raycast did not hit an objects bounding box
		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::Real closest_distance = -1.0f;
	Ogre::Vector3 closest_result;
	Ogre::RaySceneQueryResult& query_result = m_raySceneQuery->getLastResults();
	for (size_t qr_idx = 0, size = query_result.size(); qr_idx < 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) {
			if (entityName != ""
					&& query_result[qr_idx].movable->getName() != entityName) {
				std::cout << query_result[qr_idx].movable->getName()
						<< "is not " << entityName << std::endl;
				continue;
			}
			std::cout << query_result[qr_idx].movable->getName() << "is truly "
					<< entityName << std::endl;
			const std::string& movableType =
					query_result[qr_idx].movable->getMovableType();
			// mesh data to retrieve
			size_t vertex_count;
			size_t index_count;
			Ogre::Vector3* vertices;
			unsigned long* indices;

			if (movableType == "ManualObject") {
				// get the entity to check
				Ogre::ManualObject* pentity =
						static_cast<Ogre::ManualObject*>(query_result[qr_idx].movable);
				// get the mesh information
				GetMeshInformation(pentity, vertex_count, vertices, index_count,
						indices,
						pentity->getParentNode()->_getDerivedPosition(),
						pentity->getParentNode()->_getDerivedOrientation(),
						pentity->getParentNode()->_getDerivedScale());
			} else if (movableType == "Entity") {
				// get the entity to check
				Ogre::Entity *pentity =
						static_cast<Ogre::Entity*>(query_result[qr_idx].movable);
				// get the mesh information
				GetMeshInformation(pentity, vertex_count, vertices, index_count,
						indices,
						pentity->getParentNode()->_getDerivedPosition(),
						pentity->getParentNode()->_getDerivedOrientation(),
						pentity->getParentNode()->_getDerivedScale());
			} else {
				continue;
			}

			// test for hitting individual triangles on the mesh
			bool new_closest_found = false;
			for (int i = 0; i < static_cast<int>(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
						&& (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)
				closest_result = ray.getPoint(closest_distance);
		}
	}

	// return the result
	if (closest_distance >= 0.0f) {
		// raycast success
		result = closest_result;
		return true;
	}
	// raycast failed
	return false;
}