/***************************************************************************//*! * @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; }