void Entity::pick(const Rayf& ray, PickResult& pickResults) { float dist = bounds().intersectWithRay(ray, NULL); if (Math<float>::isnan(dist)) return; Vec3f hitPoint = ray.pointAtDistance(dist); EntityHit* hit = new EntityHit(*this, hitPoint, dist); pickResults.add(hit); }
void Brush::pick(const Rayf& ray, PickResult& pickResults) { float dist = bounds().intersectWithRay(ray, NULL); if (Math<float>::isnan(dist)) return; dist = Math<float>::nan(); Side* side = NULL; for (unsigned int i = 0; i < m_geometry->sides.size() && Math<float>::isnan(dist); i++) { side = m_geometry->sides[i]; dist = side->intersectWithRay(ray); } if (!Math<float>::isnan(dist)) { assert(side != NULL); Vec3f hitPoint = ray.pointAtDistance(dist); FaceHit* hit = new FaceHit(*(side->face), hitPoint, dist); pickResults.add(hit); } }
void PhysicsWorld::Pick(const Math::Vector3 &pos, PickResult &result) { Broadphase::PickResult colliders; mBroadphase->Pick(pos, colliders); // clear pick flags for (auto collider : colliders) { auto &body = *collider->mParent; body.mFlags.Clear(PhysicsFlags::PICK); } // compute result for (auto collider : colliders) { auto &body = *collider->mParent; if (!body.mFlags.Test(PhysicsFlags::PICK) && collider->CollidesCollider(pos)) { body.mFlags.Set(PhysicsFlags::PICK); result.push_back(&body); } } // end of collider loop }
/** Determine the closest object intersected by a ray given by the pick origin and direction. * This method returns true if any object was intersected. If the value of result is not * null, it will be updated with information about which object was hit by the pick ray. * * @param t The time given as the number of seconds since 1 Jan 2000 12:00:00 UTC. * @param pickOrigin origin of the pick ray * @param pickDirection direction of the pick ray (does not need to be normalized) * @param pixelAngle angle in radians subtended by a pixel * @param result pointer to a PickResult object that will be filled in if the pick ray * hits something. */ bool Universe::pickObject(double t, const Vector3d& pickOrigin, const Vector3d& pickDirection, double pixelAngle, PickResult* result) const { double closest = numeric_limits<double>::infinity(); PickResult closestResult; for (EntityTable::const_iterator iter = m_entities.begin(); iter != m_entities.end(); ++iter) { Entity* entity = iter->ptr(); if (entity->geometry() || entity->hasVisualizers()) { if (entity->isVisible() && entity->chronology()->includesTime(t)) { Vector3d position = entity->position(t); if (entity->geometry()) { Geometry* geometry = entity->geometry(); double intersectionDistance; if (TestRaySphereIntersection(pickOrigin, pickDirection, position, geometry->boundingSphereRadius(), &intersectionDistance)) { if (intersectionDistance < closest) { // Transform the pick ray into the local coordinate system of body Matrix3d invRotation = entity->orientation(t).conjugate().toRotationMatrix(); Vector3d relativePickOrigin = invRotation * (pickOrigin - position); Vector3d relativePickDirection = invRotation * pickDirection; double distance = intersectionDistance; if (geometry->rayPick(relativePickOrigin, relativePickDirection, t, &distance)) { if (distance < closest) { closest = distance; closestResult.setHit(entity, distance, pickOrigin + pickDirection * distance); } } } } } // Visualizers may act as 'pick proxies' if (entity->hasVisualizers()) { Vector3d relativePickOrigin = pickOrigin - position; // Calculate the distance to the plane containing the center of the visualizer // and perpendicular to the pick direction. double distanceToPlane = -pickDirection.dot(relativePickOrigin); if (distanceToPlane > 0.0 && distanceToPlane < closest) { for (Entity::VisualizerTable::const_iterator iter = entity->visualizers()->begin(); iter != entity->visualizers()->end(); ++iter) { const Visualizer* visualizer = iter->second.ptr(); if (visualizer->isVisible() && visualizer->rayPick(relativePickOrigin, pickDirection, pixelAngle)) { closest = distanceToPlane; closestResult.setHit(entity, distanceToPlane, pickOrigin + pickDirection * distanceToPlane); break; } } } } } } } if (closest < numeric_limits<double>::infinity()) { if (result) { *result = closestResult; } return true; } else { return false; } }